Fix client reloading and pass the plugin loaders to server and client
This commit is contained in:
parent
183561cf82
commit
6f0ed6184b
|
@ -15,6 +15,7 @@ IMPROVEMENTS:
|
|||
|
||||
BUG FIXES:
|
||||
* core: Fixed bug in reconciler where allocs already stopped were being unnecessarily updated [[GH-4764](https://github.com/hashicorp/nomad/issues/4764)]
|
||||
* client: Fix an issue reloading the client config [[GH-4730](https://github.com/hashicorp/nomad/issues/4730)]
|
||||
|
||||
## 0.8.6 (September 26, 2018)
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/hashicorp/nomad/helper"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
"github.com/hashicorp/nomad/nomad/structs/config"
|
||||
"github.com/hashicorp/nomad/plugins/shared/loader"
|
||||
"github.com/hashicorp/nomad/version"
|
||||
)
|
||||
|
||||
|
@ -206,6 +207,13 @@ type Config struct {
|
|||
// This period is meant to be long enough for a leader election to take
|
||||
// place, and a small jitter is applied to avoid a thundering herd.
|
||||
RPCHoldTimeout time.Duration
|
||||
|
||||
// PluginLoader is used to load plugins.
|
||||
PluginLoader loader.PluginCatalog
|
||||
|
||||
// PluginSingletonLoader is a plugin loader that will returns singleton
|
||||
// instances of the plugins.
|
||||
PluginSingletonLoader loader.PluginCatalog
|
||||
}
|
||||
|
||||
func (c *Config) Copy() *Config {
|
||||
|
|
|
@ -8,12 +8,16 @@ import (
|
|||
"github.com/hashicorp/nomad/helper"
|
||||
"github.com/hashicorp/nomad/helper/testlog"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
"github.com/hashicorp/nomad/plugins/shared/catalog"
|
||||
"github.com/hashicorp/nomad/plugins/shared/singleton"
|
||||
"github.com/mitchellh/go-testing-interface"
|
||||
)
|
||||
|
||||
// TestClient creates an in-memory client for testing purposes.
|
||||
func TestClient(t testing.T, cb func(c *config.Config)) *Client {
|
||||
conf := config.DefaultConfig()
|
||||
logger := testlog.HCLogger(t)
|
||||
conf.Logger = logger
|
||||
conf.VaultConfig.Enabled = helper.BoolToPtr(false)
|
||||
conf.DevMode = true
|
||||
conf.Node = &structs.Node{
|
||||
|
@ -32,12 +36,14 @@ func TestClient(t testing.T, cb func(c *config.Config)) *Client {
|
|||
}
|
||||
conf.Options[fingerprint.TightenNetworkTimeoutsConfig] = "true"
|
||||
|
||||
// Set the plugin loaders
|
||||
conf.PluginLoader = catalog.TestPluginLoader(t)
|
||||
conf.PluginSingletonLoader = singleton.NewSingletonLoader(logger, conf.PluginLoader)
|
||||
|
||||
if cb != nil {
|
||||
cb(conf)
|
||||
}
|
||||
|
||||
logger := testlog.HCLogger(t)
|
||||
conf.Logger = logger
|
||||
catalog := consul.NewMockCatalog(logger)
|
||||
mockService := consulApi.NewMockConsulServiceClient(t, logger)
|
||||
client, err := NewClient(conf, catalog, mockService)
|
||||
|
|
|
@ -110,7 +110,6 @@ func NewAgent(config *Config, logOutput io.Writer, inmem *metrics.InmemSink) (*A
|
|||
return nil, fmt.Errorf("Failed to initialize Consul client: %v", err)
|
||||
}
|
||||
|
||||
// TODO setup plugin loader
|
||||
if err := a.setupPlugins(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -129,14 +128,13 @@ func NewAgent(config *Config, logOutput io.Writer, inmem *metrics.InmemSink) (*A
|
|||
}
|
||||
|
||||
// convertServerConfig takes an agent config and log output and returns a Nomad
|
||||
// Config.
|
||||
func convertServerConfig(agentConfig *Config, logger log.Logger, logOutput io.Writer) (*nomad.Config, error) {
|
||||
// Config. There may be missing fields that must be set by the agent. To do this
|
||||
// call finalizeServerConfig
|
||||
func convertServerConfig(agentConfig *Config) (*nomad.Config, error) {
|
||||
conf := agentConfig.NomadConfig
|
||||
if conf == nil {
|
||||
conf = nomad.DefaultConfig()
|
||||
}
|
||||
conf.Logger = logger
|
||||
conf.LogOutput = logOutput
|
||||
conf.DevMode = agentConfig.DevMode
|
||||
conf.Build = agentConfig.Version.VersionNumber()
|
||||
if agentConfig.Region != "" {
|
||||
|
@ -335,61 +333,73 @@ func convertServerConfig(agentConfig *Config, logger log.Logger, logOutput io.Wr
|
|||
// serverConfig is used to generate a new server configuration struct
|
||||
// for initializing a nomad server.
|
||||
func (a *Agent) serverConfig() (*nomad.Config, error) {
|
||||
return convertServerConfig(a.config, a.logger, a.logOutput)
|
||||
c, err := convertServerConfig(a.config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
a.finalizeServerConfig(c)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// clientConfig is used to generate a new client configuration struct
|
||||
// for initializing a Nomad client.
|
||||
// finalizeServerConfig sets configuration fields on the server config that are
|
||||
// not staticly convertable and are from the agent.
|
||||
func (a *Agent) finalizeServerConfig(c *nomad.Config) {
|
||||
// Setup the logging
|
||||
c.Logger = a.logger
|
||||
c.LogOutput = a.logOutput
|
||||
|
||||
// Setup the plugin loaders
|
||||
c.PluginLoader = a.pluginLoader
|
||||
c.PluginSingletonLoader = a.pluginSingletonLoader
|
||||
}
|
||||
|
||||
// clientConfig is used to generate a new client configuration struct for
|
||||
// initializing a Nomad client.
|
||||
func (a *Agent) clientConfig() (*clientconfig.Config, error) {
|
||||
// Setup the configuration
|
||||
conf := a.config.ClientConfig
|
||||
if conf == nil {
|
||||
conf = clientconfig.DefaultConfig()
|
||||
c, err := convertClientConfig(a.config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := a.finalizeClientConfig(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// finalizeClientConfig sets configuration fields on the client config that are
|
||||
// not staticly convertable and are from the agent.
|
||||
func (a *Agent) finalizeClientConfig(c *clientconfig.Config) error {
|
||||
// Setup the logging
|
||||
c.Logger = a.logger
|
||||
c.LogOutput = a.logOutput
|
||||
|
||||
// If we are running a server, append both its bind and advertise address so
|
||||
// we are able to at least talk to the local server even if that isn't
|
||||
// configured explicitly. This handles both running server and client on one
|
||||
// host and -dev mode.
|
||||
conf.Servers = a.config.Client.Servers
|
||||
if a.server != nil {
|
||||
if a.config.AdvertiseAddrs == nil || a.config.AdvertiseAddrs.RPC == "" {
|
||||
return nil, fmt.Errorf("AdvertiseAddrs is nil or empty")
|
||||
return fmt.Errorf("AdvertiseAddrs is nil or empty")
|
||||
} else if a.config.normalizedAddrs == nil || a.config.normalizedAddrs.RPC == "" {
|
||||
return nil, fmt.Errorf("normalizedAddrs is nil or empty")
|
||||
return fmt.Errorf("normalizedAddrs is nil or empty")
|
||||
}
|
||||
|
||||
conf.Servers = append(conf.Servers,
|
||||
c.Servers = append(c.Servers,
|
||||
a.config.normalizedAddrs.RPC,
|
||||
a.config.AdvertiseAddrs.RPC)
|
||||
}
|
||||
|
||||
conf.Logger = a.logger
|
||||
conf.LogOutput = a.logOutput
|
||||
conf.LogLevel = a.config.LogLevel
|
||||
conf.DevMode = a.config.DevMode
|
||||
if a.config.Region != "" {
|
||||
conf.Region = a.config.Region
|
||||
}
|
||||
if a.config.DataDir != "" {
|
||||
conf.StateDir = filepath.Join(a.config.DataDir, "client")
|
||||
conf.AllocDir = filepath.Join(a.config.DataDir, "alloc")
|
||||
}
|
||||
if a.config.Client.StateDir != "" {
|
||||
conf.StateDir = a.config.Client.StateDir
|
||||
}
|
||||
if a.config.Client.AllocDir != "" {
|
||||
conf.AllocDir = a.config.Client.AllocDir
|
||||
}
|
||||
if a.config.Client.NetworkInterface != "" {
|
||||
conf.NetworkInterface = a.config.Client.NetworkInterface
|
||||
}
|
||||
conf.ChrootEnv = a.config.Client.ChrootEnv
|
||||
conf.Options = a.config.Client.Options
|
||||
// Logging deprecation messages about consul related configuration in client
|
||||
// Setup the plugin loaders
|
||||
c.PluginLoader = a.pluginLoader
|
||||
c.PluginSingletonLoader = a.pluginSingletonLoader
|
||||
|
||||
// Log deprecation messages about Consul related configuration in client
|
||||
// options
|
||||
var invalidConsulKeys []string
|
||||
for key := range conf.Options {
|
||||
for key := range c.Options {
|
||||
if strings.HasPrefix(key, "consul") {
|
||||
invalidConsulKeys = append(invalidConsulKeys, fmt.Sprintf("options.%s", key))
|
||||
}
|
||||
|
@ -401,34 +411,68 @@ func (a *Agent) clientConfig() (*clientconfig.Config, error) {
|
|||
to configure Nomad to work with Consul.`)
|
||||
}
|
||||
|
||||
if a.config.Client.NetworkSpeed != 0 {
|
||||
conf.NetworkSpeed = a.config.Client.NetworkSpeed
|
||||
return nil
|
||||
}
|
||||
|
||||
// convertClientConfig takes an agent config and log output and returns a client
|
||||
// Config. There may be missing fields that must be set by the agent. To do this
|
||||
// call finalizeServerConfig
|
||||
func convertClientConfig(agentConfig *Config) (*clientconfig.Config, error) {
|
||||
// Setup the configuration
|
||||
conf := agentConfig.ClientConfig
|
||||
if conf == nil {
|
||||
conf = clientconfig.DefaultConfig()
|
||||
}
|
||||
if a.config.Client.CpuCompute != 0 {
|
||||
conf.CpuCompute = a.config.Client.CpuCompute
|
||||
|
||||
conf.Servers = agentConfig.Client.Servers
|
||||
conf.LogLevel = agentConfig.LogLevel
|
||||
conf.DevMode = agentConfig.DevMode
|
||||
if agentConfig.Region != "" {
|
||||
conf.Region = agentConfig.Region
|
||||
}
|
||||
if a.config.Client.MemoryMB != 0 {
|
||||
conf.MemoryMB = a.config.Client.MemoryMB
|
||||
if agentConfig.DataDir != "" {
|
||||
conf.StateDir = filepath.Join(agentConfig.DataDir, "client")
|
||||
conf.AllocDir = filepath.Join(agentConfig.DataDir, "alloc")
|
||||
}
|
||||
if a.config.Client.MaxKillTimeout != "" {
|
||||
dur, err := time.ParseDuration(a.config.Client.MaxKillTimeout)
|
||||
if agentConfig.Client.StateDir != "" {
|
||||
conf.StateDir = agentConfig.Client.StateDir
|
||||
}
|
||||
if agentConfig.Client.AllocDir != "" {
|
||||
conf.AllocDir = agentConfig.Client.AllocDir
|
||||
}
|
||||
if agentConfig.Client.NetworkInterface != "" {
|
||||
conf.NetworkInterface = agentConfig.Client.NetworkInterface
|
||||
}
|
||||
conf.ChrootEnv = agentConfig.Client.ChrootEnv
|
||||
conf.Options = agentConfig.Client.Options
|
||||
if agentConfig.Client.NetworkSpeed != 0 {
|
||||
conf.NetworkSpeed = agentConfig.Client.NetworkSpeed
|
||||
}
|
||||
if agentConfig.Client.CpuCompute != 0 {
|
||||
conf.CpuCompute = agentConfig.Client.CpuCompute
|
||||
}
|
||||
if agentConfig.Client.MemoryMB != 0 {
|
||||
conf.MemoryMB = agentConfig.Client.MemoryMB
|
||||
}
|
||||
if agentConfig.Client.MaxKillTimeout != "" {
|
||||
dur, err := time.ParseDuration(agentConfig.Client.MaxKillTimeout)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error parsing max kill timeout: %s", err)
|
||||
}
|
||||
conf.MaxKillTimeout = dur
|
||||
}
|
||||
conf.ClientMaxPort = uint(a.config.Client.ClientMaxPort)
|
||||
conf.ClientMinPort = uint(a.config.Client.ClientMinPort)
|
||||
conf.ClientMaxPort = uint(agentConfig.Client.ClientMaxPort)
|
||||
conf.ClientMinPort = uint(agentConfig.Client.ClientMinPort)
|
||||
|
||||
// Setup the node
|
||||
conf.Node = new(structs.Node)
|
||||
conf.Node.Datacenter = a.config.Datacenter
|
||||
conf.Node.Name = a.config.NodeName
|
||||
conf.Node.Meta = a.config.Client.Meta
|
||||
conf.Node.NodeClass = a.config.Client.NodeClass
|
||||
conf.Node.Datacenter = agentConfig.Datacenter
|
||||
conf.Node.Name = agentConfig.NodeName
|
||||
conf.Node.Meta = agentConfig.Client.Meta
|
||||
conf.Node.NodeClass = agentConfig.Client.NodeClass
|
||||
|
||||
// Set up the HTTP advertise address
|
||||
conf.Node.HTTPAddr = a.config.AdvertiseAddrs.HTTP
|
||||
conf.Node.HTTPAddr = agentConfig.AdvertiseAddrs.HTTP
|
||||
|
||||
// Reserve resources on the node.
|
||||
// COMPAT(0.10): Remove in 0.10
|
||||
|
@ -437,58 +481,58 @@ func (a *Agent) clientConfig() (*clientconfig.Config, error) {
|
|||
r = new(structs.Resources)
|
||||
conf.Node.Reserved = r
|
||||
}
|
||||
r.CPU = a.config.Client.Reserved.CPU
|
||||
r.MemoryMB = a.config.Client.Reserved.MemoryMB
|
||||
r.DiskMB = a.config.Client.Reserved.DiskMB
|
||||
r.IOPS = a.config.Client.Reserved.IOPS
|
||||
r.CPU = agentConfig.Client.Reserved.CPU
|
||||
r.MemoryMB = agentConfig.Client.Reserved.MemoryMB
|
||||
r.DiskMB = agentConfig.Client.Reserved.DiskMB
|
||||
r.IOPS = agentConfig.Client.Reserved.IOPS
|
||||
|
||||
res := conf.Node.ReservedResources
|
||||
if res == nil {
|
||||
res = new(structs.NodeReservedResources)
|
||||
conf.Node.ReservedResources = res
|
||||
}
|
||||
res.Cpu.CpuShares = int64(a.config.Client.Reserved.CPU)
|
||||
res.Memory.MemoryMB = int64(a.config.Client.Reserved.MemoryMB)
|
||||
res.Disk.DiskMB = int64(a.config.Client.Reserved.DiskMB)
|
||||
res.Networks.ReservedHostPorts = a.config.Client.Reserved.ReservedPorts
|
||||
res.Cpu.CpuShares = int64(agentConfig.Client.Reserved.CPU)
|
||||
res.Memory.MemoryMB = int64(agentConfig.Client.Reserved.MemoryMB)
|
||||
res.Disk.DiskMB = int64(agentConfig.Client.Reserved.DiskMB)
|
||||
res.Networks.ReservedHostPorts = agentConfig.Client.Reserved.ReservedPorts
|
||||
|
||||
conf.Version = a.config.Version
|
||||
conf.Version = agentConfig.Version
|
||||
|
||||
if *a.config.Consul.AutoAdvertise && a.config.Consul.ClientServiceName == "" {
|
||||
if *agentConfig.Consul.AutoAdvertise && agentConfig.Consul.ClientServiceName == "" {
|
||||
return nil, fmt.Errorf("client_service_name must be set when auto_advertise is enabled")
|
||||
}
|
||||
|
||||
conf.ConsulConfig = a.config.Consul
|
||||
conf.VaultConfig = a.config.Vault
|
||||
conf.ConsulConfig = agentConfig.Consul
|
||||
conf.VaultConfig = agentConfig.Vault
|
||||
|
||||
// Set up Telemetry configuration
|
||||
conf.StatsCollectionInterval = a.config.Telemetry.collectionInterval
|
||||
conf.PublishNodeMetrics = a.config.Telemetry.PublishNodeMetrics
|
||||
conf.PublishAllocationMetrics = a.config.Telemetry.PublishAllocationMetrics
|
||||
conf.DisableTaggedMetrics = a.config.Telemetry.DisableTaggedMetrics
|
||||
conf.BackwardsCompatibleMetrics = a.config.Telemetry.BackwardsCompatibleMetrics
|
||||
conf.StatsCollectionInterval = agentConfig.Telemetry.collectionInterval
|
||||
conf.PublishNodeMetrics = agentConfig.Telemetry.PublishNodeMetrics
|
||||
conf.PublishAllocationMetrics = agentConfig.Telemetry.PublishAllocationMetrics
|
||||
conf.DisableTaggedMetrics = agentConfig.Telemetry.DisableTaggedMetrics
|
||||
conf.BackwardsCompatibleMetrics = agentConfig.Telemetry.BackwardsCompatibleMetrics
|
||||
|
||||
// Set the TLS related configs
|
||||
conf.TLSConfig = a.config.TLSConfig
|
||||
conf.TLSConfig = agentConfig.TLSConfig
|
||||
conf.Node.TLSEnabled = conf.TLSConfig.EnableHTTP
|
||||
|
||||
// Set the GC related configs
|
||||
conf.GCInterval = a.config.Client.GCInterval
|
||||
conf.GCParallelDestroys = a.config.Client.GCParallelDestroys
|
||||
conf.GCDiskUsageThreshold = a.config.Client.GCDiskUsageThreshold
|
||||
conf.GCInodeUsageThreshold = a.config.Client.GCInodeUsageThreshold
|
||||
conf.GCMaxAllocs = a.config.Client.GCMaxAllocs
|
||||
if a.config.Client.NoHostUUID != nil {
|
||||
conf.NoHostUUID = *a.config.Client.NoHostUUID
|
||||
conf.GCInterval = agentConfig.Client.GCInterval
|
||||
conf.GCParallelDestroys = agentConfig.Client.GCParallelDestroys
|
||||
conf.GCDiskUsageThreshold = agentConfig.Client.GCDiskUsageThreshold
|
||||
conf.GCInodeUsageThreshold = agentConfig.Client.GCInodeUsageThreshold
|
||||
conf.GCMaxAllocs = agentConfig.Client.GCMaxAllocs
|
||||
if agentConfig.Client.NoHostUUID != nil {
|
||||
conf.NoHostUUID = *agentConfig.Client.NoHostUUID
|
||||
} else {
|
||||
// Default no_host_uuid to true
|
||||
conf.NoHostUUID = true
|
||||
}
|
||||
|
||||
// Setup the ACLs
|
||||
conf.ACLEnabled = a.config.ACL.Enabled
|
||||
conf.ACLTokenTTL = a.config.ACL.TokenTTL
|
||||
conf.ACLPolicyTTL = a.config.ACL.PolicyTTL
|
||||
conf.ACLEnabled = agentConfig.ACL.Enabled
|
||||
conf.ACLTokenTTL = agentConfig.ACL.TokenTTL
|
||||
conf.ACLPolicyTTL = agentConfig.ACL.PolicyTTL
|
||||
|
||||
return conf, nil
|
||||
}
|
||||
|
|
|
@ -751,25 +751,36 @@ func (c *Command) handleReload() {
|
|||
|
||||
if s := c.agent.Server(); s != nil {
|
||||
c.agent.logger.Debug("starting reload of server config")
|
||||
sconf, err := convertServerConfig(newConf, c.agent.logger, c.logOutput)
|
||||
sconf, err := convertServerConfig(newConf)
|
||||
if err != nil {
|
||||
c.agent.logger.Error("failed to convert server config", "error", err)
|
||||
return
|
||||
} else {
|
||||
if err := s.Reload(sconf); err != nil {
|
||||
c.agent.logger.Error("reloading server config failed", "error", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize the config to get the agent objects injected in
|
||||
c.agent.finalizeServerConfig(sconf)
|
||||
|
||||
// Reload the config
|
||||
if err := s.Reload(sconf); err != nil {
|
||||
c.agent.logger.Error("reloading server config failed", "error", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if s := c.agent.Client(); s != nil {
|
||||
clientConfig, err := c.agent.clientConfig()
|
||||
c.agent.logger.Debug("starting reload of client config")
|
||||
clientConfig, err := convertClientConfig(newConf)
|
||||
if err != nil {
|
||||
c.agent.logger.Error("reloading client config failed", "error", err)
|
||||
c.agent.logger.Error("failed to convert client config", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Finalize the config to get the agent objects injected in
|
||||
if err := c.agent.finalizeClientConfig(clientConfig); err != nil {
|
||||
c.agent.logger.Error("failed to finalize client config", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.agent.Client().Reload(clientConfig); err != nil {
|
||||
c.agent.logger.Error("reloading client config failed", "error", err)
|
||||
return
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/hashicorp/nomad/helper/uuid"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
"github.com/hashicorp/nomad/nomad/structs/config"
|
||||
"github.com/hashicorp/nomad/plugins/shared/loader"
|
||||
"github.com/hashicorp/nomad/scheduler"
|
||||
"github.com/hashicorp/raft"
|
||||
"github.com/hashicorp/serf/serf"
|
||||
|
@ -295,6 +296,13 @@ type Config struct {
|
|||
// autopilot tasks, such as promoting eligible non-voters and removing
|
||||
// dead servers.
|
||||
AutopilotInterval time.Duration
|
||||
|
||||
// PluginLoader is used to load plugins.
|
||||
PluginLoader loader.PluginCatalog
|
||||
|
||||
// PluginSingletonLoader is a plugin loader that will returns singleton
|
||||
// instances of the plugins.
|
||||
PluginSingletonLoader loader.PluginCatalog
|
||||
}
|
||||
|
||||
// CheckVersion is used to check if the ProtocolVersion is valid
|
||||
|
|
|
@ -12,6 +12,8 @@ import (
|
|||
"github.com/hashicorp/nomad/helper/testlog"
|
||||
"github.com/hashicorp/nomad/nomad/mock"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
"github.com/hashicorp/nomad/plugins/shared/catalog"
|
||||
"github.com/hashicorp/nomad/plugins/shared/singleton"
|
||||
"github.com/mitchellh/go-testing-interface"
|
||||
)
|
||||
|
||||
|
@ -69,6 +71,10 @@ func TestServer(t testing.T, cb func(*Config)) *Server {
|
|||
config.ServerHealthInterval = 50 * time.Millisecond
|
||||
config.AutopilotInterval = 100 * time.Millisecond
|
||||
|
||||
// Set the plugin loaders
|
||||
config.PluginLoader = catalog.TestPluginLoader(t)
|
||||
config.PluginSingletonLoader = singleton.NewSingletonLoader(config.Logger, config.PluginLoader)
|
||||
|
||||
// Invoke the callback if any
|
||||
if cb != nil {
|
||||
cb(config)
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package catalog
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/nomad/helper/testlog"
|
||||
"github.com/hashicorp/nomad/nomad/structs/config"
|
||||
"github.com/hashicorp/nomad/plugins/shared/loader"
|
||||
"github.com/mitchellh/go-testing-interface"
|
||||
)
|
||||
|
||||
// TestPluginLoader returns a plugin loader populated only with internal plugins
|
||||
func TestPluginLoader(t testing.T) loader.PluginCatalog {
|
||||
return TestPluginLoaderWithOptions(t, "", nil, nil)
|
||||
}
|
||||
|
||||
// TestPluginLoaderWithOptions allows configuring the plugin loader fully.
|
||||
func TestPluginLoaderWithOptions(t testing.T,
|
||||
pluginDir string,
|
||||
options map[string]string,
|
||||
configs []*config.PluginConfig) loader.PluginCatalog {
|
||||
|
||||
// Get a logger
|
||||
logger := testlog.HCLogger(t)
|
||||
|
||||
// Get the registered plugins
|
||||
catalog := Catalog()
|
||||
|
||||
// Create our map of plugins
|
||||
internal := make(map[loader.PluginID]*loader.InternalPluginConfig, len(catalog))
|
||||
|
||||
for id, reg := range catalog {
|
||||
if reg.Config == nil {
|
||||
logger.Warn("skipping loading internal plugin because it is missing its configuration", "plugin", id)
|
||||
continue
|
||||
}
|
||||
|
||||
pluginConfig := reg.Config.Config
|
||||
if reg.ConfigLoader != nil {
|
||||
pc, err := reg.ConfigLoader(options)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to retrieve config for internal plugin %v: %v", id, err)
|
||||
}
|
||||
|
||||
pluginConfig = pc
|
||||
}
|
||||
|
||||
internal[id] = &loader.InternalPluginConfig{
|
||||
Factory: reg.Config.Factory,
|
||||
Config: pluginConfig,
|
||||
}
|
||||
}
|
||||
|
||||
// Build the plugin loader
|
||||
config := &loader.PluginLoaderConfig{
|
||||
Logger: logger,
|
||||
PluginDir: "",
|
||||
Configs: configs,
|
||||
InternalPlugins: internal,
|
||||
}
|
||||
l, err := loader.NewPluginLoader(config)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create plugin loader: %v", err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
|
@ -32,8 +32,6 @@ func validateConfig(config *PluginLoaderConfig) error {
|
|||
return fmt.Errorf("nil config passed")
|
||||
} else if config.Logger == nil {
|
||||
multierror.Append(&mErr, fmt.Errorf("nil logger passed"))
|
||||
} else if config.PluginDir == "" {
|
||||
multierror.Append(&mErr, fmt.Errorf("invalid plugin dir %q passed", config.PluginDir))
|
||||
}
|
||||
|
||||
// Validate that all plugins have a binary name
|
||||
|
@ -149,9 +147,18 @@ func (l *PluginLoader) initInternal(plugins map[PluginID]*InternalPluginConfig,
|
|||
|
||||
// scan scans the plugin directory and retrieves potentially eligible binaries
|
||||
func (l *PluginLoader) scan() ([]os.FileInfo, error) {
|
||||
if l.pluginDir == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Capture the list of binaries in the plugins folder
|
||||
f, err := os.Open(l.pluginDir)
|
||||
if err != nil {
|
||||
// There are no plugins to scan
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to open plugin directory %q: %v", l.pluginDir, err)
|
||||
}
|
||||
files, err := f.Readdirnames(-1)
|
||||
|
|
Loading…
Reference in New Issue