From 268bece1ab33bffdf52f741856c0bf8bc4c0f58c Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Wed, 21 Sep 2016 11:18:44 -0700 Subject: [PATCH 1/3] Vault defined at all levels --- jobspec/parse.go | 36 ++++++++++++++++ jobspec/parse_test.go | 48 +++++++++++++++++++++ jobspec/test-fixtures/vault_inheritance.hcl | 22 ++++++++++ 3 files changed, 106 insertions(+) create mode 100644 jobspec/test-fixtures/vault_inheritance.hcl diff --git a/jobspec/parse.go b/jobspec/parse.go index fa7d7b3ca..c81d30d5e 100644 --- a/jobspec/parse.go +++ b/jobspec/parse.go @@ -101,6 +101,7 @@ func parseJob(result *structs.Job, list *ast.ObjectList) error { delete(m, "meta") delete(m, "update") delete(m, "periodic") + delete(m, "vault") // Set the ID and name to the object key result.ID = obj.Keys[0].Token.Value().(string) @@ -139,6 +140,7 @@ func parseJob(result *structs.Job, list *ast.ObjectList) error { "meta", "task", "group", + "vault", "vault_token", } if err := checkHCLKeys(listVal, valid); err != nil { @@ -205,6 +207,23 @@ func parseJob(result *structs.Job, list *ast.ObjectList) error { } } + // If we have a vault block, then parse that + if o := listVal.Filter("vault"); len(o.Items) > 0 { + var jobVault structs.Vault + if err := parseVault(&jobVault, o); err != nil { + return multierror.Prefix(err, "vault ->") + } + + // Go through the task groups/tasks and if they don't have a Vault block, set it + for _, tg := range result.TaskGroups { + for _, task := range tg.Tasks { + if task.Vault == nil { + task.Vault = &jobVault + } + } + } + } + return nil } @@ -242,6 +261,7 @@ func parseGroups(result *structs.Job, list *ast.ObjectList) error { "meta", "task", "ephemeral_disk", + "vault", } if err := checkHCLKeys(listVal, valid); err != nil { return multierror.Prefix(err, fmt.Sprintf("'%s' ->", n)) @@ -256,6 +276,7 @@ func parseGroups(result *structs.Job, list *ast.ObjectList) error { delete(m, "task") delete(m, "restart") delete(m, "ephemeral_disk") + delete(m, "vault") // Default count to 1 if not specified if _, ok := m["count"]; !ok { @@ -312,6 +333,21 @@ func parseGroups(result *structs.Job, list *ast.ObjectList) error { } } + // If we have a vault block, then parse that + if o := listVal.Filter("vault"); len(o.Items) > 0 { + var tgVault structs.Vault + if err := parseVault(&tgVault, o); err != nil { + return multierror.Prefix(err, fmt.Sprintf("'%s', vault ->", n)) + } + + // Go through the tasks and if they don't have a Vault block, set it + for _, task := range g.Tasks { + if task.Vault == nil { + task.Vault = &tgVault + } + } + } + collection = append(collection, &g) } diff --git a/jobspec/parse_test.go b/jobspec/parse_test.go index 969976295..fa6bd320c 100644 --- a/jobspec/parse_test.go +++ b/jobspec/parse_test.go @@ -440,6 +440,54 @@ func TestParse(t *testing.T) { }, false, }, + { + "vault_inheritance.hcl", + &structs.Job{ + ID: "example", + Name: "example", + Type: "service", + Priority: 50, + Region: "global", + TaskGroups: []*structs.TaskGroup{ + &structs.TaskGroup{ + Name: "cache", + Count: 1, + LocalDisk: structs.DefaultLocalDisk(), + Tasks: []*structs.Task{ + &structs.Task{ + Name: "redis", + LogConfig: structs.DefaultLogConfig(), + Vault: &structs.Vault{ + Policies: []string{"group"}, + }, + }, + &structs.Task{ + Name: "redis2", + LogConfig: structs.DefaultLogConfig(), + Vault: &structs.Vault{ + Policies: []string{"task"}, + }, + }, + }, + }, + &structs.TaskGroup{ + Name: "cache2", + Count: 1, + LocalDisk: structs.DefaultLocalDisk(), + Tasks: []*structs.Task{ + &structs.Task{ + Name: "redis", + LogConfig: structs.DefaultLogConfig(), + Vault: &structs.Vault{ + Policies: []string{"job"}, + }, + }, + }, + }, + }, + }, + false, + }, } for _, tc := range cases { diff --git a/jobspec/test-fixtures/vault_inheritance.hcl b/jobspec/test-fixtures/vault_inheritance.hcl new file mode 100644 index 000000000..b45e2d38e --- /dev/null +++ b/jobspec/test-fixtures/vault_inheritance.hcl @@ -0,0 +1,22 @@ +job "example" { + vault { + policies = ["job"] + } + group "cache" { + vault { + policies = ["group"] + } + + task "redis" { } + + task "redis2" { + vault { + policies = ["task"] + env = false + } + } + } + group "cache2" { + task "redis" { } + } +} From ee676308898100334176b690017e0c8c668c25a4 Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Tue, 20 Sep 2016 13:22:29 -0700 Subject: [PATCH 2/3] Struct and parse --- client/driver/driver.go | 5 +++-- jobspec/parse.go | 6 ++++++ jobspec/parse_test.go | 4 ++++ nomad/structs/structs.go | 4 ++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/client/driver/driver.go b/client/driver/driver.go index ac152a508..ab31c5f8a 100644 --- a/client/driver/driver.go +++ b/client/driver/driver.go @@ -166,8 +166,9 @@ func GetTaskEnv(allocDir *allocdir.AllocDir, node *structs.Node, env.SetAlloc(alloc) } - // TODO: make this conditional on the task's vault block allowing it - env.SetVaultToken(vaultToken, true) + if task.Vault != nil { + env.SetVaultToken(vaultToken, task.Vault.Env) + } return env.Build(), nil } diff --git a/jobspec/parse.go b/jobspec/parse.go index c81d30d5e..90a678e3d 100644 --- a/jobspec/parse.go +++ b/jobspec/parse.go @@ -1126,6 +1126,7 @@ func parseVault(result *structs.Vault, list *ast.ObjectList) error { // Check for invalid keys valid := []string{ "policies", + "env", } if err := checkHCLKeys(listVal, valid); err != nil { return multierror.Prefix(err, "vault ->") @@ -1136,6 +1137,11 @@ func parseVault(result *structs.Vault, list *ast.ObjectList) error { return err } + // Default the env bool + if _, ok := m["env"]; !ok { + m["env"] = true + } + if err := mapstructure.WeakDecode(m, result); err != nil { return err } diff --git a/jobspec/parse_test.go b/jobspec/parse_test.go index fa6bd320c..1831366b6 100644 --- a/jobspec/parse_test.go +++ b/jobspec/parse_test.go @@ -160,6 +160,7 @@ func TestParse(t *testing.T) { }, Vault: &structs.Vault{ Policies: []string{"foo", "bar"}, + Env: true, }, }, &structs.Task{ @@ -459,6 +460,7 @@ func TestParse(t *testing.T) { LogConfig: structs.DefaultLogConfig(), Vault: &structs.Vault{ Policies: []string{"group"}, + Env: true, }, }, &structs.Task{ @@ -466,6 +468,7 @@ func TestParse(t *testing.T) { LogConfig: structs.DefaultLogConfig(), Vault: &structs.Vault{ Policies: []string{"task"}, + Env: false, }, }, }, @@ -480,6 +483,7 @@ func TestParse(t *testing.T) { LogConfig: structs.DefaultLogConfig(), Vault: &structs.Vault{ Policies: []string{"job"}, + Env: true, }, }, }, diff --git a/nomad/structs/structs.go b/nomad/structs/structs.go index 75c43c14f..503000e55 100644 --- a/nomad/structs/structs.go +++ b/nomad/structs/structs.go @@ -2630,6 +2630,10 @@ func (d *EphemeralDisk) Copy() *EphemeralDisk { type Vault struct { // Policies is the set of policies that the task needs access to Policies []string + + // Env marks whether the Vault Token should be exposed as an environment + // variable + Env bool } // Copy returns a copy of this Vault block. From c3fb00cf6a6a69e0ea8656b8e2bead784ee9a2fc Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Wed, 21 Sep 2016 11:29:50 -0700 Subject: [PATCH 3/3] tasks updated --- scheduler/util.go | 3 +++ scheduler/util_test.go | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/scheduler/util.go b/scheduler/util.go index 9a7099987..e3e790fa6 100644 --- a/scheduler/util.go +++ b/scheduler/util.go @@ -359,6 +359,9 @@ func tasksUpdated(a, b *structs.TaskGroup) bool { if !reflect.DeepEqual(at.Artifacts, bt.Artifacts) { return true } + if !reflect.DeepEqual(at.Vault, bt.Vault) { + return true + } // Inspect the network to see if the dynamic ports are different if len(at.Resources.Networks) != len(bt.Resources.Networks) { diff --git a/scheduler/util_test.go b/scheduler/util_test.go index b9a1109d2..0c6179d28 100644 --- a/scheduler/util_test.go +++ b/scheduler/util_test.go @@ -540,6 +540,12 @@ func TestTasksUpdated(t *testing.T) { if !tasksUpdated(j1.TaskGroups[0], j14.TaskGroups[0]) { t.Fatalf("bad") } + + j15 := mock.Job() + j15.TaskGroups[0].Tasks[0].Vault = &structs.Vault{Policies: []string{"foo"}} + if !tasksUpdated(j1.TaskGroups[0], j15.TaskGroups[0]) { + t.Fatalf("bad") + } } func TestEvictAndPlace_LimitLessThanAllocs(t *testing.T) {