Skip to content

Commit

Permalink
Added a -hcl2-strict flag to allow for lenient hcl variable parsing. (
Browse files Browse the repository at this point in the history
#11284)

Co-authored-by: James Rasell <jrasell@hashicorp.com>
  • Loading branch information
apollo13 and jrasell committed Nov 4, 2021
1 parent 166b0cf commit b52f42d
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 18 deletions.
3 changes: 3 additions & 0 deletions .changelog/11284.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
cli: added `hcl2-strict` flag to control HCL2 parsing errors where variable passed without root
```
6 changes: 3 additions & 3 deletions command/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,10 @@ type JobGetter struct {

// ApiJob returns the Job struct from jobfile.
func (j *JobGetter) ApiJob(jpath string) (*api.Job, error) {
return j.ApiJobWithArgs(jpath, nil, nil)
return j.ApiJobWithArgs(jpath, nil, nil, true)
}

func (j *JobGetter) ApiJobWithArgs(jpath string, vars []string, varfiles []string) (*api.Job, error) {
func (j *JobGetter) ApiJobWithArgs(jpath string, vars []string, varfiles []string, strict bool) (*api.Job, error) {
var jobfile io.Reader
pathName := filepath.Base(jpath)
switch jpath {
Expand Down Expand Up @@ -459,7 +459,7 @@ func (j *JobGetter) ApiJobWithArgs(jpath string, vars []string, varfiles []strin
AllowFS: true,
VarFiles: varfiles,
Envs: os.Environ(),
Strict: true,
Strict: strict,
})

if err != nil {
Expand Down
53 changes: 52 additions & 1 deletion command/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,58 @@ job "example" {
_, err = vf.WriteString(fileVars + "\n")
require.NoError(t, err)

j, err := (&JobGetter{}).ApiJobWithArgs(hclf.Name(), cliArgs, []string{vf.Name()})
j, err := (&JobGetter{}).ApiJobWithArgs(hclf.Name(), cliArgs, []string{vf.Name()}, true)
require.NoError(t, err)

require.NotNil(t, j)
require.Equal(t, expected, j.Datacenters)
}

func TestJobGetter_HCL2_Variables_StrictFalse(t *testing.T) {
t.Parallel()

hcl := `
variables {
var1 = "default-val"
var2 = "default-val"
var3 = "default-val"
var4 = "default-val"
}
job "example" {
datacenters = ["${var.var1}", "${var.var2}", "${var.var3}", "${var.var4}"]
}
`

os.Setenv("NOMAD_VAR_var4", "from-envvar")
defer os.Unsetenv("NOMAD_VAR_var4")

// Both the CLI and var file contain variables that are not used with the
// template and therefore would error, if hcl2-strict was true.
cliArgs := []string{`var2=from-cli`,`unsedVar1=from-cli`}
fileVars := `
var3 = "from-varfile"
unsedVar2 = "from-varfile"
`
expected := []string{"default-val", "from-cli", "from-varfile", "from-envvar"}

hclf, err := ioutil.TempFile("", "hcl")
require.NoError(t, err)
defer os.Remove(hclf.Name())
defer hclf.Close()

_, err = hclf.WriteString(hcl)
require.NoError(t, err)

vf, err := ioutil.TempFile("", "var.hcl")
require.NoError(t, err)
defer os.Remove(vf.Name())
defer vf.Close()

_, err = vf.WriteString(fileVars + "\n")
require.NoError(t, err)

j, err := (&JobGetter{}).ApiJobWithArgs(hclf.Name(), cliArgs, []string{vf.Name()}, false)
require.NoError(t, err)

require.NotNil(t, j)
Expand Down
11 changes: 9 additions & 2 deletions command/job_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ Plan Options:
-hcl1
Parses the job file as HCLv1.
-hcl2-strict
Whether an error should be produced from the HCL2 parser where a variable
has been supplied which is not defined within the root variables. Defaults
to true.
-policy-override
Sets the flag to force override any soft mandatory Sentinel policies.
Expand All @@ -105,6 +110,7 @@ func (c *JobPlanCommand) AutocompleteFlags() complete.Flags {
"-policy-override": complete.PredictNothing,
"-verbose": complete.PredictNothing,
"-hcl1": complete.PredictNothing,
"-hcl2-strict": complete.PredictNothing,
"-var": complete.PredictAnything,
"-var-file": complete.PredictFiles("*.var"),
})
Expand All @@ -116,7 +122,7 @@ func (c *JobPlanCommand) AutocompleteArgs() complete.Predictor {

func (c *JobPlanCommand) Name() string { return "job plan" }
func (c *JobPlanCommand) Run(args []string) int {
var diff, policyOverride, verbose bool
var diff, policyOverride, verbose, hcl2Strict bool
var varArgs, varFiles flaghelper.StringFlag

flagSet := c.Meta.FlagSet(c.Name(), FlagSetClient)
Expand All @@ -125,6 +131,7 @@ func (c *JobPlanCommand) Run(args []string) int {
flagSet.BoolVar(&policyOverride, "policy-override", false, "")
flagSet.BoolVar(&verbose, "verbose", false, "")
flagSet.BoolVar(&c.JobGetter.hcl1, "hcl1", false, "")
flagSet.BoolVar(&hcl2Strict, "hcl2-strict", true, "")
flagSet.Var(&varArgs, "var", "")
flagSet.Var(&varFiles, "var-file", "")

Expand All @@ -142,7 +149,7 @@ func (c *JobPlanCommand) Run(args []string) int {

path := args[0]
// Get Job struct from Jobfile
job, err := c.JobGetter.ApiJobWithArgs(args[0], varArgs, varFiles)
job, err := c.JobGetter.ApiJobWithArgs(args[0], varArgs, varFiles, hcl2Strict)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error getting job struct: %s", err))
return 255
Expand Down
11 changes: 9 additions & 2 deletions command/job_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ Run Options:
-hcl1
Parses the job file as HCLv1.
-hcl2-strict
Whether an error should be produced from the HCL2 parser where a variable
has been supplied which is not defined within the root variables. Defaults
to true.
-output
Output the JSON that would be submitted to the HTTP API without submitting
the job.
Expand Down Expand Up @@ -144,6 +149,7 @@ func (c *JobRunCommand) AutocompleteFlags() complete.Flags {
"-policy-override": complete.PredictNothing,
"-preserve-counts": complete.PredictNothing,
"-hcl1": complete.PredictNothing,
"-hcl2-strict": complete.PredictNothing,
"-var": complete.PredictAnything,
"-var-file": complete.PredictFiles("*.var"),
})
Expand All @@ -156,7 +162,7 @@ func (c *JobRunCommand) AutocompleteArgs() complete.Predictor {
func (c *JobRunCommand) Name() string { return "job run" }

func (c *JobRunCommand) Run(args []string) int {
var detach, verbose, output, override, preserveCounts bool
var detach, verbose, output, override, preserveCounts, hcl2Strict bool
var checkIndexStr, consulToken, consulNamespace, vaultToken, vaultNamespace string
var varArgs, varFiles flaghelper.StringFlag

Expand All @@ -168,6 +174,7 @@ func (c *JobRunCommand) Run(args []string) int {
flagSet.BoolVar(&override, "policy-override", false, "")
flagSet.BoolVar(&preserveCounts, "preserve-counts", false, "")
flagSet.BoolVar(&c.JobGetter.hcl1, "hcl1", false, "")
flagSet.BoolVar(&hcl2Strict, "hcl2-strict", true, "")
flagSet.StringVar(&checkIndexStr, "check-index", "", "")
flagSet.StringVar(&consulToken, "consul-token", "", "")
flagSet.StringVar(&consulNamespace, "consul-namespace", "", "")
Expand Down Expand Up @@ -195,7 +202,7 @@ func (c *JobRunCommand) Run(args []string) int {
}

// Get Job struct from Jobfile
job, err := c.JobGetter.ApiJobWithArgs(args[0], varArgs, varFiles)
job, err := c.JobGetter.ApiJobWithArgs(args[0], varArgs, varFiles, hcl2Strict)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error getting job struct: %s", err))
return 1
Expand Down
17 changes: 12 additions & 5 deletions command/job_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,16 @@ Validate Options:
-hcl1
Parses the job file as HCLv1.
-hcl2-strict
Whether an error should be produced from the HCL2 parser where a variable
has been supplied which is not defined within the root variables. Defaults
to true.
-var 'key=value'
Variable for template, can be used multiple times.
-var-file=path
Path to HCL2 file containing user variables.
`
return strings.TrimSpace(helpText)
}
Expand All @@ -53,9 +57,10 @@ func (c *JobValidateCommand) Synopsis() string {

func (c *JobValidateCommand) AutocompleteFlags() complete.Flags {
return complete.Flags{
"-hcl1": complete.PredictNothing,
"-var": complete.PredictAnything,
"-var-file": complete.PredictFiles("*.var"),
"-hcl1": complete.PredictNothing,
"-hcl2-strict": complete.PredictNothing,
"-var": complete.PredictAnything,
"-var-file": complete.PredictFiles("*.var"),
}
}

Expand All @@ -67,10 +72,12 @@ func (c *JobValidateCommand) Name() string { return "job validate" }

func (c *JobValidateCommand) Run(args []string) int {
var varArgs, varFiles flaghelper.StringFlag
var hcl2Strict bool

flagSet := c.Meta.FlagSet(c.Name(), FlagSetNone)
flagSet.Usage = func() { c.Ui.Output(c.Help()) }
flagSet.BoolVar(&c.JobGetter.hcl1, "hcl1", false, "")
flagSet.BoolVar(&hcl2Strict, "hcl2-strict", true, "")
flagSet.Var(&varArgs, "var", "")
flagSet.Var(&varFiles, "var-file", "")

Expand All @@ -87,7 +94,7 @@ func (c *JobValidateCommand) Run(args []string) int {
}

// Get Job struct from Jobfile
job, err := c.JobGetter.ApiJobWithArgs(args[0], varArgs, varFiles)
job, err := c.JobGetter.ApiJobWithArgs(args[0], varArgs, varFiles, hcl2Strict)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error getting job struct: %s", err))
return 1
Expand Down
8 changes: 8 additions & 0 deletions website/content/docs/commands/job/plan.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ capability for the job's namespace.

- `-hcl1`: If set, HCL1 parser is used for parsing the job spec.

- `-hcl2-strict`: Whether an error should be produced from the HCL2 parser where
a variable has been supplied which is not defined within the root variables.
Defaults to true.

- `-var=<key=value>`: Variable for template, can be used multiple times.

- `-var-file=<path>`: Path to HCL2 file containing user variables.

- `-verbose`: Increase diff verbosity.

## Examples
Expand Down
14 changes: 9 additions & 5 deletions website/content/docs/commands/job/run.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ downloaded and read from URL specified. Nomad downloads the job file using

By default, on successful job submission the run command will enter an
interactive monitor and display log information detailing the scheduling
decisions, placement information, and [deployment status] for the provided job
if applicable ([`batch`] and [`system`] jobs don't create deployments). The monitor will
decisions, placement information, and [deployment status] for the provided job
if applicable ([`batch`] and [`system`] jobs don't create deployments). The monitor will
exit after scheduling and deployment have finished or failed.

On successful job submission and scheduling, exit code 0 will be returned. If
Expand Down Expand Up @@ -72,6 +72,10 @@ that volume.

- `-hcl1`: If set, HCL1 parser is used for parsing the job spec.

- `-hcl2-strict`: Whether an error should be produced from the HCL2 parser where
a variable has been supplied which is not defined within the root variables.
Defaults to true.

- `-output`: Output the JSON that would be submitted to the HTTP API without
submitting the job.

Expand Down Expand Up @@ -133,7 +137,7 @@ $ nomad job run job1.nomad
Deployed
Task Group Desired Placed Healthy Unhealthy Progress Deadline
cache 2 2 1 0 2021-06-09T15:32:58-07:00
cache 2 2 1 0 2021-06-09T15:32:58-07:00
web 1 1 1 0 2021-06-09T15:32:58-07:00
```

Expand All @@ -154,7 +158,7 @@ $ nomad job run -check-index 6 example.nomad
==> 2021-06-09T16:57:30-07:00: Evaluation "5ef16dff" finished with status "complete"
==> 2021-06-09T16:57:30-07:00: Monitoring deployment "62eb607c"
✓ Deployment "62eb607c" successful
2021-06-09T16:57:30-07:00
ID = 62eb607c
Job ID = example
Expand Down Expand Up @@ -218,7 +222,7 @@ $ nomad job run example.nomad
```

[`go-getter`]: https://github.com/hashicorp/go-getter
[deployment status]: /docs/commands/deployment#status
[deployment status]: /docs/commands/deployment#status
[`batch`]: /docs/schedulers#batch
[`system`]: /docs/schedulers#system
[`job plan` command]: /docs/commands/job/plan
Expand Down
12 changes: 12 additions & 0 deletions website/content/docs/commands/job/validate.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ of 1 indicates an error.
When ACLs are enabled, this command requires a token with the `read-job`
capability for the job's namespace.

## Validate Options

- `-hcl1`: If set, HCL1 parser is used for parsing the job spec.

- `-hcl2-strict`: Whether an error should be produced from the HCL2 parser where
a variable has been supplied which is not defined within the root variables.
Defaults to true.

- `-var=<key=value>`: Variable for template, can be used multiple times.

- `-var-file=<path>`: Path to HCL2 file containing user variables.

## Examples

Validate a job with invalid syntax:
Expand Down

0 comments on commit b52f42d

Please sign in to comment.