github.com/hhrutter/nomad@v0.6.0-rc2.0.20170723054333-80c4b03f0705/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  }