cli: use HCLv2 parser

Also, fallback to using HCLv1.
This commit is contained in:
Mahmood Ali 2020-10-21 10:22:08 -04:00
parent f9290090e0
commit 84ec0b38e8
4 changed files with 74 additions and 7 deletions

View File

@ -7,6 +7,7 @@ import (
"io"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"time"
@ -14,6 +15,7 @@ import (
gg "github.com/hashicorp/go-getter"
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/jobspec"
"github.com/hashicorp/nomad/jobspec2"
"github.com/kr/text"
"github.com/mitchellh/cli"
"github.com/posener/complete"
@ -378,13 +380,20 @@ READ:
}
type JobGetter struct {
hcl1 bool
// The fields below can be overwritten for tests
testStdin io.Reader
}
// StructJob returns the Job struct from jobfile.
func (j *JobGetter) ApiJob(jpath string) (*api.Job, error) {
return j.ApiJobWithArgs(jpath, nil)
}
func (j *JobGetter) ApiJobWithArgs(jpath string, vars map[string]string) (*api.Job, error) {
var jobfile io.Reader
pathName := filepath.Base(jpath)
switch jpath {
case "-":
if j.testStdin != nil {
@ -392,6 +401,7 @@ func (j *JobGetter) ApiJob(jpath string) (*api.Job, error) {
} else {
jobfile = os.Stdin
}
pathName = "stdin.hcl"
default:
if len(jpath) == 0 {
return nil, fmt.Errorf("Error jobfile path has to be specified.")
@ -432,9 +442,15 @@ func (j *JobGetter) ApiJob(jpath string) (*api.Job, error) {
}
// Parse the JobFile
jobStruct, err := jobspec.Parse(jobfile)
var jobStruct *api.Job
var err error
if j.hcl1 {
jobStruct, err = jobspec.Parse(jobfile)
} else {
jobStruct, err = jobspec2.ParseWithArgs(pathName, jobfile, vars, true)
}
if err != nil {
return nil, fmt.Errorf("Error parsing job file from %s: %v", jpath, err)
return nil, fmt.Errorf("Error parsing job file from %s:\n%v", jpath, err)
}
return jobStruct, nil

View File

@ -6,6 +6,7 @@ import (
"strings"
"time"
cflags "github.com/hashicorp/consul/command/flags"
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/scheduler"
"github.com/posener/complete"
@ -72,6 +73,9 @@ Plan Options:
Determines whether the diff between the remote job and planned job is shown.
Defaults to true.
-hcl1
Parses the job file as HCLv1.
-policy-override
Sets the flag to force override any soft mandatory Sentinel policies.
@ -91,6 +95,8 @@ func (c *JobPlanCommand) AutocompleteFlags() complete.Flags {
"-diff": complete.PredictNothing,
"-policy-override": complete.PredictNothing,
"-verbose": complete.PredictNothing,
"-hcl1": complete.PredictNothing,
"-var": complete.PredictAnything,
})
}
@ -101,12 +107,15 @@ 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 varArgs cflags.AppendSliceValue
flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
flags.Usage = func() { c.Ui.Output(c.Help()) }
flags.BoolVar(&diff, "diff", true, "")
flags.BoolVar(&policyOverride, "policy-override", false, "")
flags.BoolVar(&verbose, "verbose", false, "")
flags.BoolVar(&c.JobGetter.hcl1, "hcl1", false, "")
flags.Var(&varArgs, "var", "")
if err := flags.Parse(args); err != nil {
return 255
@ -122,7 +131,7 @@ func (c *JobPlanCommand) Run(args []string) int {
path := args[0]
// Get Job struct from Jobfile
job, err := c.JobGetter.ApiJob(args[0])
job, err := c.JobGetter.ApiJobWithArgs(args[0], parseVars(varArgs))
if err != nil {
c.Ui.Error(fmt.Sprintf("Error getting job struct: %s", err))
return 255

View File

@ -9,6 +9,7 @@ import (
"strings"
"time"
cflags "github.com/hashicorp/consul/command/flags"
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/helper"
"github.com/posener/complete"
@ -79,6 +80,9 @@ Run Options:
the evaluation ID will be printed to the screen, which can be used to
examine the evaluation using the eval-status command.
-hcl1
Parses the job file as HCLv1.
-output
Output the JSON that would be submitted to the HTTP API without submitting
the job.
@ -88,7 +92,7 @@ Run Options:
-preserve-counts
If set, the existing task group counts will be preserved when updating a job.
-consul-token
If set, the passed Consul token is stored in the job before sending to the
Nomad servers. This allows passing the Consul token without storing it in
@ -127,6 +131,8 @@ func (c *JobRunCommand) AutocompleteFlags() complete.Flags {
"-output": complete.PredictNothing,
"-policy-override": complete.PredictNothing,
"-preserve-counts": complete.PredictNothing,
"-hcl1": complete.PredictNothing,
"-var": complete.PredictAnything,
})
}
@ -139,6 +145,7 @@ func (c *JobRunCommand) Name() string { return "job run" }
func (c *JobRunCommand) Run(args []string) int {
var detach, verbose, output, override, preserveCounts bool
var checkIndexStr, consulToken, vaultToken, vaultNamespace string
var varArgs cflags.AppendSliceValue
flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
flags.Usage = func() { c.Ui.Output(c.Help()) }
@ -147,10 +154,12 @@ func (c *JobRunCommand) Run(args []string) int {
flags.BoolVar(&output, "output", false, "")
flags.BoolVar(&override, "policy-override", false, "")
flags.BoolVar(&preserveCounts, "preserve-counts", false, "")
flags.BoolVar(&c.JobGetter.hcl1, "hcl1", false, "")
flags.StringVar(&checkIndexStr, "check-index", "", "")
flags.StringVar(&consulToken, "consul-token", "", "")
flags.StringVar(&vaultToken, "vault-token", "", "")
flags.StringVar(&vaultNamespace, "vault-namespace", "", "")
flags.Var(&varArgs, "var", "")
if err := flags.Parse(args); err != nil {
return 1
@ -171,7 +180,7 @@ func (c *JobRunCommand) Run(args []string) int {
}
// Get Job struct from Jobfile
job, err := c.JobGetter.ApiJob(args[0])
job, err := c.JobGetter.ApiJobWithArgs(args[0], parseVars(varArgs))
if err != nil {
c.Ui.Error(fmt.Sprintf("Error getting job struct: %s", err))
return 1
@ -319,3 +328,22 @@ func parseCheckIndex(input string) (uint64, bool, error) {
u, err := strconv.ParseUint(input, 10, 64)
return u, true, err
}
func parseVars(vars []string) map[string]string {
if len(vars) == 0 {
return nil
}
result := make(map[string]string, len(vars))
for _, v := range vars {
parts := strings.SplitN(v, "=", 2)
k := parts[0]
if len(parts) == 2 {
result[k] = parts[1]
} else {
result[k] = os.Getenv(k)
}
}
return result
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"strings"
cflags "github.com/hashicorp/consul/command/flags"
multierror "github.com/hashicorp/go-multierror"
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/command/agent"
@ -27,6 +28,11 @@ Alias: nomad validate
If the supplied path is "-", the jobfile is read from stdin. Otherwise
it is read from the file at the supplied path or downloaded and
read from URL specified.
Validate Options:
-hcl1
Parses the job file as HCLv1.
`
return strings.TrimSpace(helpText)
}
@ -36,7 +42,10 @@ func (c *JobValidateCommand) Synopsis() string {
}
func (c *JobValidateCommand) AutocompleteFlags() complete.Flags {
return nil
return complete.Flags{
"-hcl1": complete.PredictNothing,
"-var": complete.PredictAnything,
}
}
func (c *JobValidateCommand) AutocompleteArgs() complete.Predictor {
@ -46,8 +55,13 @@ func (c *JobValidateCommand) AutocompleteArgs() complete.Predictor {
func (c *JobValidateCommand) Name() string { return "job validate" }
func (c *JobValidateCommand) Run(args []string) int {
var varArgs cflags.AppendSliceValue
flags := c.Meta.FlagSet(c.Name(), FlagSetNone)
flags.Usage = func() { c.Ui.Output(c.Help()) }
flags.BoolVar(&c.JobGetter.hcl1, "hcl1", false, "")
flags.Var(&varArgs, "var", "")
if err := flags.Parse(args); err != nil {
return 1
}
@ -61,7 +75,7 @@ func (c *JobValidateCommand) Run(args []string) int {
}
// Get Job struct from Jobfile
job, err := c.JobGetter.ApiJob(args[0])
job, err := c.JobGetter.ApiJobWithArgs(args[0], parseVars(varArgs))
if err != nil {
c.Ui.Error(fmt.Sprintf("Error getting job struct: %s", err))
return 1