README
¶
Veraison Plugin Framework
Note: This section is primarily of interest to core Veraison developers. see here if you wish to learn how to implement plugins to support new attestation schemes.
Veraison services functionality can be extended via plugins. Extension points
are defined via interfaces that embed plugin.IPluggable
interface (which defines
functionality common to all plugins. plugin.IPluggable
implementations are
managed via a plugin.IManager[I IPluggable]
, which allows obtaining plugin
implementations either by name or media type.
Veraison plugin handling is implemented on top of HashiCorp go-plugin framework.
Defining new plugin types
All Veraison plugins must implement the IPluggable
interface:
type IPluggable interface {
GetName() string
GetAttestationScheme() string
GetSupportedMediaTypes() []string
}
A plugin implementation must have a unique name, and it may also advertise the media types it can handle.
Warning: Currently, Veraison doesn't support multiple plugins advertising the same media type. If a manager (see below) discovers a plugin that advertises a media type that has already been registered, it will return an error.
In order to define new extension points (plugin types) for Veraison, one needs
to define a new interface embedding plugin.IPluggable
, and
provide an RPC channel for that interface.
package myplugin
import (
"net/rpc"
"github.com/veraison/plugin"
)
type IMyPlugin interface {
plugin.IPluggable
Method1()
}
var MyPluginRPC = &plugin.RPCChannel[IMyPlugin]{
GetClient: func(c *rpc.Client) interface{} { return &PRCClient{client: c } },
GetServer: func(i IMyPlugin) interface{} { return &PRCServer{Impl: i } },
}
type PRCClient {
client *rpc.Client
}
type RPCServer struct {
Impl IMyPlugin
}
// ---8<----------------------------------------------------------
// IMyPlugin implementations for RPCClient and RPCServer go below.
// ...
HashiCorp framework supports implementing RPC using net/rpc
or
gRPC. See
here for further details.
Creating plugins
ℹ For the specifics of how to create implementations of the already defined
IEndorsmentHandler
andIEvidenceHandler
Veraison plugins, see here.
Plugins are created by implementing the corresponding interface, registering
this implementation under an appropriate name (matching the name the manager
will look for on discovery -- see below), and serving the plugin inside
main()
:
package main
import (
"github.com/veraison/plugin"
"myplugin" // see above
)
type Impl struct {}
func (o *Impl) GetName() string { return "my-implementation" }
func (o *Impl) GetAttestationScheme() string { return "my-scheme" }
func (o *Impl) GetSupportedMediaTypes() []string { return []string{"text/html"} }
func (o *Impl) Method1() {}
func main() {
// "my-plugin" should match what the manager is looking for -- see below
plugin.RegisterImplementation("my-plugin", &Impl{}, myplugin.MyPluginRPC)
plugin.Serve()
}
Discovering and using plugins
In short, you create a manager using plugin.CreateGoPluginManager
, specifying
which plugins you want it to manage, and where to look for them, and then
look up your plugin either via it's name or one of the media types it supports.
package main
import (
"github.com/veraison/config"
"github.com/veraison/log"
"github.com/veraison/plugin"
"myplugin" // see above
)
func main() {
// Read configuration form a file using github.com/spf13/viper
v, err := config.ReadRawConfig("", false)
if err != nil {
log.Fatalf("Could not read config sources: %v", err)
}
// Extract the sub-secition of config related to plugin management
subs, err := config.GetSubs(v, "plugin")
if err != nil {
log.Fatal(err)
}
pluginManager, err := plugin.CreateGoPluginManager(
subs["plugin"], log.Named("plugin"),
// plugins must register themselves with type "my-plugin" -- see
// above.
"my-plugins", myplugin.MyPluginRPC)
var impl myplugin.IMyPlugin
// look up by name...
imp, err = pluginManager.LookupByName("my-implementation")
if err != nil {
log.Fatal(err)
}
// ...or, alternatively, by media type
imp, err = pluginManager.LookupByMediaType("test/html")
if err != nil {
log.Fatal(err)
}
// use your plugin
impl.Method1()
}
Documentation
¶
Overview ¶
Copyright 2023 Contributors to the Veraison project. SPDX-License-Identifier: Apache-2.0
Copyright 2023 Contributors to the Veraison project. SPDX-License-Identifier: Apache-2.0
Copyright 2023 Contributors to the Veraison project. SPDX-License-Identifier: Apache-2.0
Copyright 2023 Contributors to the Veraison project. SPDX-License-Identifier: Apache-2.0
Copyright 2023 Contributors to the Veraison project. SPDX-License-Identifier: Apache-2.0
Copyright 2023 Contributors to the Veraison project. SPDX-License-Identifier: Apache-2.0
Copyright 2023 Contributors to the Veraison project. SPDX-License-Identifier: Apache-2.0
Copyright 2023 Contributors to the Veraison project. SPDX-License-Identifier: Apache-2.0
Index ¶
- Variables
- func DiscoverGoPlugin[I IPluggable]() error
- func DiscoverGoPluginUsing[I IPluggable](o *GoPluginLoader) error
- func GetGoPluginHandleByAttestationSchemeUsing[I IPluggable](ldr *GoPluginLoader, scheme string) (I, error)
- func GetGoPluginHandleByMediaType[I IPluggable](mediaType string) (I, error)
- func GetGoPluginHandleByMediaTypeUsing[I IPluggable](ldr *GoPluginLoader, mediaType string) (I, error)
- func GetGoPluginHandleByNameUsing[I IPluggable](ldr *GoPluginLoader, name string) (I, error)
- func GetGoPluginLoadedAttestationSchemes[I IPluggable](ldr *GoPluginLoader) []string
- func GetRPCClient[I IPluggable](name string, impl I, c *rpc.Client) interface{}
- func GetRPCServer[I IPluggable](name string, impl I) interface{}
- func GetTypeName[I IPluggable]() string
- func Init(m map[string]interface{}) error
- func RegisterGoPlugin[I IPluggable](name string, ch *RPCChannel[I]) error
- func RegisterGoPluginUsing[I IPluggable](loader *GoPluginLoader, name string, ch *RPCChannel[I]) error
- func RegisterImplementation[I IPluggable](name string, i I, ch *RPCChannel[I]) error
- func Serve()
- type GoPluginLoader
- type GoPluginLoaderConfig
- type GoPluginManager
- func CreateGoPluginManager[I IPluggable](v *viper.Viper, logger *zap.SugaredLogger, name string, ch *RPCChannel[I]) (*GoPluginManager[I], error)
- func CreateGoPluginManagerWithLoader[I IPluggable](loader *GoPluginLoader, name string, logger *zap.SugaredLogger, ...) (*GoPluginManager[I], error)
- func NewGoPluginManager[I IPluggable](loader *GoPluginLoader, logger *zap.SugaredLogger) *GoPluginManager[I]
- func (o *GoPluginManager[I]) Close() error
- func (o *GoPluginManager[I]) GetRegisteredAttestationSchemes() []string
- func (o *GoPluginManager[I]) GetRegisteredMediaTypes() []string
- func (o *GoPluginManager[I]) Init(name string, ch *RPCChannel[I]) error
- func (o *GoPluginManager[I]) IsRegisteredMediaType(mediaType string) bool
- func (o *GoPluginManager[I]) LookupByAttestationScheme(name string) (I, error)
- func (o *GoPluginManager[I]) LookupByMediaType(mediaType string) (I, error)
- func (o *GoPluginManager[I]) LookupByName(name string) (I, error)
- type IManager
- type IPluggable
- type IPluginContext
- type Plugin
- type PluginContext
- type RPCChannel
Constants ¶
This section is empty.
Variables ¶
var ErrNotFound = errors.New("plugin not found")
Functions ¶
func DiscoverGoPlugin ¶
func DiscoverGoPlugin[I IPluggable]() error
func DiscoverGoPluginUsing ¶
func DiscoverGoPluginUsing[I IPluggable](o *GoPluginLoader) error
func GetGoPluginHandleByAttestationSchemeUsing ¶
func GetGoPluginHandleByAttestationSchemeUsing[I IPluggable]( ldr *GoPluginLoader, scheme string, ) (I, error)
func GetGoPluginHandleByMediaType ¶
func GetGoPluginHandleByMediaType[I IPluggable](mediaType string) (I, error)
func GetGoPluginHandleByMediaTypeUsing ¶
func GetGoPluginHandleByMediaTypeUsing[I IPluggable]( ldr *GoPluginLoader, mediaType string, ) (I, error)
func GetGoPluginHandleByNameUsing ¶
func GetGoPluginHandleByNameUsing[I IPluggable](ldr *GoPluginLoader, name string) (I, error)
func GetGoPluginLoadedAttestationSchemes ¶
func GetGoPluginLoadedAttestationSchemes[I IPluggable](ldr *GoPluginLoader) []string
func GetRPCClient ¶
func GetRPCClient[I IPluggable](name string, impl I, c *rpc.Client) interface{}
func GetRPCServer ¶
func GetRPCServer[I IPluggable](name string, impl I) interface{}
func GetTypeName ¶
func GetTypeName[I IPluggable]() string
func RegisterGoPlugin ¶
func RegisterGoPlugin[I IPluggable](name string, ch *RPCChannel[I]) error
func RegisterGoPluginUsing ¶
func RegisterGoPluginUsing[I IPluggable]( loader *GoPluginLoader, name string, ch *RPCChannel[I], ) error
func RegisterImplementation ¶
func RegisterImplementation[I IPluggable](name string, i I, ch *RPCChannel[I]) error
Types ¶
type GoPluginLoader ¶
type GoPluginLoader struct { Location string // contains filtered or unexported fields }
func CreateGoPluginLoader ¶
func CreateGoPluginLoader( cfg map[string]interface{}, logger *zap.SugaredLogger, ) (*GoPluginLoader, error)
func NewGoPluginLoader ¶
func NewGoPluginLoader(logger *zap.SugaredLogger) *GoPluginLoader
func (*GoPluginLoader) Close ¶
func (o *GoPluginLoader) Close()
func (*GoPluginLoader) GetRegisteredMediaTypes ¶
func (o *GoPluginLoader) GetRegisteredMediaTypes() []string
func (*GoPluginLoader) GetRegisteredMediaTypesByPluginType ¶
func (o *GoPluginLoader) GetRegisteredMediaTypesByPluginType(typeName string) []string
func (*GoPluginLoader) Init ¶
func (o *GoPluginLoader) Init(m map[string]interface{}) error
type GoPluginLoaderConfig ¶
type GoPluginLoaderConfig struct {
Directory string `mapstructure:"dir"`
}
type GoPluginManager ¶
type GoPluginManager[I IPluggable] struct { // contains filtered or unexported fields }
func CreateGoPluginManager ¶
func CreateGoPluginManager[I IPluggable]( v *viper.Viper, logger *zap.SugaredLogger, name string, ch *RPCChannel[I], ) (*GoPluginManager[I], error)
func CreateGoPluginManagerWithLoader ¶
func CreateGoPluginManagerWithLoader[I IPluggable]( loader *GoPluginLoader, name string, logger *zap.SugaredLogger, ch *RPCChannel[I], ) (*GoPluginManager[I], error)
func NewGoPluginManager ¶
func NewGoPluginManager[I IPluggable]( loader *GoPluginLoader, logger *zap.SugaredLogger, ) *GoPluginManager[I]
func (*GoPluginManager[I]) Close ¶
func (o *GoPluginManager[I]) Close() error
func (*GoPluginManager[I]) GetRegisteredAttestationSchemes ¶
func (o *GoPluginManager[I]) GetRegisteredAttestationSchemes() []string
func (*GoPluginManager[I]) GetRegisteredMediaTypes ¶
func (o *GoPluginManager[I]) GetRegisteredMediaTypes() []string
func (*GoPluginManager[I]) Init ¶
func (o *GoPluginManager[I]) Init(name string, ch *RPCChannel[I]) error
func (*GoPluginManager[I]) IsRegisteredMediaType ¶
func (o *GoPluginManager[I]) IsRegisteredMediaType(mediaType string) bool
func (*GoPluginManager[I]) LookupByAttestationScheme ¶
func (o *GoPluginManager[I]) LookupByAttestationScheme(name string) (I, error)
func (*GoPluginManager[I]) LookupByMediaType ¶
func (o *GoPluginManager[I]) LookupByMediaType(mediaType string) (I, error)
func (*GoPluginManager[I]) LookupByName ¶
func (o *GoPluginManager[I]) LookupByName(name string) (I, error)
type IManager ¶
type IManager[I IPluggable] interface { // Init initializes the manager, configuring the RPC channel that will // be used to communicate with plugins, and performing plugin // discovery. Init(name string, ch *RPCChannel[I]) error // Close terminates the manager, shutting down any current plugin // connections. Close() error // IsRegisteredMediaType returns true iff the provided mediaType has // been registered with that manager as handled by one of the // discovered plugins. IsRegisteredMediaType(mediaType string) bool // GetRegisteredMediaTypes returns a []string of media types that have // been registered with the manager by discovered plugins. GetRegisteredMediaTypes() []string // GetRegisteredAttestationSchemes returns a []string of names for // schemes that have been registered with the manager by discovered // plugins. GetRegisteredAttestationSchemes() []string // LookupByMediaType returns a handle (implementation of the managed // interface) to the plugin that handles the specified mediaType. If // the mediaType is not handled by any of the registered plugins, an // error is returned. LookupByMediaType(mediaType string) (I, error) // LookupByName returns a handle (implementation of the managed // interface) to the plugin with the specified name. If there is no // such plugin, an error is returned. LookupByName(name string) (I, error) // LookupByScheme returns a handle (implementation of the managed // interface) to the plugin that implements the attestation scheme with // the specified name. If there is no such plugin, an error is // returned. LookupByAttestationScheme(name string) (I, error) }
IManager defines the interface for managing plugins of a particular type (specified by the type parameter).
type IPluggable ¶
type IPluggable interface { // GetName returns a string containing the name of the // implementation of this IPluggable interface. It is the plugin name. GetName() string // GetAttestationScheme returns a string containing the name of the // attestation scheme handled by this IPluggable implementation. GetAttestationScheme() string // GetSupportedMediaTypes returns a []string containing the media types // this plugin is capable of handling. GetSupportedMediaTypes() []string }
IPluggable respresents a "pluggable" point within Veraison services. It is the common interfaces shared by all Veraison plugins loaded through this framework.
type IPluginContext ¶
type IPluginContext interface { GetName() string GetAttestationScheme() string GetTypeName() string GetPath() string GetHandle() interface{} Close() }
IPluginContext is the common interace for handling all PluginContext[I] type instances of the generic PluginContext[].
type PluginContext ¶
type PluginContext[I IPluggable] struct { // Path to the exectable binary containing the plugin implementation Path string // Name of this plugin Name string // Name of the attestatin scheme implemented by this plugin Scheme string // SupportedMediaTypes are the types of input this plugin can process. // This is is the method by which a plugin is selected. SupportedMediaTypes []string // Handle is actual RPC interface to the plugin implementation. Handle I // contains filtered or unexported fields }
PluginConntext is a generic for handling Veraison services plugins. It is parameterised on the IPluggale interface it handles.
func (PluginContext[I]) Close ¶
func (o PluginContext[I]) Close()
func (PluginContext[I]) GetAttestationScheme ¶
func (o PluginContext[I]) GetAttestationScheme() string
func (PluginContext[I]) GetHandle ¶
func (o PluginContext[I]) GetHandle() interface{}
func (PluginContext[I]) GetName ¶
func (o PluginContext[I]) GetName() string
func (PluginContext[I]) GetPath ¶
func (o PluginContext[I]) GetPath() string
func (PluginContext[I]) GetTypeName ¶
func (o PluginContext[I]) GetTypeName() string
type RPCChannel ¶
type RPCChannel[I IPluggable] struct { GetClient func(c *rpc.Client) interface{} GetServer func(i I) interface{} }