mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
adds implied secrets constraint to job hook (#26328)
This commit is contained in:
@@ -279,6 +279,8 @@ func (jobImpliedConstraints) Mutate(j *structs.Job) (*structs.Job, []error, erro
|
||||
|
||||
taskScheduleTaskGroups := j.RequiredScheduleTask()
|
||||
|
||||
secretBlocks := j.Secrets()
|
||||
|
||||
// Hot path where none of our things require constraints.
|
||||
//
|
||||
// [UPDATE THIS] if you are adding a new constraint thing!
|
||||
@@ -286,7 +288,8 @@ func (jobImpliedConstraints) Mutate(j *structs.Job) (*structs.Job, []error, erro
|
||||
nativeServiceDisco.Empty() && len(consulServiceDisco) == 0 &&
|
||||
numaTaskGroups.Empty() && bridgeNetworkingTaskGroups.Empty() &&
|
||||
transparentProxyTaskGroups.Empty() &&
|
||||
taskScheduleTaskGroups.Empty() {
|
||||
taskScheduleTaskGroups.Empty() &&
|
||||
len(secretBlocks) == 0 {
|
||||
return j, nil, nil
|
||||
}
|
||||
|
||||
@@ -302,6 +305,12 @@ func (jobImpliedConstraints) Mutate(j *structs.Job) (*structs.Job, []error, erro
|
||||
mutateConstraint(constraintMatcherLeft, tg, vaultConstraintFn(vaultBlock))
|
||||
}
|
||||
|
||||
for _, secretProviders := range secretBlocks {
|
||||
for _, provider := range secretProviders {
|
||||
mutateConstraint(constraintMatcherLeft, tg, secretsConstraintFn(provider))
|
||||
}
|
||||
}
|
||||
|
||||
// If the task group utilizes NUMA resources, run the mutator.
|
||||
if numaTaskGroups.Contains(tg.Name) {
|
||||
mutateConstraint(constraintMatcherFull, tg, numaVersionConstraint)
|
||||
@@ -382,6 +391,17 @@ func vaultConstraintFn(vault *structs.Vault) *structs.Constraint {
|
||||
return vaultConstraint
|
||||
}
|
||||
|
||||
// secretsConstraintFn returns a constraint that checks for the existence of a
|
||||
// fingerprinted secrets plugin. This is to support upgrades to 1.11 where a nomad
|
||||
// server follower may not be upgraded yet and attempt to place a job on a client
|
||||
// that has not been upgraded. This should be removed in Nomad 1.14.
|
||||
func secretsConstraintFn(provider string) *structs.Constraint {
|
||||
return &structs.Constraint{
|
||||
LTarget: fmt.Sprintf("${attr.plugins.secrets.%s.version}", provider),
|
||||
Operand: structs.ConstraintAttributeIsSet,
|
||||
}
|
||||
}
|
||||
|
||||
// consulConstraintFn returns a service discovery constraint that matches the
|
||||
// fingerprint of the requested Consul cluster. This is to support Nomad
|
||||
// Enterprise but neither the fingerprint or non-default cluster are allowed
|
||||
|
||||
@@ -1280,6 +1280,122 @@ func Test_jobImpliedConstraints_Mutate(t *testing.T) {
|
||||
expectedOutputWarnings: nil,
|
||||
expectedOutputError: nil,
|
||||
},
|
||||
{
|
||||
name: "task with secret",
|
||||
inputJob: &structs.Job{
|
||||
Name: "example",
|
||||
TaskGroups: []*structs.TaskGroup{
|
||||
{
|
||||
Name: "group-with-secret",
|
||||
Tasks: []*structs.Task{
|
||||
{
|
||||
Name: "task-with-secret",
|
||||
Secrets: []*structs.Secret{
|
||||
{
|
||||
Provider: "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedOutputJob: &structs.Job{
|
||||
Name: "example",
|
||||
TaskGroups: []*structs.TaskGroup{
|
||||
{
|
||||
Name: "group-with-secret",
|
||||
Tasks: []*structs.Task{
|
||||
{
|
||||
Name: "task-with-secret",
|
||||
Secrets: []*structs.Secret{
|
||||
{
|
||||
Provider: "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Constraints: []*structs.Constraint{
|
||||
{
|
||||
LTarget: "${attr.plugins.secrets.test.version}",
|
||||
Operand: structs.ConstraintAttributeIsSet,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "tasks with overlapping secrets",
|
||||
inputJob: &structs.Job{
|
||||
Name: "example",
|
||||
TaskGroups: []*structs.TaskGroup{
|
||||
{
|
||||
Name: "group-with-secret",
|
||||
Tasks: []*structs.Task{
|
||||
{
|
||||
Name: "task-with-secret",
|
||||
Secrets: []*structs.Secret{
|
||||
{
|
||||
Provider: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "task-with-secret",
|
||||
Secrets: []*structs.Secret{
|
||||
{
|
||||
Provider: "foo",
|
||||
},
|
||||
{
|
||||
Provider: "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedOutputJob: &structs.Job{
|
||||
Name: "example",
|
||||
TaskGroups: []*structs.TaskGroup{
|
||||
{
|
||||
Name: "group-with-secret",
|
||||
Tasks: []*structs.Task{
|
||||
{
|
||||
Name: "task-with-secret",
|
||||
Secrets: []*structs.Secret{
|
||||
{
|
||||
Provider: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "task-with-secret",
|
||||
Secrets: []*structs.Secret{
|
||||
{
|
||||
Provider: "foo",
|
||||
},
|
||||
{
|
||||
Provider: "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Constraints: []*structs.Constraint{
|
||||
{
|
||||
LTarget: "${attr.plugins.secrets.foo.version}",
|
||||
Operand: structs.ConstraintAttributeIsSet,
|
||||
},
|
||||
{
|
||||
LTarget: "${attr.plugins.secrets.bar.version}",
|
||||
Operand: structs.ConstraintAttributeIsSet,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
||||
@@ -5096,6 +5096,33 @@ func (j *Job) Vault() map[string]map[string]*Vault {
|
||||
return blocks
|
||||
}
|
||||
|
||||
// Secrets returns the set of secrets per task group, per task
|
||||
func (j *Job) Secrets() map[string][]string {
|
||||
blocks := make(map[string][]string, len(j.TaskGroups))
|
||||
|
||||
for _, tg := range j.TaskGroups {
|
||||
secrets := []string{}
|
||||
|
||||
for _, task := range tg.Tasks {
|
||||
if len(task.Secrets) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, s := range task.Secrets {
|
||||
if !slices.Contains(secrets, s.Provider) {
|
||||
secrets = append(secrets, s.Provider)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(secrets) != 0 {
|
||||
blocks[tg.Name] = secrets
|
||||
}
|
||||
}
|
||||
|
||||
return blocks
|
||||
}
|
||||
|
||||
// ConnectTasks returns the set of Consul Connect enabled tasks defined on the
|
||||
// job that will require a Service Identity token in the case that Consul ACLs
|
||||
// are enabled. The TaskKind.Value is the name of the Consul service.
|
||||
|
||||
Reference in New Issue
Block a user