diff --git a/client/client.go b/client/client.go index f99c2f330..ace692e56 100644 --- a/client/client.go +++ b/client/client.go @@ -1225,6 +1225,16 @@ func (c *Client) setupNode() error { if node.Name == "" { node.Name, _ = os.Hostname() } + // TODO(dani): Fingerprint these to handle volumes that don't exist/have bad perms. + if node.HostVolumes == nil { + if l := len(c.config.HostVolumes); l != 0 { + node.HostVolumes = make(map[string]*structs.ClientHostVolumeConfig, l) + for k, v := range c.config.HostVolumes { + node.HostVolumes[k] = v.Copy() + } + } + } + if node.Name == "" { node.Name = node.ID } diff --git a/client/config/config.go b/client/config/config.go index 9bac1803a..cb7e25726 100644 --- a/client/config/config.go +++ b/client/config/config.go @@ -234,6 +234,9 @@ type Config struct { // for allocations in bridge networking mode. Subnet must be in CIDR // notation BridgeNetworkAllocSubnet string + + // HostVolumes is the set of configured host volumes + HostVolumes map[string]*structs.ClientHostVolumeConfig } func (c *Config) Copy() *Config { @@ -242,6 +245,7 @@ func (c *Config) Copy() *Config { nc.Node = nc.Node.Copy() nc.Servers = helper.CopySliceString(nc.Servers) nc.Options = helper.CopyMapStringString(nc.Options) + nc.HostVolumes = structs.CopyMapStringClientHostVolumeConfig(nc.HostVolumes) nc.ConsulConfig = c.ConsulConfig.Copy() nc.VaultConfig = c.VaultConfig.Copy() return nc diff --git a/command/agent/agent.go b/command/agent/agent.go index f0f2cebf5..6cfe7266b 100644 --- a/command/agent/agent.go +++ b/command/agent/agent.go @@ -469,6 +469,12 @@ func convertClientConfig(agentConfig *Config) (*clientconfig.Config, error) { conf.ClientMinPort = uint(agentConfig.Client.ClientMinPort) conf.DisableRemoteExec = agentConfig.Client.DisableRemoteExec + hvMap := make(map[string]*structs.ClientHostVolumeConfig, len(agentConfig.Client.HostVolumes)) + for _, v := range agentConfig.Client.HostVolumes { + hvMap[v.Name] = v + } + conf.HostVolumes = hvMap + // Setup the node conf.Node = new(structs.Node) conf.Node.Datacenter = agentConfig.Datacenter diff --git a/command/agent/config.go b/command/agent/config.go index fe3f74c4b..2b5000307 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -245,6 +245,10 @@ type ClientConfig struct { // ServerJoin contains information that is used to attempt to join servers ServerJoin *ServerJoin `hcl:"server_join"` + // HostVolumes contains information about the volumes an operator has made + // available to jobs running on this node. + HostVolumes []*structs.ClientHostVolumeConfig `hcl:"host_volume"` + // ExtraKeysHCL is used by hcl to surface unexpected keys ExtraKeysHCL []string `hcl:",unusedKeys" json:"-"` @@ -1322,6 +1326,16 @@ func (a *ClientConfig) Merge(b *ClientConfig) *ClientConfig { result.ServerJoin = result.ServerJoin.Merge(b.ServerJoin) } + if len(a.HostVolumes) == 0 && len(b.HostVolumes) != 0 { + cc := make([]*structs.ClientHostVolumeConfig, len(b.HostVolumes)) + for k, v := range b.HostVolumes { + cc[k] = v.Copy() + } + result.HostVolumes = cc + } else if len(b.HostVolumes) != 0 { + result.HostVolumes = structs.HostVolumeSliceMerge(a.HostVolumes, b.HostVolumes) + } + return &result } diff --git a/command/agent/config_parse.go b/command/agent/config_parse.go index 225ca8942..0056af6ef 100644 --- a/command/agent/config_parse.go +++ b/command/agent/config_parse.go @@ -138,6 +138,11 @@ func extraKeys(c *Config) error { // stats is an unused key, continue to silently ignore it removeEqualFold(&c.Client.ExtraKeysHCL, "stats") + // Remove HostVolume extra keys + for _, hv := range c.Client.HostVolumes { + removeEqualFold(&c.Client.ExtraKeysHCL, hv.Name) + } + for _, k := range []string{"enabled_schedulers", "start_join", "retry_join", "server_join"} { removeEqualFold(&c.ExtraKeysHCL, k) removeEqualFold(&c.ExtraKeysHCL, "server") diff --git a/command/agent/config_parse_test.go b/command/agent/config_parse_test.go index c8593ce59..cbb57b833 100644 --- a/command/agent/config_parse_test.go +++ b/command/agent/config_parse_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/hashicorp/nomad/helper" + "github.com/hashicorp/nomad/nomad/structs" "github.com/hashicorp/nomad/nomad/structs/config" "github.com/stretchr/testify/require" ) @@ -81,6 +82,9 @@ var basicConfig = &Config{ GCMaxAllocs: 50, NoHostUUID: helper.BoolToPtr(false), DisableRemoteExec: true, + HostVolumes: []*structs.ClientHostVolumeConfig{ + {Name: "tmp", Source: "/tmp"}, + }, }, Server: &ServerConfig{ Enabled: true, diff --git a/command/agent/testdata/basic.hcl b/command/agent/testdata/basic.hcl index 97b4cd99c..68176295e 100644 --- a/command/agent/testdata/basic.hcl +++ b/command/agent/testdata/basic.hcl @@ -89,6 +89,10 @@ client { gc_max_allocs = 50 no_host_uuid = false disable_remote_exec = true + + host_volume "tmp" { + source = "/tmp" + } } server { diff --git a/command/agent/testdata/basic.json b/command/agent/testdata/basic.json index 11af6beb4..f855dd397 100644 --- a/command/agent/testdata/basic.json +++ b/command/agent/testdata/basic.json @@ -44,12 +44,22 @@ "client_max_port": 2000, "client_min_port": 1000, "cpu_total_compute": 4444, + "disable_remote_exec": true, "enabled": true, "gc_disk_usage_threshold": 82, "gc_inode_usage_threshold": 91, "gc_interval": "6s", "gc_max_allocs": 50, "gc_parallel_destroys": 6, + "host_volume": [ + { + "tmp": [ + { + "source": "/tmp" + } + ] + } + ], "max_kill_timeout": "10s", "meta": [ { @@ -60,7 +70,6 @@ "network_interface": "eth0", "network_speed": 100, "no_host_uuid": false, - "disable_remote_exec": true, "node_class": "linux-medium-64bit", "options": [ { @@ -137,25 +146,39 @@ "log_json": true, "log_level": "ERR", "name": "my-web", - "plugin": { - "docker": { - "args": [ - "foo", - "bar" - ], - "config": { - "foo": "bar", - "nested": { - "bam": 2 + "plugin": [ + { + "docker": [ + { + "args": [ + "foo", + "bar" + ], + "config": [ + { + "foo": "bar", + "nested": [ + { + "bam": 2 + } + ] + } + ] } - } + ] }, - "exec": { - "config": { - "foo": true + { + "exec": [ + { + "config": [ + { + "foo": true + } + ] } + ] } - }, + ], "plugin_dir": "/tmp/nomad-plugins", "ports": [ {