mirror of
https://github.com/kemko/nomad.git
synced 2026-01-03 08:55:43 +03:00
loader and singleton
This commit is contained in:
committed by
Michael Schurter
parent
b9f36134dc
commit
c19cd2e5cf
195
pluginutils/loader/plugin_test.go
Normal file
195
pluginutils/loader/plugin_test.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package loader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
plugin "github.com/hashicorp/go-plugin"
|
||||
"github.com/hashicorp/nomad/plugins/base"
|
||||
"github.com/hashicorp/nomad/plugins/device"
|
||||
"github.com/hashicorp/nomad/plugins/shared/hclspec"
|
||||
)
|
||||
|
||||
type stringSliceFlags []string
|
||||
|
||||
func (i *stringSliceFlags) String() string {
|
||||
return "my string representation"
|
||||
}
|
||||
|
||||
func (i *stringSliceFlags) Set(value string) error {
|
||||
*i = append(*i, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestMain runs either the tests or runs a mock plugin based on the passed
|
||||
// flags
|
||||
func TestMain(m *testing.M) {
|
||||
var plugin, configSchema bool
|
||||
var name, pluginType, pluginVersion string
|
||||
var pluginApiVersions stringSliceFlags
|
||||
flag.BoolVar(&plugin, "plugin", false, "run binary as a plugin")
|
||||
flag.BoolVar(&configSchema, "config-schema", true, "return a config schema")
|
||||
flag.StringVar(&name, "name", "", "plugin name")
|
||||
flag.StringVar(&pluginType, "type", "", "plugin type")
|
||||
flag.StringVar(&pluginVersion, "version", "", "plugin version")
|
||||
flag.Var(&pluginApiVersions, "api-version", "supported plugin API version")
|
||||
flag.Parse()
|
||||
|
||||
if plugin {
|
||||
if err := pluginMain(name, pluginType, pluginVersion, pluginApiVersions, configSchema); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
}
|
||||
|
||||
// pluginMain starts a mock plugin using the passed parameters
|
||||
func pluginMain(name, pluginType, version string, apiVersions []string, config bool) error {
|
||||
// Validate passed parameters
|
||||
if name == "" || pluginType == "" {
|
||||
return fmt.Errorf("name and plugin type must be specified")
|
||||
}
|
||||
|
||||
switch pluginType {
|
||||
case base.PluginTypeDevice:
|
||||
default:
|
||||
return fmt.Errorf("unsupported plugin type %q", pluginType)
|
||||
}
|
||||
|
||||
// Create the mock plugin
|
||||
m := &mockPlugin{
|
||||
name: name,
|
||||
ptype: pluginType,
|
||||
version: version,
|
||||
apiVersions: apiVersions,
|
||||
configSchema: config,
|
||||
}
|
||||
|
||||
// Build the plugin map
|
||||
pmap := map[string]plugin.Plugin{
|
||||
base.PluginTypeBase: &base.PluginBase{Impl: m},
|
||||
}
|
||||
switch pluginType {
|
||||
case base.PluginTypeDevice:
|
||||
pmap[base.PluginTypeDevice] = &device.PluginDevice{Impl: m}
|
||||
}
|
||||
|
||||
// Serve the plugin
|
||||
plugin.Serve(&plugin.ServeConfig{
|
||||
HandshakeConfig: base.Handshake,
|
||||
Plugins: pmap,
|
||||
GRPCServer: plugin.DefaultGRPCServer,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// mockFactory returns a PluginFactory method which creates the mock plugin with
|
||||
// the passed parameters
|
||||
func mockFactory(name, ptype, version string, apiVersions []string, configSchema bool) func(log log.Logger) interface{} {
|
||||
return func(log log.Logger) interface{} {
|
||||
return &mockPlugin{
|
||||
name: name,
|
||||
ptype: ptype,
|
||||
version: version,
|
||||
apiVersions: apiVersions,
|
||||
configSchema: configSchema,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mockPlugin is a plugin that meets various plugin interfaces but is only
|
||||
// useful for testing.
|
||||
type mockPlugin struct {
|
||||
name string
|
||||
ptype string
|
||||
version string
|
||||
apiVersions []string
|
||||
configSchema bool
|
||||
|
||||
// config is built on SetConfig
|
||||
config *mockPluginConfig
|
||||
|
||||
// nomadconfig is set on SetConfig
|
||||
nomadConfig *base.AgentConfig
|
||||
|
||||
// negotiatedApiVersion is the version of the api to use and is set on
|
||||
// SetConfig
|
||||
negotiatedApiVersion string
|
||||
}
|
||||
|
||||
// mockPluginConfig is the configuration for the mock plugin
|
||||
type mockPluginConfig struct {
|
||||
Foo string `codec:"foo"`
|
||||
Bar int `codec:"bar"`
|
||||
|
||||
// ResKey is a key that is populated in the Env map when a device is
|
||||
// reserved.
|
||||
ResKey string `codec:"res_key"`
|
||||
}
|
||||
|
||||
// PluginInfo returns the plugin information based on the passed fields when
|
||||
// building the mock plugin
|
||||
func (m *mockPlugin) PluginInfo() (*base.PluginInfoResponse, error) {
|
||||
return &base.PluginInfoResponse{
|
||||
Type: m.ptype,
|
||||
PluginApiVersions: m.apiVersions,
|
||||
PluginVersion: m.version,
|
||||
Name: m.name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *mockPlugin) ConfigSchema() (*hclspec.Spec, error) {
|
||||
if !m.configSchema {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// configSpec is the hclspec for parsing the mock's configuration
|
||||
configSpec := hclspec.NewObject(map[string]*hclspec.Spec{
|
||||
"foo": hclspec.NewAttr("foo", "string", false),
|
||||
"bar": hclspec.NewAttr("bar", "number", false),
|
||||
"res_key": hclspec.NewAttr("res_key", "string", false),
|
||||
})
|
||||
|
||||
return configSpec, nil
|
||||
}
|
||||
|
||||
// SetConfig decodes the configuration and stores it
|
||||
func (m *mockPlugin) SetConfig(c *base.Config) error {
|
||||
var config mockPluginConfig
|
||||
if len(c.PluginConfig) != 0 {
|
||||
if err := base.MsgPackDecode(c.PluginConfig, &config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
m.config = &config
|
||||
m.nomadConfig = c.AgentConfig
|
||||
m.negotiatedApiVersion = c.ApiVersion
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockPlugin) Fingerprint(ctx context.Context) (<-chan *device.FingerprintResponse, error) {
|
||||
return make(chan *device.FingerprintResponse), nil
|
||||
}
|
||||
|
||||
func (m *mockPlugin) Reserve(deviceIDs []string) (*device.ContainerReservation, error) {
|
||||
if m.config == nil || m.config.ResKey == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &device.ContainerReservation{
|
||||
Envs: map[string]string{m.config.ResKey: "config-set"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *mockPlugin) Stats(ctx context.Context, interval time.Duration) (<-chan *device.StatsResponse, error) {
|
||||
return make(chan *device.StatsResponse), nil
|
||||
}
|
||||
Reference in New Issue
Block a user