mirror of
https://github.com/kemko/nomad.git
synced 2026-01-01 16:05:42 +03:00
cli: ensure HCL env vars are added to the job submission object. (#18832)
This commit is contained in:
3
.changelog/18832.txt
Normal file
3
.changelog/18832.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
```release-note:bug
|
||||||
|
cli: ensure HCL env vars are added to the job submission object in the `job run` command
|
||||||
|
```
|
||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"maps"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -534,6 +535,10 @@ func (j *JobGetter) Get(jpath string) (*api.JobSubmission, *api.Job, error) {
|
|||||||
return nil, nil, fmt.Errorf("Failed to parse HCL job: %w", err)
|
return nil, nil, fmt.Errorf("Failed to parse HCL job: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Perform the environment listing here as it is used twice beyond this
|
||||||
|
// point.
|
||||||
|
osEnv := os.Environ()
|
||||||
|
|
||||||
// we are parsing HCL2, whether from a file or stdio
|
// we are parsing HCL2, whether from a file or stdio
|
||||||
jobStruct, err = jobspec2.ParseWithConfig(&jobspec2.ParseConfig{
|
jobStruct, err = jobspec2.ParseWithConfig(&jobspec2.ParseConfig{
|
||||||
Path: pathName,
|
Path: pathName,
|
||||||
@@ -541,7 +546,7 @@ func (j *JobGetter) Get(jpath string) (*api.JobSubmission, *api.Job, error) {
|
|||||||
ArgVars: j.Vars,
|
ArgVars: j.Vars,
|
||||||
AllowFS: true,
|
AllowFS: true,
|
||||||
VarFiles: j.VarFiles,
|
VarFiles: j.VarFiles,
|
||||||
Envs: os.Environ(),
|
Envs: osEnv,
|
||||||
Strict: j.Strict,
|
Strict: j.Strict,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -549,15 +554,24 @@ func (j *JobGetter) Get(jpath string) (*api.JobSubmission, *api.Job, error) {
|
|||||||
var readVarFileErr error
|
var readVarFileErr error
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// combine any -var-file data into one big blob
|
// combine any -var-file data into one big blob
|
||||||
varFileCat, readVarFileErr = extractVarFiles([]string(j.VarFiles))
|
varFileCat, readVarFileErr = extractVarFiles(j.VarFiles)
|
||||||
if readVarFileErr != nil {
|
if readVarFileErr != nil {
|
||||||
return nil, nil, fmt.Errorf("Failed to read var file(s): %w", readVarFileErr)
|
return nil, nil, fmt.Errorf("Failed to read var file(s): %w", readVarFileErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract variables declared by the -var flag and as environment
|
||||||
|
// variables.
|
||||||
|
extractedVarFlags := extractVarFlags(j.Vars)
|
||||||
|
extractedEnvVars := extractJobSpecEnvVars(osEnv)
|
||||||
|
|
||||||
|
// Merge the two maps ensuring that variables defined by -var flags
|
||||||
|
// take precedence.
|
||||||
|
maps.Copy(extractedEnvVars, extractedVarFlags)
|
||||||
|
|
||||||
// submit the job with the submission with content from -var flags
|
// submit the job with the submission with content from -var flags
|
||||||
jobSubmission = &api.JobSubmission{
|
jobSubmission = &api.JobSubmission{
|
||||||
VariableFlags: extractVarFlags(j.Vars),
|
VariableFlags: extractedEnvVars,
|
||||||
Variables: varFileCat,
|
Variables: varFileCat,
|
||||||
Source: source.String(),
|
Source: source.String(),
|
||||||
Format: formatHCL2,
|
Format: formatHCL2,
|
||||||
@@ -606,6 +620,36 @@ func extractVarFlags(slice []string) map[string]string {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extractJobSpecEnvVars is used to extract Nomad specific HCL variables from
|
||||||
|
// the OS environment. The input envVars parameter is expected to be generated
|
||||||
|
// from the os.Environment function call. The result is never nil for
|
||||||
|
// convenience.
|
||||||
|
func extractJobSpecEnvVars(envVars []string) map[string]string {
|
||||||
|
|
||||||
|
m := make(map[string]string)
|
||||||
|
|
||||||
|
for _, raw := range envVars {
|
||||||
|
if !strings.HasPrefix(raw, jobspec2.VarEnvPrefix) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim the prefix, so we just have the raw key=value variable
|
||||||
|
// remaining.
|
||||||
|
raw = raw[len(jobspec2.VarEnvPrefix):]
|
||||||
|
|
||||||
|
// Identify the index of the equals sign which is where we split the
|
||||||
|
// variable k/v pair. -1 indicates the equals sign is not found and
|
||||||
|
// therefore the var is not valid.
|
||||||
|
if eq := strings.Index(raw, "="); eq == -1 {
|
||||||
|
continue
|
||||||
|
} else if raw[:eq] != "" {
|
||||||
|
m[raw[:eq]] = raw[eq+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
// mergeAutocompleteFlags is used to join multiple flag completion sets.
|
// mergeAutocompleteFlags is used to join multiple flag completion sets.
|
||||||
func mergeAutocompleteFlags(flags ...complete.Flags) complete.Flags {
|
func mergeAutocompleteFlags(flags ...complete.Flags) complete.Flags {
|
||||||
merged := make(map[string]complete.Predictor, len(flags))
|
merged := make(map[string]complete.Predictor, len(flags))
|
||||||
|
|||||||
@@ -685,3 +685,51 @@ func Test_extractVarFlags(t *testing.T) {
|
|||||||
}, result)
|
}, result)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_extractJobSpecEnvVars(t *testing.T) {
|
||||||
|
ci.Parallel(t)
|
||||||
|
|
||||||
|
t.Run("nil", func(t *testing.T) {
|
||||||
|
must.MapEmpty(t, extractJobSpecEnvVars(nil))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("complete", func(t *testing.T) {
|
||||||
|
result := extractJobSpecEnvVars([]string{
|
||||||
|
"NOMAD_VAR_count=13",
|
||||||
|
"GOPATH=/Users/jrasell/go",
|
||||||
|
"NOMAD_VAR_image=redis:7",
|
||||||
|
})
|
||||||
|
must.Eq(t, map[string]string{
|
||||||
|
"count": "13",
|
||||||
|
"image": "redis:7",
|
||||||
|
}, result)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("whitespace", func(t *testing.T) {
|
||||||
|
result := extractJobSpecEnvVars([]string{
|
||||||
|
"NOMAD_VAR_count = 13",
|
||||||
|
"GOPATH = /Users/jrasell/go",
|
||||||
|
})
|
||||||
|
must.Eq(t, map[string]string{
|
||||||
|
"count ": " 13",
|
||||||
|
}, result)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("empty key", func(t *testing.T) {
|
||||||
|
result := extractJobSpecEnvVars([]string{
|
||||||
|
"NOMAD_VAR_=13",
|
||||||
|
"=/Users/jrasell/go",
|
||||||
|
})
|
||||||
|
must.Eq(t, map[string]string{}, result)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("empty value", func(t *testing.T) {
|
||||||
|
result := extractJobSpecEnvVars([]string{
|
||||||
|
"NOMAD_VAR_count=",
|
||||||
|
"GOPATH=",
|
||||||
|
})
|
||||||
|
must.Eq(t, map[string]string{
|
||||||
|
"count": "",
|
||||||
|
}, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user