get.porter.sh/porter@v1.3.0/pkg/porter/internal_plugins.go (about) 1 package porter 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "io" 9 10 "get.porter.sh/porter/pkg/config" 11 "get.porter.sh/porter/pkg/plugins" 12 "get.porter.sh/porter/pkg/portercontext" 13 secretsplugins "get.porter.sh/porter/pkg/secrets/plugins" 14 "get.porter.sh/porter/pkg/secrets/plugins/filesystem" 15 "get.porter.sh/porter/pkg/secrets/plugins/host" 16 signingplugins "get.porter.sh/porter/pkg/signing/plugins" 17 "get.porter.sh/porter/pkg/signing/plugins/cosign" 18 "get.porter.sh/porter/pkg/signing/plugins/notation" 19 storageplugins "get.porter.sh/porter/pkg/storage/plugins" 20 "get.porter.sh/porter/pkg/storage/plugins/mongodb" 21 "get.porter.sh/porter/pkg/storage/plugins/mongodb_docker" 22 "get.porter.sh/porter/pkg/tracing" 23 "github.com/hashicorp/go-plugin" 24 ) 25 26 type RunInternalPluginOpts struct { 27 Key string 28 } 29 30 func (o *RunInternalPluginOpts) ApplyArgs(args []string) error { 31 if len(args) == 0 { 32 return errors.New("The positional argument KEY was not specified") 33 } 34 if len(args) > 1 { 35 return errors.New("Multiple positional arguments were specified but only one KEY is expected") 36 } 37 38 o.Key = args[0] 39 return nil 40 } 41 42 func (o *RunInternalPluginOpts) Validate() error { 43 if o.Key == "" { 44 return fmt.Errorf("no plugin key was specified") 45 } 46 47 if _, ok := internalPlugins[o.Key]; !ok { 48 return fmt.Errorf("invalid plugin key specified: %s", o.Key) 49 } 50 51 return nil 52 } 53 54 func (o *RunInternalPluginOpts) parsePluginConfig(c *portercontext.Context) (interface{}, error) { 55 pluginCfg := map[string]interface{}{} 56 if err := json.NewDecoder(c.In).Decode(&pluginCfg); err != nil { 57 if err == io.EOF { 58 // No plugin config was specified 59 return pluginCfg, nil 60 } 61 return nil, fmt.Errorf("error parsing plugin configuration from stdin as json: %w", err) 62 } 63 return pluginCfg, nil 64 } 65 66 func (p *Porter) RunInternalPlugins(ctx context.Context, opts RunInternalPluginOpts) (err error) { 67 err = opts.Validate() 68 if err != nil { 69 return err 70 } 71 72 // Read the plugin configuration from the porter config file from STDIN 73 pluginCfg, err := opts.parsePluginConfig(p.Context) 74 if err != nil { 75 return err 76 } 77 78 // Create an instance of the plugin 79 selectedPlugin := internalPlugins[opts.Key] 80 impl, err := selectedPlugin.Create(p.Config, pluginCfg) 81 if err != nil { 82 return fmt.Errorf("could not create an instance of the requested internal plugin %s: %w", opts.Key, err) 83 } 84 85 defer func() { 86 if panicErr := recover(); err != nil { 87 err = fmt.Errorf("%v", panicErr) 88 } 89 90 if closer, ok := impl.(closablePlugin); ok { 91 if err = closer.Close(ctx); err != nil { 92 log := tracing.LoggerFromContext(ctx) 93 _ = log.Error(fmt.Errorf("error stopping the %s plugin: %w", opts.Key, err)) 94 } 95 } 96 }() 97 98 plugins.Serve(p.Context, selectedPlugin.Interface, impl, selectedPlugin.ProtocolVersion) 99 return err // Return the error that may have been set during recover above 100 } 101 102 // A list of available plugins that we can serve directly from the porter binary 103 var internalPlugins map[string]InternalPlugin = getInternalPlugins() 104 105 // InternalPlugin represents the information needed to run one of the plugins 106 // defined in porter's repository. 107 type InternalPlugin struct { 108 Interface string 109 ProtocolVersion int 110 Create func(c *config.Config, pluginCfg interface{}) (plugin.Plugin, error) 111 } 112 113 // A long running plugin needs to setup a connection or other resources first, 114 // and will hold those resources until porter is done with the plugin. 115 type closablePlugin interface { 116 Close(ctx context.Context) error 117 } 118 119 func getInternalPlugins() map[string]InternalPlugin { 120 return map[string]InternalPlugin{ 121 host.PluginKey: { 122 Interface: secretsplugins.PluginInterface, 123 ProtocolVersion: secretsplugins.PluginProtocolVersion, 124 Create: func(c *config.Config, pluginCfg interface{}) (plugin.Plugin, error) { 125 return host.NewPlugin(c.Context), nil 126 }, 127 }, 128 filesystem.PluginKey: { 129 Interface: secretsplugins.PluginInterface, 130 ProtocolVersion: secretsplugins.PluginProtocolVersion, 131 Create: func(c *config.Config, pluginCfg interface{}) (plugin.Plugin, error) { 132 return filesystem.NewPlugin(c, pluginCfg), nil 133 }, 134 }, 135 mongodb.PluginKey: { 136 Interface: storageplugins.PluginInterface, 137 ProtocolVersion: storageplugins.PluginProtocolVersion, 138 Create: func(c *config.Config, pluginCfg interface{}) (plugin.Plugin, error) { 139 return mongodb.NewPlugin(c.Context, pluginCfg) 140 }, 141 }, 142 mongodb_docker.PluginKey: { 143 Interface: storageplugins.PluginInterface, 144 ProtocolVersion: storageplugins.PluginProtocolVersion, 145 Create: func(c *config.Config, pluginCfg interface{}) (plugin.Plugin, error) { 146 return mongodb_docker.NewPlugin(c.Context, pluginCfg) 147 }, 148 }, 149 notation.PluginKey: { 150 Interface: signingplugins.PluginInterface, 151 ProtocolVersion: signingplugins.PluginProtocolVersion, 152 Create: func(c *config.Config, pluginCfg interface{}) (plugin.Plugin, error) { 153 return notation.NewPlugin(c.Context, pluginCfg) 154 }, 155 }, 156 cosign.PluginKey: { 157 Interface: signingplugins.PluginInterface, 158 ProtocolVersion: signingplugins.PluginProtocolVersion, 159 Create: func(c *config.Config, pluginCfg interface{}) (plugin.Plugin, error) { 160 return cosign.NewPlugin(c.Context, pluginCfg) 161 }, 162 }, 163 } 164 }