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