github.com/ystia/yorc/v4@v4.3.0/plugin/serve.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  	"encoding/gob"
    19  	"text/template"
    20  
    21  	"github.com/hashicorp/go-plugin"
    22  
    23  	"github.com/ystia/yorc/v4/config"
    24  	"github.com/ystia/yorc/v4/events"
    25  	"github.com/ystia/yorc/v4/prov"
    26  	"github.com/ystia/yorc/v4/vault"
    27  )
    28  
    29  const (
    30  	// DelegatePluginName is the name of Delegates Plugins it could be used as a lookup key in Client.Dispense
    31  	DelegatePluginName = "delegate"
    32  	// DefinitionsPluginName is the name of Delegates Plugins it could be used as a lookup key in Client.Dispense
    33  	DefinitionsPluginName = "definitions"
    34  	// ConfigManagerPluginName is the name of ConfigManager plugin it could be used as a lookup key in Client.Dispense
    35  	ConfigManagerPluginName = "cfgManager"
    36  	// OperationPluginName is the name of Operation Plugins it could be used as a lookup key in Client.Dispense
    37  	OperationPluginName = "operation"
    38  	// ActionPluginName is the name of Action Plugins it could be used as a lookup key in Client.Dispense
    39  	ActionPluginName = "action"
    40  	// InfraUsageCollectorPluginName is the name of InfraUsageCollector Plugins it could be used as a lookup key in Client.Dispense
    41  	InfraUsageCollectorPluginName = "infraUsageCollector"
    42  )
    43  
    44  // HandshakeConfig are used to just do a basic handshake between
    45  // a plugin and host. If the handshake fails, a user friendly error is shown.
    46  // This prevents users from executing bad plugins or executing a plugin
    47  // directory. It is a UX feature, not a security feature.
    48  var HandshakeConfig = plugin.HandshakeConfig{
    49  	ProtocolVersion:  3,
    50  	MagicCookieKey:   "YORC_PLUG_API",
    51  	MagicCookieValue: "a3292e718f7c96578aae47e92b7475394e72e6da3de3455554462ba15dde56d1b3187ad0e5f809f50767e0d10ca6944fdf4c6c412380d3aa083b9e8951f7101e",
    52  }
    53  
    54  // DelegateFunc is a function that is called when creating a plugin server
    55  type DelegateFunc func() prov.DelegateExecutor
    56  
    57  // OperationFunc is a function that is called when creating a plugin server
    58  type OperationFunc func() prov.OperationExecutor
    59  
    60  // ActionFunc is a function that is called when creating a plugin server
    61  type ActionFunc func() prov.ActionOperator
    62  
    63  // InfraUsageCollectorFunc is a function that is called when creating a plugin server
    64  type InfraUsageCollectorFunc func() prov.InfraUsageCollector
    65  
    66  // ServeOpts are the configurations to serve a plugin.
    67  type ServeOpts struct {
    68  	DelegateFunc                       DelegateFunc
    69  	DelegateSupportedTypes             []string
    70  	Definitions                        map[string][]byte
    71  	OperationFunc                      OperationFunc
    72  	OperationSupportedArtifactTypes    []string
    73  	ActionFunc                         ActionFunc
    74  	ActionTypes                        []string
    75  	InfraUsageCollectorFunc            InfraUsageCollectorFunc
    76  	InfraUsageCollectorSupportedInfras []string
    77  }
    78  
    79  // Serve serves a plugin. This function never returns and should be the final
    80  // function called in the main function of the plugin.
    81  func Serve(opts *ServeOpts) {
    82  	SetupPluginCommunication()
    83  
    84  	// Configuring Yorc logs to use Hashicorp hclog in the plugin so that
    85  	// these logs can be parsed and filtered in the Yorc server  according to their
    86  	// log level
    87  	initPluginYorcLog()
    88  
    89  	// Cannot configure here standard log to use Hashicorp hclog, as next call
    90  	// plugin.Serve() is setting standard log output to os.Stderr.
    91  	// This will be done in config.go by the defaultConfigManager
    92  
    93  	plugin.Serve(&plugin.ServeConfig{
    94  		HandshakeConfig: HandshakeConfig,
    95  		Plugins:         getPlugins(opts),
    96  		Logger:          hclogger,
    97  	})
    98  }
    99  
   100  func getPlugins(opts *ServeOpts) map[string]plugin.Plugin {
   101  	if opts == nil {
   102  		opts = new(ServeOpts)
   103  	}
   104  	return map[string]plugin.Plugin{
   105  		DelegatePluginName:            &DelegatePlugin{F: opts.DelegateFunc, SupportedTypes: opts.DelegateSupportedTypes},
   106  		OperationPluginName:           &OperationPlugin{F: opts.OperationFunc, SupportedTypes: opts.OperationSupportedArtifactTypes},
   107  		ActionPluginName:              &ActionPlugin{F: opts.ActionFunc, ActionTypes: opts.ActionTypes},
   108  		DefinitionsPluginName:         &DefinitionsPlugin{Definitions: opts.Definitions},
   109  		ConfigManagerPluginName:       &ConfigManagerPlugin{&defaultConfigManager{}},
   110  		InfraUsageCollectorPluginName: &InfraUsageCollectorPlugin{F: opts.InfraUsageCollectorFunc, SupportedInfras: opts.InfraUsageCollectorSupportedInfras},
   111  	}
   112  }
   113  
   114  // SetupPluginCommunication makes mandatory actions to allow RPC calls btw server and plugins
   115  // This must be called both by serve and each plugin
   116  func SetupPluginCommunication() {
   117  	// As we have type []interface{} in the config.Configuration structure, we need to register it before sending config from yorc server to plugins
   118  	gob.Register(make(map[string]interface{}, 0))
   119  	gob.Register(make(events.LogOptionalFields, 0))
   120  	gob.Register(make([]interface{}, 0))
   121  	gob.Register(make([]string, 0))
   122  	gob.RegisterName("DynamicMap", &config.DynamicMap{})
   123  	gob.Register(template.FuncMap{})
   124  	gob.Register(new(vault.Client))
   125  	gob.RegisterName("RPCError", RPCError{})
   126  }