diff --git a/agent/exec/dockerapi/adapter.go b/agent/exec/dockerapi/adapter.go index e271b8a88d..e247866570 100644 --- a/agent/exec/dockerapi/adapter.go +++ b/agent/exec/dockerapi/adapter.go @@ -29,8 +29,8 @@ type containerAdapter struct { secrets exec.SecretGetter } -func newContainerAdapter(client engineapi.APIClient, task *api.Task, secrets exec.SecretGetter) (*containerAdapter, error) { - ctnr, err := newContainerConfig(task) +func newContainerAdapter(client engineapi.APIClient, nodeDescription *api.NodeDescription, task *api.Task, secrets exec.SecretGetter) (*containerAdapter, error) { + ctnr, err := newContainerConfig(nodeDescription, task) if err != nil { return nil, err } diff --git a/agent/exec/dockerapi/container.go b/agent/exec/dockerapi/container.go index 9bfb92f7bd..b4beffe59a 100644 --- a/agent/exec/dockerapi/container.go +++ b/agent/exec/dockerapi/container.go @@ -42,12 +42,12 @@ type containerConfig struct { // newContainerConfig returns a validated container config. No methods should // return an error if this function returns without error. -func newContainerConfig(t *api.Task) (*containerConfig, error) { +func newContainerConfig(n *api.NodeDescription, t *api.Task) (*containerConfig, error) { var c containerConfig - return &c, c.setTask(t) + return &c, c.setTask(n, t) } -func (c *containerConfig) setTask(t *api.Task) error { +func (c *containerConfig) setTask(n *api.NodeDescription, t *api.Task) error { container := t.Spec.GetContainer() if container == nil { return exec.ErrRuntimeUnsupported @@ -64,7 +64,7 @@ func (c *containerConfig) setTask(t *api.Task) error { } c.task = t - preparedSpec, err := template.ExpandContainerSpec(t) + preparedSpec, err := template.ExpandContainerSpec(n, t) if err != nil { return err } diff --git a/agent/exec/dockerapi/controller.go b/agent/exec/dockerapi/controller.go index 33178dc272..5f73f03b51 100644 --- a/agent/exec/dockerapi/controller.go +++ b/agent/exec/dockerapi/controller.go @@ -41,8 +41,8 @@ type controller struct { var _ exec.Controller = &controller{} // newController returns a docker exec controller for the provided task. -func newController(client engineapi.APIClient, task *api.Task, secrets exec.SecretGetter) (exec.Controller, error) { - adapter, err := newContainerAdapter(client, task, secrets) +func newController(client engineapi.APIClient, nodeDescription *api.NodeDescription, task *api.Task, secrets exec.SecretGetter) (exec.Controller, error) { + adapter, err := newContainerAdapter(client, nodeDescription, task, secrets) if err != nil { return nil, err } diff --git a/agent/exec/dockerapi/controller_integration_test.go b/agent/exec/dockerapi/controller_integration_test.go index 33bb448a06..3c4d6866d5 100644 --- a/agent/exec/dockerapi/controller_integration_test.go +++ b/agent/exec/dockerapi/controller_integration_test.go @@ -80,7 +80,7 @@ func TestControllerFlowIntegration(t *testing.T) { return nil }) - ctlr, err := newController(client, task, nil) + ctlr, err := newController(client, nil, task, nil) assert.NoError(t, err) assert.NotNil(t, ctlr) assert.NoError(t, ctlr.Prepare(ctx)) diff --git a/agent/exec/dockerapi/controller_test.go b/agent/exec/dockerapi/controller_test.go index 6ddac9b414..7c95fabbe4 100644 --- a/agent/exec/dockerapi/controller_test.go +++ b/agent/exec/dockerapi/controller_test.go @@ -411,11 +411,19 @@ func TestControllerRemove(t *testing.T) { } func genTestControllerEnv(t *testing.T, task *api.Task) (context.Context, *StubAPIClient, exec.Controller, *containerConfig, func()) { + testNodeDescription := &api.NodeDescription{ + Hostname: "testHostname", + Platform: &api.Platform{ + OS: "linux", + Architecture: "x86_64", + }, + } + client := NewStubAPIClient() - ctlr, err := newController(client, task, nil) + ctlr, err := newController(client, testNodeDescription, task, nil) assert.NoError(t, err) - config, err := newContainerConfig(task) + config, err := newContainerConfig(testNodeDescription, task) assert.NoError(t, err) assert.NotNil(t, config) diff --git a/agent/exec/dockerapi/executor.go b/agent/exec/dockerapi/executor.go index ec746443fe..6601ce224b 100644 --- a/agent/exec/dockerapi/executor.go +++ b/agent/exec/dockerapi/executor.go @@ -11,21 +11,25 @@ import ( "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/log" "golang.org/x/net/context" + "sync" ) type executor struct { client engineapi.APIClient secrets exec.SecretsManager genericResources []*api.GenericResource + mutex sync.Mutex // This mutex protects the following node field + node *api.NodeDescription } // NewExecutor returns an executor from the docker client. func NewExecutor(client engineapi.APIClient, genericResources []*api.GenericResource) exec.Executor { - return &executor{ + var executor = &executor{ client: client, secrets: secrets.NewManager(), genericResources: genericResources, } + return executor } // Describe returns the underlying node description from the docker client. @@ -111,6 +115,11 @@ func (e *executor) Describe(ctx context.Context) (*api.NodeDescription, error) { }, } + // Save the node information in the executor field + e.mutex.Lock() + e.node = description + e.mutex.Unlock() + return description, nil } @@ -120,7 +129,11 @@ func (e *executor) Configure(ctx context.Context, node *api.Node) error { // Controller returns a docker container controller. func (e *executor) Controller(t *api.Task) (exec.Controller, error) { - ctlr, err := newController(e.client, t, secrets.Restrict(e.secrets, t)) + // Get the node description from the executor field + e.mutex.Lock() + nodeDescription := e.node + e.mutex.Unlock() + ctlr, err := newController(e.client, nodeDescription, t, secrets.Restrict(e.secrets, t)) if err != nil { return nil, err } diff --git a/manager/controlapi/service.go b/manager/controlapi/service.go index d556b6c0e7..0a0a9ffa2a 100644 --- a/manager/controlapi/service.go +++ b/manager/controlapi/service.go @@ -128,7 +128,13 @@ func validateContainerSpec(taskSpec api.TaskSpec) error { // Building a empty/dummy Task to validate the templating and // the resulting container spec as well. This is a *best effort* // validation. - container, err := template.ExpandContainerSpec(&api.Task{ + container, err := template.ExpandContainerSpec(&api.NodeDescription{ + Hostname: "nodeHostname", + Platform: &api.Platform{ + OS: "os", + Architecture: "architecture", + }, + }, &api.Task{ Spec: taskSpec, ServiceID: "serviceid", Slot: 1, diff --git a/template/context.go b/template/context.go index d26e155be4..e3badef532 100644 --- a/template/context.go +++ b/template/context.go @@ -14,6 +14,12 @@ import ( "github.com/pkg/errors" ) +// Platform holds information about the underlying platform of the node +type Platform struct { + Architecture string + OS string +} + // Context defines the strict set of values that can be injected into a // template expression in SwarmKit data structure. // NOTE: Be very careful adding any fields to this structure with types @@ -27,7 +33,9 @@ type Context struct { } Node struct { - ID string + ID string + Hostname string + Platform Platform } Task struct { @@ -41,16 +49,25 @@ type Context struct { } } -// NewContextFromTask returns a new template context from the data available in -// task. The provided context can then be used to populate runtime values in a +// NewContext returns a new template context from the data available in the +// task and the node where it is scheduled to run. +// The provided context can then be used to populate runtime values in a // ContainerSpec. -func NewContextFromTask(t *api.Task) (ctx Context) { +func NewContext(n *api.NodeDescription, t *api.Task) (ctx Context) { ctx.Service.ID = t.ServiceID ctx.Service.Name = t.ServiceAnnotations.Name ctx.Service.Labels = t.ServiceAnnotations.Labels ctx.Node.ID = t.NodeID + // Add node information to context only if we have them available + if n != nil { + ctx.Node.Hostname = n.Hostname + ctx.Node.Platform = Platform{ + Architecture: n.Platform.Architecture, + OS: n.Platform.OS, + } + } ctx.Task.ID = t.ID ctx.Task.Name = naming.Task(t) @@ -157,12 +174,13 @@ func (ctx PayloadContext) envGetter(variable string) (string, error) { } // NewPayloadContextFromTask returns a new template context from the data -// available in the task. This context also provides access to the configs +// available in the task and the node where it is scheduled to run. +// This context also provides access to the configs // and secrets that the task has access to. The provided context can then // be used to populate runtime values in a templated config or secret. -func NewPayloadContextFromTask(t *api.Task, dependencies exec.DependencyGetter) (ctx PayloadContext) { +func NewPayloadContextFromTask(node *api.NodeDescription, t *api.Task, dependencies exec.DependencyGetter) (ctx PayloadContext) { return PayloadContext{ - Context: NewContextFromTask(t), + Context: NewContext(node, t), t: t, restrictedSecrets: secrets.Restrict(dependencies.Secrets(), t), restrictedConfigs: configs.Restrict(dependencies.Configs(), t), diff --git a/template/context_test.go b/template/context_test.go index 4aab3a1b0f..e760f34371 100644 --- a/template/context_test.go +++ b/template/context_test.go @@ -10,11 +10,12 @@ import ( func TestTemplateContext(t *testing.T) { for _, testcase := range []struct { - Test string - Task *api.Task - Context Context - Expected *api.ContainerSpec - Err error + Test string + Task *api.Task + Context Context + Expected *api.ContainerSpec + Err error + NodeDescription *api.NodeDescription }{ { Test: "Identity", @@ -35,6 +36,8 @@ func TestTemplateContext(t *testing.T) { }, } }), + NodeDescription: modifyNode(func(n *api.NodeDescription) { + }), Expected: &api.ContainerSpec{ Env: []string{ "NOTOUCH=dont", @@ -70,6 +73,8 @@ func TestTemplateContext(t *testing.T) { }, } }), + NodeDescription: modifyNode(func(n *api.NodeDescription) { + }), Expected: &api.ContainerSpec{ Labels: map[string]string{ "ContainerLabel": "should-NOT-end-up-as-task", @@ -106,6 +111,8 @@ func TestTemplateContext(t *testing.T) { }, } }), + NodeDescription: modifyNode(func(n *api.NodeDescription) { + }), Expected: &api.ContainerSpec{ Mounts: []api.Mount{ { @@ -130,13 +137,53 @@ func TestTemplateContext(t *testing.T) { }, } }), + NodeDescription: modifyNode(func(n *api.NodeDescription) { + }), Expected: &api.ContainerSpec{ Hostname: "myhost-10", }, }, + { + Test: "Node hostname", + Task: modifyTask(func(t *api.Task) { + t.Spec = api.TaskSpec{ + Runtime: &api.TaskSpec_Container{ + Container: &api.ContainerSpec{ + Hostname: "myservice-{{.Node.Hostname}}", + }, + }, + } + }), + NodeDescription: modifyNode(func(n *api.NodeDescription) { + n.Hostname = "mynode" + }), + Expected: &api.ContainerSpec{ + Hostname: "myservice-mynode", + }, + }, + { + Test: "Node architecture", + Task: modifyTask(func(t *api.Task) { + t.Spec = api.TaskSpec{ + Runtime: &api.TaskSpec_Container{ + Container: &api.ContainerSpec{ + Hostname: "{{.Node.Hostname}}-{{.Node.Platform.OS}}-{{.Node.Platform.Architecture}}", + }, + }, + } + }), + NodeDescription: modifyNode(func(n *api.NodeDescription) { + n.Hostname = "mynode" + n.Platform.Architecture = "myarchitecture" + n.Platform.OS = "myos" + }), + Expected: &api.ContainerSpec{ + Hostname: "mynode-myos-myarchitecture", + }, + }, } { t.Run(testcase.Test, func(t *testing.T) { - spec, err := ExpandContainerSpec(testcase.Task) + spec, err := ExpandContainerSpec(testcase.NodeDescription, testcase.Task) if err != nil { if testcase.Err == nil { t.Fatalf("unexpected error: %v", err) @@ -194,6 +241,22 @@ func modifyTask(fn func(t *api.Task)) *api.Task { return t } +// modifyNode generates a node with interesting values then calls the function +// with it. The caller can then modify the node and return the result. +func modifyNode(fn func(n *api.NodeDescription)) *api.NodeDescription { + n := &api.NodeDescription{ + Hostname: "nodeHostname", + Platform: &api.Platform{ + Architecture: "x86_64", + OS: "linux", + }, + } + + fn(n) + + return n +} + // visitAllTemplatedFields does just that. // TODO(stevvooe): Might be best to make this the actual implementation. func visitAllTemplatedFields(spec *api.ContainerSpec, fn func(value string)) { diff --git a/template/expand.go b/template/expand.go index e45c36252d..45ca97114e 100644 --- a/template/expand.go +++ b/template/expand.go @@ -10,18 +10,19 @@ import ( ) // ExpandContainerSpec expands templated fields in the runtime using the task -// state. Templating is all evaluated on the agent-side, before execution. +// state and the node where it is scheduled to run. +// Templating is all evaluated on the agent-side, before execution. // // Note that these are projected only on runtime values, since active task // values are typically manipulated in the manager. -func ExpandContainerSpec(t *api.Task) (*api.ContainerSpec, error) { +func ExpandContainerSpec(n *api.NodeDescription, t *api.Task) (*api.ContainerSpec, error) { container := t.Spec.GetContainer() if container == nil { return nil, errors.Errorf("task missing ContainerSpec to expand") } container = container.Copy() - ctx := NewContextFromTask(t) + ctx := NewContext(n, t) var err error container.Env, err = expandEnv(ctx, container.Env) @@ -128,12 +129,12 @@ func expandPayload(ctx PayloadContext, payload []byte) ([]byte, error) { // ExpandSecretSpec expands the template inside the secret payload, if any. // Templating is evaluated on the agent-side. -func ExpandSecretSpec(s *api.Secret, t *api.Task, dependencies exec.DependencyGetter) (*api.SecretSpec, error) { +func ExpandSecretSpec(s *api.Secret, node *api.NodeDescription, t *api.Task, dependencies exec.DependencyGetter) (*api.SecretSpec, error) { if s.Spec.Templating == nil { return &s.Spec, nil } if s.Spec.Templating.Name == "golang" { - ctx := NewPayloadContextFromTask(t, dependencies) + ctx := NewPayloadContextFromTask(node, t, dependencies) secretSpec := s.Spec.Copy() var err error @@ -145,12 +146,12 @@ func ExpandSecretSpec(s *api.Secret, t *api.Task, dependencies exec.DependencyGe // ExpandConfigSpec expands the template inside the config payload, if any. // Templating is evaluated on the agent-side. -func ExpandConfigSpec(c *api.Config, t *api.Task, dependencies exec.DependencyGetter) (*api.ConfigSpec, error) { +func ExpandConfigSpec(c *api.Config, node *api.NodeDescription, t *api.Task, dependencies exec.DependencyGetter) (*api.ConfigSpec, error) { if c.Spec.Templating == nil { return &c.Spec, nil } if c.Spec.Templating.Name == "golang" { - ctx := NewPayloadContextFromTask(t, dependencies) + ctx := NewPayloadContextFromTask(node, t, dependencies) configSpec := c.Spec.Copy() var err error diff --git a/template/getter.go b/template/getter.go index f06c438c25..05e5de72eb 100644 --- a/template/getter.go +++ b/template/getter.go @@ -9,11 +9,12 @@ import ( type templatedSecretGetter struct { dependencies exec.DependencyGetter t *api.Task + node *api.NodeDescription } // NewTemplatedSecretGetter returns a SecretGetter that evaluates templates. -func NewTemplatedSecretGetter(dependencies exec.DependencyGetter, t *api.Task) exec.SecretGetter { - return templatedSecretGetter{dependencies: dependencies, t: t} +func NewTemplatedSecretGetter(dependencies exec.DependencyGetter, t *api.Task, node *api.NodeDescription) exec.SecretGetter { + return templatedSecretGetter{dependencies: dependencies, t: t, node: node} } func (t templatedSecretGetter) Get(secretID string) (*api.Secret, error) { @@ -31,7 +32,7 @@ func (t templatedSecretGetter) Get(secretID string) (*api.Secret, error) { return secret, err } - newSpec, err := ExpandSecretSpec(secret, t.t, t.dependencies) + newSpec, err := ExpandSecretSpec(secret, t.node, t.t, t.dependencies) if err != nil { return secret, errors.Wrapf(err, "failed to expand templated secret %s", secretID) } @@ -44,11 +45,12 @@ func (t templatedSecretGetter) Get(secretID string) (*api.Secret, error) { type templatedConfigGetter struct { dependencies exec.DependencyGetter t *api.Task + node *api.NodeDescription } // NewTemplatedConfigGetter returns a ConfigGetter that evaluates templates. -func NewTemplatedConfigGetter(dependencies exec.DependencyGetter, t *api.Task) exec.ConfigGetter { - return templatedConfigGetter{dependencies: dependencies, t: t} +func NewTemplatedConfigGetter(dependencies exec.DependencyGetter, t *api.Task, node *api.NodeDescription) exec.ConfigGetter { + return templatedConfigGetter{dependencies: dependencies, t: t, node: node} } func (t templatedConfigGetter) Get(configID string) (*api.Config, error) { @@ -66,7 +68,7 @@ func (t templatedConfigGetter) Get(configID string) (*api.Config, error) { return config, err } - newSpec, err := ExpandConfigSpec(config, t.t, t.dependencies) + newSpec, err := ExpandConfigSpec(config, t.node, t.t, t.dependencies) if err != nil { return config, errors.Wrapf(err, "failed to expand templated config %s", configID) } @@ -82,10 +84,10 @@ type templatedDependencyGetter struct { } // NewTemplatedDependencyGetter returns a DependencyGetter that evaluates templates. -func NewTemplatedDependencyGetter(dependencies exec.DependencyGetter, t *api.Task) exec.DependencyGetter { +func NewTemplatedDependencyGetter(dependencies exec.DependencyGetter, t *api.Task, node *api.NodeDescription) exec.DependencyGetter { return templatedDependencyGetter{ - secrets: NewTemplatedSecretGetter(dependencies, t), - configs: NewTemplatedConfigGetter(dependencies, t), + secrets: NewTemplatedSecretGetter(dependencies, t, node), + configs: NewTemplatedConfigGetter(dependencies, t, node), } } diff --git a/template/getter_test.go b/template/getter_test.go index 88ea0570ec..a7b8d021f2 100644 --- a/template/getter_test.go +++ b/template/getter_test.go @@ -31,6 +31,7 @@ func TestTemplatedSecret(t *testing.T) { desc string secretSpec api.SecretSpec task *api.Task + node *api.NodeDescription expected string expectedErr string } @@ -43,14 +44,20 @@ func TestTemplatedSecret(t *testing.T) { "SERVICE_NAME={{.Service.Name}}\n" + "TASK_ID={{.Task.ID}}\n" + "TASK_NAME={{.Task.Name}}\n" + - "NODE_ID={{.Node.ID}}\n"), + "NODE_ID={{.Node.ID}}\n" + + "NODE_HOSTNAME={{.Node.Hostname}}\n" + + "NODE_OS={{.Node.Platform.OS}}\n" + + "NODE_ARCHITECTURE={{.Node.Platform.Architecture}}"), Templating: &api.Driver{Name: "golang"}, }, expected: "SERVICE_ID=serviceID\n" + "SERVICE_NAME=serviceName\n" + "TASK_ID=taskID\n" + "TASK_NAME=serviceName.10.taskID\n" + - "NODE_ID=nodeID\n", + "NODE_ID=nodeID\n" + + "NODE_HOSTNAME=myhostname\n" + + "NODE_OS=testOS\n" + + "NODE_ARCHITECTURE=testArchitecture", task: modifyTask(func(t *api.Task) { t.Spec = api.TaskSpec{ Runtime: &api.TaskSpec_Container{ @@ -65,6 +72,11 @@ func TestTemplatedSecret(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + n.Hostname = "myhostname" + n.Platform.OS = "testOS" + n.Platform.Architecture = "testArchitecture" + }), }, { desc: "Test expansion of secret, by target", @@ -99,6 +111,9 @@ func TestTemplatedSecret(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + // use default values + }), }, { desc: "Test expansion of config, by target", @@ -135,6 +150,9 @@ func TestTemplatedSecret(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + // use default values + }), }, { desc: "Test expansion of secret not available to task", @@ -157,6 +175,9 @@ func TestTemplatedSecret(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + // use default values + }), }, { desc: "Test expansion of config not available to task", @@ -179,6 +200,9 @@ func TestTemplatedSecret(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + // use default values + }), }, { desc: "Test that expansion of the same secret avoids recursion", @@ -209,6 +233,9 @@ func TestTemplatedSecret(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + // use default values + }), }, { desc: "Test env", @@ -234,6 +261,9 @@ func TestTemplatedSecret(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + // use default values + }), }, } @@ -244,7 +274,7 @@ func TestTemplatedSecret(t *testing.T) { dependencyManager.Secrets().Add(*templatedSecret, *referencedSecret) dependencyManager.Configs().Add(*referencedConfig) - templatedDependencies := NewTemplatedDependencyGetter(agent.Restrict(dependencyManager, testCase.task), testCase.task) + templatedDependencies := NewTemplatedDependencyGetter(agent.Restrict(dependencyManager, testCase.task), testCase.task, testCase.node) expandedSecret, err := templatedDependencies.Secrets().Get("templatedsecret") if testCase.expectedErr != "" { @@ -281,6 +311,7 @@ func TestTemplatedConfig(t *testing.T) { task *api.Task expected string expectedErr string + node *api.NodeDescription } testCases := []testCase{ @@ -291,14 +322,20 @@ func TestTemplatedConfig(t *testing.T) { "SERVICE_NAME={{.Service.Name}}\n" + "TASK_ID={{.Task.ID}}\n" + "TASK_NAME={{.Task.Name}}\n" + - "NODE_ID={{.Node.ID}}\n"), + "NODE_ID={{.Node.ID}}\n" + + "NODE_HOSTNAME={{.Node.Hostname}}\n" + + "NODE_OS={{.Node.Platform.OS}}\n" + + "NODE_ARCHITECTURE={{.Node.Platform.Architecture}}"), Templating: &api.Driver{Name: "golang"}, }, expected: "SERVICE_ID=serviceID\n" + "SERVICE_NAME=serviceName\n" + "TASK_ID=taskID\n" + "TASK_NAME=serviceName.10.taskID\n" + - "NODE_ID=nodeID\n", + "NODE_ID=nodeID\n" + + "NODE_HOSTNAME=myhostname\n" + + "NODE_OS=testOS\n" + + "NODE_ARCHITECTURE=testArchitecture", task: modifyTask(func(t *api.Task) { t.Spec = api.TaskSpec{ Runtime: &api.TaskSpec_Container{ @@ -313,6 +350,11 @@ func TestTemplatedConfig(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + n.Hostname = "myhostname" + n.Platform.OS = "testOS" + n.Platform.Architecture = "testArchitecture" + }), }, { desc: "Test expansion of secret, by target", @@ -349,6 +391,9 @@ func TestTemplatedConfig(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + // use default values + }), }, { desc: "Test expansion of config, by target", @@ -383,6 +428,9 @@ func TestTemplatedConfig(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + // use default values + }), }, { desc: "Test expansion of secret not available to task", @@ -405,6 +453,9 @@ func TestTemplatedConfig(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + // use default values + }), }, { desc: "Test expansion of config not available to task", @@ -427,6 +478,9 @@ func TestTemplatedConfig(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + // use default values + }), }, { desc: "Test that expansion of the same config avoids recursion", @@ -457,6 +511,9 @@ func TestTemplatedConfig(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + // use default values + }), }, { desc: "Test env", @@ -482,6 +539,9 @@ func TestTemplatedConfig(t *testing.T) { }, } }), + node: modifyNode(func(n *api.NodeDescription) { + // use default values + }), }, } @@ -492,7 +552,7 @@ func TestTemplatedConfig(t *testing.T) { dependencyManager.Configs().Add(*templatedConfig, *referencedConfig) dependencyManager.Secrets().Add(*referencedSecret) - templatedDependencies := NewTemplatedDependencyGetter(agent.Restrict(dependencyManager, testCase.task), testCase.task) + templatedDependencies := NewTemplatedDependencyGetter(agent.Restrict(dependencyManager, testCase.task), testCase.task, testCase.node) expandedConfig, err := templatedDependencies.Configs().Get("templatedconfig") if testCase.expectedErr != "" {