github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/command/validate.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/hashicorp/packer/packer" 9 "github.com/hashicorp/packer/template" 10 ) 11 12 type ValidateCommand struct { 13 Meta 14 } 15 16 func (c *ValidateCommand) Run(args []string) int { 17 var cfgSyntaxOnly bool 18 flags := c.Meta.FlagSet("validate", FlagSetBuildFilter|FlagSetVars) 19 flags.Usage = func() { c.Ui.Say(c.Help()) } 20 flags.BoolVar(&cfgSyntaxOnly, "syntax-only", false, "check syntax only") 21 if err := flags.Parse(args); err != nil { 22 return 1 23 } 24 25 args = flags.Args() 26 if len(args) != 1 { 27 flags.Usage() 28 return 1 29 } 30 31 // Parse the template 32 tpl, err := template.ParseFile(args[0]) 33 if err != nil { 34 c.Ui.Error(fmt.Sprintf("Failed to parse template: %s", err)) 35 return 1 36 } 37 38 // If we're only checking syntax, then we're done already 39 if cfgSyntaxOnly { 40 c.Ui.Say("Syntax-only check passed. Everything looks okay.") 41 return 0 42 } 43 44 // Get the core 45 core, err := c.Meta.Core(tpl) 46 if err != nil { 47 c.Ui.Error(err.Error()) 48 return 1 49 } 50 51 errs := make([]error, 0) 52 warnings := make(map[string][]string) 53 54 // Get the builds we care about 55 buildNames := c.Meta.BuildNames(core) 56 builds := make([]packer.Build, 0, len(buildNames)) 57 for _, n := range buildNames { 58 b, err := core.Build(n) 59 if err != nil { 60 c.Ui.Error(fmt.Sprintf( 61 "Failed to initialize build '%s': %s", 62 n, err)) 63 return 1 64 } 65 66 builds = append(builds, b) 67 } 68 69 // Check the configuration of all builds 70 for _, b := range builds { 71 log.Printf("Preparing build: %s", b.Name()) 72 warns, err := b.Prepare() 73 if len(warns) > 0 { 74 warnings[b.Name()] = warns 75 } 76 if err != nil { 77 errs = append(errs, fmt.Errorf("Errors validating build '%s'. %s", b.Name(), err)) 78 } 79 } 80 81 if len(errs) > 0 { 82 c.Ui.Error("Template validation failed. Errors are shown below.\n") 83 for i, err := range errs { 84 c.Ui.Error(err.Error()) 85 86 if (i + 1) < len(errs) { 87 c.Ui.Error("") 88 } 89 } 90 91 return 1 92 } 93 94 if len(warnings) > 0 { 95 c.Ui.Say("Template validation succeeded, but there were some warnings.") 96 c.Ui.Say("These are ONLY WARNINGS, and Packer will attempt to build the") 97 c.Ui.Say("template despite them, but they should be paid attention to.\n") 98 99 for build, warns := range warnings { 100 c.Ui.Say(fmt.Sprintf("Warnings for build '%s':\n", build)) 101 for _, warning := range warns { 102 c.Ui.Say(fmt.Sprintf("* %s", warning)) 103 } 104 } 105 106 return 0 107 } 108 109 c.Ui.Say("Template validated successfully.") 110 return 0 111 } 112 113 func (*ValidateCommand) Help() string { 114 helpText := ` 115 Usage: packer validate [options] TEMPLATE 116 117 Checks the template is valid by parsing the template and also 118 checking the configuration with the various builders, provisioners, etc. 119 120 If it is not valid, the errors will be shown and the command will exit 121 with a non-zero exit status. If it is valid, it will exit with a zero 122 exit status. 123 124 Options: 125 126 -syntax-only Only check syntax. Do not verify config of the template. 127 -except=foo,bar,baz Validate all builds other than these 128 -only=foo,bar,baz Validate only these builds 129 -var 'key=value' Variable for templates, can be used multiple times. 130 -var-file=path JSON file containing user variables. 131 ` 132 133 return strings.TrimSpace(helpText) 134 } 135 136 func (*ValidateCommand) Synopsis() string { 137 return "check that a template is valid" 138 }