github.com/ystia/yorc/v4@v4.3.0/plugin/operation.go (about)

     1  // Copyright 2018 Bull S.A.S. Atos Technologies - Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois, France.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package plugin
    16  
    17  import (
    18  	"context"
    19  	"net/rpc"
    20  	"time"
    21  
    22  	plugin "github.com/hashicorp/go-plugin"
    23  	"github.com/pkg/errors"
    24  
    25  	"github.com/ystia/yorc/v4/config"
    26  	"github.com/ystia/yorc/v4/events"
    27  	"github.com/ystia/yorc/v4/prov"
    28  )
    29  
    30  // OperationExecutor is an extension of prov.OperationExecutor that expose its supported node types
    31  type OperationExecutor interface {
    32  	prov.OperationExecutor
    33  	// Returns a list of regexp matches for node types
    34  	GetSupportedArtifactTypes() ([]string, error)
    35  }
    36  
    37  // OperationPlugin is public for use by reflexion and should be considered as private to this package.
    38  // Please do not use it directly.
    39  type OperationPlugin struct {
    40  	F              func() prov.OperationExecutor
    41  	SupportedTypes []string
    42  }
    43  
    44  // Server is public for use by reflexion and should be considered as private to this package.
    45  // Please do not use it directly.
    46  func (p *OperationPlugin) Server(b *plugin.MuxBroker) (interface{}, error) {
    47  	oes := &OperationExecutorServer{Broker: b, SupportedTypes: p.SupportedTypes}
    48  	if p.F != nil {
    49  		oes.OpExecutor = p.F()
    50  	} else if len(p.SupportedTypes) > 0 {
    51  		return nil, errors.New("If OperationSupportedArtifactTypes is defined then you have to defined an OperationFunc")
    52  	}
    53  
    54  	return oes, nil
    55  }
    56  
    57  // Client is public for use by reflexion and should be considered as private to this package.
    58  // Please do not use it directly.
    59  func (p *OperationPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
    60  	return &OperationExecutorClient{Broker: b, Client: c}, nil
    61  }
    62  
    63  // OperationExecutorClient is public for use by reflexion and should be considered as private to this package.
    64  // Please do not use it directly.
    65  type OperationExecutorClient struct {
    66  	Broker *plugin.MuxBroker
    67  	Client *rpc.Client
    68  }
    69  
    70  // ExecAsyncOperation is public for use by reflexion and should be considered as private to this package.
    71  // Please do not use it directly.
    72  func (c *OperationExecutorClient) ExecAsyncOperation(ctx context.Context, conf config.Configuration, taskID, deploymentID, nodeName string, operation prov.Operation, stepName string) (*prov.Action, time.Duration, error) {
    73  
    74  	lof, ok := events.FromContext(ctx)
    75  	if !ok {
    76  		return nil, 0, errors.New("Missing contextual log optionnal fields")
    77  	}
    78  
    79  	id := c.Broker.NextId()
    80  	closeChan := make(chan struct{}, 0)
    81  	defer close(closeChan)
    82  	go clientMonitorContextCancellation(ctx, closeChan, id, c.Broker)
    83  
    84  	var resp OperationExecutorExecAsyncOperationResponse
    85  	args := &OperationExecutorExecAsyncOperationArgs{
    86  		ChannelID:         id,
    87  		Conf:              conf,
    88  		TaskID:            taskID,
    89  		DeploymentID:      deploymentID,
    90  		NodeName:          nodeName,
    91  		Operation:         operation,
    92  		StepName:          stepName,
    93  		LogOptionalFields: lof,
    94  	}
    95  	err := c.Client.Call("Plugin.ExecAsyncOperation", args, &resp)
    96  	if err != nil {
    97  		return nil, 0, errors.Wrap(err, "Failed to call ExecAsyncOperation for plugin")
    98  	}
    99  	return resp.Action, resp.MonitoringTimeInterval, toError(resp.Error)
   100  }
   101  
   102  // ExecOperation is public for use by reflexion and should be considered as private to this package.
   103  // Please do not use it directly.
   104  func (c *OperationExecutorClient) ExecOperation(ctx context.Context, conf config.Configuration, taskID, deploymentID, nodeName string, operation prov.Operation) error {
   105  	lof, ok := events.FromContext(ctx)
   106  	if !ok {
   107  		return errors.New("Missing contextual log optionnal fields")
   108  	}
   109  	id := c.Broker.NextId()
   110  	closeChan := make(chan struct{}, 0)
   111  	defer close(closeChan)
   112  	go clientMonitorContextCancellation(ctx, closeChan, id, c.Broker)
   113  
   114  	var resp OperationExecutorExecOperationResponse
   115  	args := &OperationExecutorExecOperationArgs{
   116  		ChannelID:         id,
   117  		Conf:              conf,
   118  		TaskID:            taskID,
   119  		DeploymentID:      deploymentID,
   120  		NodeName:          nodeName,
   121  		Operation:         operation,
   122  		LogOptionalFields: lof,
   123  	}
   124  	err := c.Client.Call("Plugin.ExecOperation", args, &resp)
   125  	if err != nil {
   126  		return errors.Wrap(err, "Failed to call ExecOperation for plugin")
   127  	}
   128  	return toError(resp.Error)
   129  }
   130  
   131  // OperationExecutorServer is public for use by reflexion and should be considered as private to this package.
   132  // Please do not use it directly.
   133  type OperationExecutorServer struct {
   134  	Broker         *plugin.MuxBroker
   135  	OpExecutor     prov.OperationExecutor
   136  	SupportedTypes []string
   137  }
   138  
   139  // OperationExecutorExecOperationArgs is public for use by reflexion and should be considered as private to this package.
   140  // Please do not use it directly.
   141  type OperationExecutorExecOperationArgs struct {
   142  	ChannelID         uint32
   143  	Conf              config.Configuration
   144  	TaskID            string
   145  	DeploymentID      string
   146  	NodeName          string
   147  	Operation         prov.Operation
   148  	LogOptionalFields events.LogOptionalFields
   149  }
   150  
   151  // OperationExecutorExecOperationResponse is public for use by reflexion and should be considered as private to this package.
   152  // Please do not use it directly.
   153  type OperationExecutorExecOperationResponse struct {
   154  	Error *RPCError
   155  }
   156  
   157  // OperationExecutorExecAsyncOperationArgs is public for use by reflexion and should be considered as private to this package.
   158  // Please do not use it directly.
   159  type OperationExecutorExecAsyncOperationArgs struct {
   160  	ChannelID         uint32
   161  	Conf              config.Configuration
   162  	TaskID            string
   163  	DeploymentID      string
   164  	NodeName          string
   165  	Operation         prov.Operation
   166  	StepName          string
   167  	LogOptionalFields events.LogOptionalFields
   168  }
   169  
   170  // OperationExecutorExecAsyncOperationResponse is public for use by reflexion and should be considered as private to this package.
   171  // Please do not use it directly.
   172  type OperationExecutorExecAsyncOperationResponse struct {
   173  	Action                 *prov.Action
   174  	MonitoringTimeInterval time.Duration
   175  	Error                  *RPCError
   176  }
   177  
   178  // ExecOperation is public for use by reflexion and should be considered as private to this package.
   179  // Please do not use it directly.
   180  func (s *OperationExecutorServer) ExecOperation(args *OperationExecutorExecOperationArgs, reply *OperationExecutorExecOperationResponse) error {
   181  
   182  	ctx, cancelFunc := context.WithCancel(events.NewContext(context.Background(), args.LogOptionalFields))
   183  	defer cancelFunc()
   184  
   185  	go s.Broker.AcceptAndServe(args.ChannelID, &RPCContextCanceller{CancelFunc: cancelFunc})
   186  	err := s.OpExecutor.ExecOperation(ctx, args.Conf, args.TaskID, args.DeploymentID, args.NodeName, args.Operation)
   187  	var resp OperationExecutorExecOperationResponse
   188  	if err != nil {
   189  		resp.Error = NewRPCError(err)
   190  	}
   191  	*reply = resp
   192  	return nil
   193  }
   194  
   195  // ExecAsyncOperation is public for use by reflexion and should be considered as private to this package.
   196  // Please do not use it directly.
   197  func (s *OperationExecutorServer) ExecAsyncOperation(args *OperationExecutorExecAsyncOperationArgs, reply *OperationExecutorExecAsyncOperationResponse) error {
   198  
   199  	ctx, cancelFunc := context.WithCancel(events.NewContext(context.Background(), args.LogOptionalFields))
   200  	defer cancelFunc()
   201  
   202  	go s.Broker.AcceptAndServe(args.ChannelID, &RPCContextCanceller{CancelFunc: cancelFunc})
   203  	var err error
   204  	var resp OperationExecutorExecAsyncOperationResponse
   205  	resp.Action, resp.MonitoringTimeInterval, err = s.OpExecutor.ExecAsyncOperation(ctx, args.Conf, args.TaskID, args.DeploymentID, args.NodeName, args.Operation, args.StepName)
   206  	if err != nil {
   207  		resp.Error = NewRPCError(err)
   208  	}
   209  	*reply = resp
   210  	return nil
   211  }
   212  
   213  // GetSupportedArtifactTypes is public for use by reflexion and should be considered as private to this package.
   214  // Please do not use it directly.
   215  func (s *OperationExecutorServer) GetSupportedArtifactTypes(_ interface{}, reply *OperationExecutorGetTypesResponse) error {
   216  	*reply = OperationExecutorGetTypesResponse{SupportedTypes: s.SupportedTypes}
   217  	return nil
   218  }
   219  
   220  // OperationExecutorGetTypesResponse is public for use by reflexion and should be considered as private to this package.
   221  // Please do not use it directly.
   222  type OperationExecutorGetTypesResponse struct {
   223  	SupportedTypes []string
   224  	Error          *RPCError
   225  }
   226  
   227  // GetSupportedArtifactTypes is public for use by reflexion and should be considered as private to this package.
   228  // Please do not use it directly.
   229  func (c *OperationExecutorClient) GetSupportedArtifactTypes() ([]string, error) {
   230  	var resp OperationExecutorGetTypesResponse
   231  	err := c.Client.Call("Plugin.GetSupportedArtifactTypes", new(interface{}), &resp)
   232  	if err != nil {
   233  		return nil, errors.Wrap(err, "Failed to get supported types for plugin")
   234  	}
   235  	return resp.SupportedTypes, toError(resp.Error)
   236  }