github.com/djenriquez/nomad-1@v0.8.1/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 "github.com/hashicorp/nomad/nomad/structs" 11 "github.com/posener/complete" 12 ) 13 14 type JobValidateCommand struct { 15 Meta 16 JobGetter 17 } 18 19 func (c *JobValidateCommand) Help() string { 20 helpText := ` 21 Usage: nomad job validate [options] <path> 22 Alias: nomad validate 23 24 Checks if a given HCL job file has a valid specification. This can be used to 25 check for any syntax errors or validation problems with a job. 26 27 If the supplied path is "-", the jobfile is read from stdin. Otherwise 28 it is read from the file at the supplied path or downloaded and 29 read from URL specified. 30 ` 31 return strings.TrimSpace(helpText) 32 } 33 34 func (c *JobValidateCommand) Synopsis() string { 35 return "Checks if a given job specification is valid" 36 } 37 38 func (c *JobValidateCommand) AutocompleteFlags() complete.Flags { 39 return nil 40 } 41 42 func (c *JobValidateCommand) AutocompleteArgs() complete.Predictor { 43 return complete.PredictOr(complete.PredictFiles("*.nomad"), complete.PredictFiles("*.hcl")) 44 } 45 46 func (c *JobValidateCommand) Run(args []string) int { 47 flags := c.Meta.FlagSet("job validate", FlagSetNone) 48 flags.Usage = func() { c.Ui.Output(c.Help()) } 49 if err := flags.Parse(args); err != nil { 50 return 1 51 } 52 53 // Check that we got exactly one node 54 args = flags.Args() 55 if len(args) != 1 { 56 c.Ui.Error(c.Help()) 57 return 1 58 } 59 60 // Get Job struct from Jobfile 61 job, err := c.JobGetter.ApiJob(args[0]) 62 if err != nil { 63 c.Ui.Error(fmt.Sprintf("Error getting job struct: %s", err)) 64 return 1 65 } 66 67 // Get the HTTP client 68 client, err := c.Meta.Client() 69 if err != nil { 70 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 71 return 255 72 } 73 74 // Force the region to be that of the job. 75 if r := job.Region; r != nil { 76 client.SetRegion(*r) 77 } 78 79 // Check that the job is valid 80 jr, _, err := client.Jobs().Validate(job, nil) 81 if err != nil { 82 jr, err = c.validateLocal(job) 83 } 84 if err != nil { 85 c.Ui.Error(fmt.Sprintf("Error validating job: %s", err)) 86 return 1 87 } 88 89 if jr != nil && !jr.DriverConfigValidated { 90 c.Ui.Output( 91 c.Colorize().Color("[bold][yellow]Driver configuration not validated since connection to Nomad agent couldn't be established.[reset]\n")) 92 } 93 94 if jr != nil && jr.Error != "" { 95 c.Ui.Error( 96 c.Colorize().Color("[bold][red]Job validation errors:[reset]")) 97 c.Ui.Error(jr.Error) 98 return 1 99 } 100 101 // Print any warnings if there are any 102 if jr.Warnings != "" { 103 c.Ui.Output( 104 c.Colorize().Color(fmt.Sprintf("[bold][yellow]Job Warnings:\n%s[reset]\n", jr.Warnings))) 105 } 106 107 // Done! 108 c.Ui.Output( 109 c.Colorize().Color("[bold][green]Job validation successful[reset]")) 110 return 0 111 } 112 113 // validateLocal validates without talking to a Nomad agent 114 func (c *JobValidateCommand) validateLocal(aj *api.Job) (*api.JobValidateResponse, error) { 115 var out api.JobValidateResponse 116 117 job := agent.ApiJobToStructJob(aj) 118 canonicalizeWarnings := job.Canonicalize() 119 120 if vErr := job.Validate(); vErr != nil { 121 if merr, ok := vErr.(*multierror.Error); ok { 122 for _, err := range merr.Errors { 123 out.ValidationErrors = append(out.ValidationErrors, err.Error()) 124 } 125 out.Error = merr.Error() 126 } else { 127 out.ValidationErrors = append(out.ValidationErrors, vErr.Error()) 128 out.Error = vErr.Error() 129 } 130 } 131 132 warnings := job.Warnings() 133 out.Warnings = structs.MergeMultierrorWarnings(warnings, canonicalizeWarnings) 134 return &out, nil 135 }