github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/command/job_validate.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "strings" 6 7 multierror "github.com/hashicorp/go-multierror" 8 "github.com/hashicorp/nomad/api" 9 "github.com/hashicorp/nomad/command/agent" 10 flaghelper "github.com/hashicorp/nomad/helper/flags" 11 "github.com/hashicorp/nomad/nomad/structs" 12 "github.com/posener/complete" 13 ) 14 15 type JobValidateCommand struct { 16 Meta 17 JobGetter 18 } 19 20 func (c *JobValidateCommand) Help() string { 21 helpText := ` 22 Usage: nomad job validate [options] <path> 23 Alias: nomad validate 24 25 Checks if a given HCL job file has a valid specification. This can be used to 26 check for any syntax errors or validation problems with a job. 27 28 If the supplied path is "-", the jobfile is read from stdin. Otherwise 29 it is read from the file at the supplied path or downloaded and 30 read from URL specified. 31 32 When ACLs are enabled, this command requires a token with the 'read-job' 33 capability for the job's namespace. 34 35 Validate Options: 36 37 -hcl1 38 Parses the job file as HCLv1. 39 40 -var 'key=value' 41 Variable for template, can be used multiple times. 42 43 -var-file=path 44 Path to HCL2 file containing user variables. 45 46 ` 47 return strings.TrimSpace(helpText) 48 } 49 50 func (c *JobValidateCommand) Synopsis() string { 51 return "Checks if a given job specification is valid" 52 } 53 54 func (c *JobValidateCommand) AutocompleteFlags() complete.Flags { 55 return complete.Flags{ 56 "-hcl1": complete.PredictNothing, 57 "-var": complete.PredictAnything, 58 "-var-file": complete.PredictFiles("*.var"), 59 } 60 } 61 62 func (c *JobValidateCommand) AutocompleteArgs() complete.Predictor { 63 return complete.PredictOr(complete.PredictFiles("*.nomad"), complete.PredictFiles("*.hcl")) 64 } 65 66 func (c *JobValidateCommand) Name() string { return "job validate" } 67 68 func (c *JobValidateCommand) Run(args []string) int { 69 var varArgs, varFiles flaghelper.StringFlag 70 71 flagSet := c.Meta.FlagSet(c.Name(), FlagSetNone) 72 flagSet.Usage = func() { c.Ui.Output(c.Help()) } 73 flagSet.BoolVar(&c.JobGetter.hcl1, "hcl1", false, "") 74 flagSet.Var(&varArgs, "var", "") 75 flagSet.Var(&varFiles, "var-file", "") 76 77 if err := flagSet.Parse(args); err != nil { 78 return 1 79 } 80 81 // Check that we got exactly one node 82 args = flagSet.Args() 83 if len(args) != 1 { 84 c.Ui.Error("This command takes one argument: <path>") 85 c.Ui.Error(commandErrorText(c)) 86 return 1 87 } 88 89 // Get Job struct from Jobfile 90 job, err := c.JobGetter.ApiJobWithArgs(args[0], varArgs, varFiles) 91 if err != nil { 92 c.Ui.Error(fmt.Sprintf("Error getting job struct: %s", err)) 93 return 1 94 } 95 96 // Get the HTTP client 97 client, err := c.Meta.Client() 98 if err != nil { 99 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 100 return 255 101 } 102 103 // Force the region to be that of the job. 104 if r := job.Region; r != nil { 105 client.SetRegion(*r) 106 } 107 108 // Check that the job is valid 109 jr, _, err := client.Jobs().Validate(job, nil) 110 if err != nil { 111 jr, err = c.validateLocal(job) 112 } 113 if err != nil { 114 c.Ui.Error(fmt.Sprintf("Error validating job: %s", err)) 115 return 1 116 } 117 118 if jr != nil && !jr.DriverConfigValidated { 119 c.Ui.Output( 120 c.Colorize().Color("[bold][yellow]Driver configuration not validated since connection to Nomad agent couldn't be established.[reset]\n")) 121 } 122 123 if jr != nil && jr.Error != "" { 124 c.Ui.Error( 125 c.Colorize().Color("[bold][red]Job validation errors:[reset]")) 126 c.Ui.Error(jr.Error) 127 return 1 128 } 129 130 // Print any warnings if there are any 131 if jr.Warnings != "" { 132 c.Ui.Output( 133 c.Colorize().Color(fmt.Sprintf("[bold][yellow]Job Warnings:\n%s[reset]\n", jr.Warnings))) 134 } 135 136 // Done! 137 c.Ui.Output( 138 c.Colorize().Color("[bold][green]Job validation successful[reset]")) 139 return 0 140 } 141 142 // validateLocal validates without talking to a Nomad agent 143 func (c *JobValidateCommand) validateLocal(aj *api.Job) (*api.JobValidateResponse, error) { 144 var out api.JobValidateResponse 145 146 job := agent.ApiJobToStructJob(aj) 147 job.Canonicalize() 148 149 if vErr := job.Validate(); vErr != nil { 150 if merr, ok := vErr.(*multierror.Error); ok { 151 for _, err := range merr.Errors { 152 out.ValidationErrors = append(out.ValidationErrors, err.Error()) 153 } 154 out.Error = merr.Error() 155 } else { 156 out.ValidationErrors = append(out.ValidationErrors, vErr.Error()) 157 out.Error = vErr.Error() 158 } 159 } 160 161 out.Warnings = structs.MergeMultierrorWarnings(job.Warnings()) 162 return &out, nil 163 }