diff --git a/command/deploy.go b/command/deploy.go index ea828dd20..05ffff171 100644 --- a/command/deploy.go +++ b/command/deploy.go @@ -102,6 +102,7 @@ func (c *DeployCommand) Run(args []string) int { var err error var level, format string + var strictMode bool config := &levant.DeployConfig{ Client: &structs.ClientConfig{}, @@ -125,6 +126,7 @@ func (c *DeployCommand) Run(args []string) int { flags.StringVar(&format, "log-format", "HUMAN", "") flags.StringVar(&config.Deploy.VaultToken, "vault-token", "", "") flags.BoolVar(&config.Deploy.EnvVault, "vault", false, "") + flags.BoolVar(&strictMode, "strict", false, "") flags.Var((*helper.FlagStringSlice)(&config.Template.VariableFiles), "var-file", "") @@ -159,7 +161,7 @@ func (c *DeployCommand) Run(args []string) int { } config.Template.Job, err = template.RenderJob(config.Template.TemplateFile, - config.Template.VariableFiles, config.Client.ConsulAddr, &c.Meta.flagVars) + config.Template.VariableFiles, config.Client.ConsulAddr, strictMode, &c.Meta.flagVars) if err != nil { c.UI.Error(fmt.Sprintf("[ERROR] levant/command: %v", err)) return 1 diff --git a/command/deploy_test.go b/command/deploy_test.go index 6db2492ac..46acc6a9d 100644 --- a/command/deploy_test.go +++ b/command/deploy_test.go @@ -30,7 +30,7 @@ func TestDeploy_checkCanaryAutoPromote(t *testing.T) { } for i, c := range cases { - job, err := template.RenderJob(c.File, []string{}, "", &fVars) + job, err := template.RenderJob(c.File, []string{}, "", false, &fVars) if err != nil { t.Fatalf("case %d failed: %v", i, err) } @@ -61,7 +61,7 @@ func TestDeploy_checkForceBatch(t *testing.T) { } for i, c := range cases { - job, err := template.RenderJob(c.File, []string{}, "", &fVars) + job, err := template.RenderJob(c.File, []string{}, "", false, &fVars) if err != nil { t.Fatalf("case %d failed: %v", i, err) } diff --git a/command/plan.go b/command/plan.go index 4099fcefb..9750dcf27 100644 --- a/command/plan.go +++ b/command/plan.go @@ -88,6 +88,7 @@ func (c *PlanCommand) Run(args []string) int { Template: &structs.TemplateConfig{}, } + var strictMode bool flags := c.Meta.FlagSet("plan", FlagSetVars) flags.Usage = func() { c.UI.Output(c.Help()) } @@ -98,6 +99,7 @@ func (c *PlanCommand) Run(args []string) int { flags.StringVar(&level, "log-level", "INFO", "") flags.StringVar(&format, "log-format", "HUMAN", "") flags.Var((*helper.FlagStringSlice)(&config.Template.VariableFiles), "var-file", "") + flags.BoolVar(&strictMode, "strict", false, "") if err = flags.Parse(args); err != nil { return 1 @@ -124,7 +126,7 @@ func (c *PlanCommand) Run(args []string) int { } config.Template.Job, err = template.RenderJob(config.Template.TemplateFile, - config.Template.VariableFiles, config.Client.ConsulAddr, &c.Meta.flagVars) + config.Template.VariableFiles, config.Client.ConsulAddr, strictMode, &c.Meta.flagVars) if err != nil { c.UI.Error(fmt.Sprintf("[ERROR] levant/command: %v", err)) diff --git a/command/render.go b/command/render.go index c2fa1026c..42e1c93a7 100644 --- a/command/render.go +++ b/command/render.go @@ -60,6 +60,7 @@ func (c *RenderCommand) Run(args []string) int { var addr, outPath, templateFile string var variables []string + var strictMode bool var err error var tpl *bytes.Buffer @@ -69,6 +70,7 @@ func (c *RenderCommand) Run(args []string) int { flags.StringVar(&addr, "consul-address", "", "") flags.Var((*helper.FlagStringSlice)(&variables), "var-file", "") flags.StringVar(&outPath, "out", "", "") + flags.BoolVar(&strictMode, "strict", false, "") if err = flags.Parse(args); err != nil { return 1 @@ -89,7 +91,7 @@ func (c *RenderCommand) Run(args []string) int { return 1 } - tpl, err = template.RenderTemplate(templateFile, variables, addr, &c.Meta.flagVars) + tpl, err = template.RenderTemplate(templateFile, variables, addr, strictMode, &c.Meta.flagVars) if err != nil { c.UI.Error(fmt.Sprintf("[ERROR] levant/command: %v", err)) return 1 diff --git a/template/render.go b/template/render.go index b5d542ab7..ece783fd5 100644 --- a/template/render.go +++ b/template/render.go @@ -19,9 +19,9 @@ import ( // RenderJob takes in a template and variables performing a render of the // template followed by Nomad jobspec parse. -func RenderJob(templateFile string, variableFiles []string, addr string, flagVars *map[string]string) (job *nomad.Job, err error) { +func RenderJob(templateFile string, variableFiles []string, addr string, strictMode bool, flagVars *map[string]string) (job *nomad.Job, err error) { var tpl *bytes.Buffer - tpl, err = RenderTemplate(templateFile, variableFiles, addr, flagVars) + tpl, err = RenderTemplate(templateFile, variableFiles, addr, strictMode, flagVars) if err != nil { return } @@ -32,12 +32,13 @@ func RenderJob(templateFile string, variableFiles []string, addr string, flagVar // RenderTemplate is the main entry point to render the template based on the // passed variables file. -func RenderTemplate(templateFile string, variableFiles []string, addr string, flagVars *map[string]string) (tpl *bytes.Buffer, err error) { +func RenderTemplate(templateFile string, variableFiles []string, addr string, strictMode bool, flagVars *map[string]string) (tpl *bytes.Buffer, err error) { t := &tmpl{} t.flagVariables = flagVars t.jobTemplateFile = templateFile t.variableFiles = variableFiles + t.errMissingKey = strictMode c, err := client.NewConsulClient(addr) if err != nil { diff --git a/template/render_test.go b/template/render_test.go index ee2618ae1..0b94bae6a 100644 --- a/template/render_test.go +++ b/template/render_test.go @@ -25,7 +25,7 @@ func TestTemplater_RenderTemplate(t *testing.T) { fVars := make(map[string]string) // Test basic TF template render. - job, err = RenderJob("test-fixtures/single_templated.nomad", []string{"test-fixtures/test.tf"}, "", &fVars) + job, err = RenderJob("test-fixtures/single_templated.nomad", []string{"test-fixtures/test.tf"}, "", false, &fVars) if err != nil { t.Fatal(err) } @@ -34,7 +34,7 @@ func TestTemplater_RenderTemplate(t *testing.T) { } // Test basic YAML template render. - job, err = RenderJob("test-fixtures/single_templated.nomad", []string{"test-fixtures/test.yaml"}, "", &fVars) + job, err = RenderJob("test-fixtures/single_templated.nomad", []string{"test-fixtures/test.yaml"}, "", false, &fVars) if err != nil { t.Fatal(err) } @@ -43,7 +43,7 @@ func TestTemplater_RenderTemplate(t *testing.T) { } // Test multiple var-files - job, err = RenderJob("test-fixtures/single_templated.nomad", []string{"test-fixtures/test.yaml", "test-fixtures/test-overwrite.yaml"}, "", &fVars) + job, err = RenderJob("test-fixtures/single_templated.nomad", []string{"test-fixtures/test.yaml", "test-fixtures/test-overwrite.yaml"}, "", false, &fVars) if err != nil { t.Fatal(err) } @@ -52,7 +52,7 @@ func TestTemplater_RenderTemplate(t *testing.T) { } // Test multiple var-files of different types - job, err = RenderJob("test-fixtures/single_templated.nomad", []string{"test-fixtures/test.tf", "test-fixtures/test-overwrite.yaml"}, "", &fVars) + job, err = RenderJob("test-fixtures/single_templated.nomad", []string{"test-fixtures/test.tf", "test-fixtures/test-overwrite.yaml"}, "", false, &fVars) if err != nil { t.Fatal(err) } @@ -62,7 +62,7 @@ func TestTemplater_RenderTemplate(t *testing.T) { // Test multiple var-files with var-args fVars["job_name"] = testJobNameOverwrite2 - job, err = RenderJob("test-fixtures/single_templated.nomad", []string{"test-fixtures/test.tf", "test-fixtures/test-overwrite.yaml"}, "", &fVars) + job, err = RenderJob("test-fixtures/single_templated.nomad", []string{"test-fixtures/test.tf", "test-fixtures/test-overwrite.yaml"}, "", false, &fVars) if err != nil { t.Fatal(err) } @@ -71,7 +71,7 @@ func TestTemplater_RenderTemplate(t *testing.T) { } // Test empty var-args and empty variable file render. - job, err = RenderJob("test-fixtures/none_templated.nomad", []string{}, "", &fVars) + job, err = RenderJob("test-fixtures/none_templated.nomad", []string{}, "", false, &fVars) if err != nil { t.Fatal(err) } @@ -82,7 +82,7 @@ func TestTemplater_RenderTemplate(t *testing.T) { // Test var-args only render. delete(fVars, "job_name") fVars["job_name"] = testJobName - job, err = RenderJob("test-fixtures/single_templated.nomad", []string{}, "", &fVars) + job, err = RenderJob("test-fixtures/single_templated.nomad", []string{}, "", false, &fVars) if err != nil { t.Fatal(err) } @@ -94,7 +94,7 @@ func TestTemplater_RenderTemplate(t *testing.T) { delete(fVars, "job_name") fVars["datacentre"] = testDCName os.Setenv(testEnvName, testEnvValue) - job, err = RenderJob("test-fixtures/multi_templated.nomad", []string{"test-fixtures/test.yaml"}, "", &fVars) + job, err = RenderJob("test-fixtures/multi_templated.nomad", []string{"test-fixtures/test.yaml"}, "", false, &fVars) if err != nil { t.Fatal(err) } diff --git a/template/template.go b/template/template.go index 2297970e1..4440f851f 100644 --- a/template/template.go +++ b/template/template.go @@ -13,6 +13,7 @@ type tmpl struct { flagVariables *map[string]string jobTemplateFile string variableFiles []string + errMissingKey bool } const ( @@ -28,7 +29,13 @@ const ( func (t *tmpl) newTemplate() *template.Template { tmpl := template.New("jobTemplate") tmpl.Delims(leftDelim, rightDelim) - tmpl.Option("missingkey=zero") + + if t.errMissingKey { + tmpl.Option("missingkey=error") + } else { + tmpl.Option("missingkey=zero") + } + tmpl.Funcs(funcMap(t.consulClient)) return tmpl } diff --git a/test/acctest/acctest.go b/test/acctest/acctest.go index 7f7e01d57..2accd1a28 100644 --- a/test/acctest/acctest.go +++ b/test/acctest/acctest.go @@ -56,7 +56,6 @@ func Test(t *testing.T, c TestCase) { if err != nil { t.Fatalf("failed to create nomad client: %s", err) } - state := &TestState{ JobName: fmt.Sprintf("levant-%s", t.Name()), Nomad: nomad, diff --git a/test/acctest/deploy.go b/test/acctest/deploy.go index b654b7796..f9d648037 100644 --- a/test/acctest/deploy.go +++ b/test/acctest/deploy.go @@ -26,7 +26,7 @@ func (c DeployTestStepRunner) Run(s *TestState) error { } c.Vars["job_name"] = s.JobName - job, err := template.RenderJob("fixtures/"+c.FixtureName, []string{}, "", &c.Vars) + job, err := template.RenderJob("fixtures/"+c.FixtureName, []string{}, "", false, &c.Vars) if err != nil { return fmt.Errorf("error rendering template: %s", err) }