Merge pull request #2386 from hashicorp/b-template-variable-change-failure

provider/template: don't error when rendering fails in Exists
This commit is contained in:
Paul Hinze 2015-06-17 15:36:11 -05:00
commit 5e86e709bc
3 changed files with 74 additions and 11 deletions

View File

@ -5,6 +5,7 @@ import (
"encoding/hex"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
@ -75,7 +76,13 @@ func Delete(d *schema.ResourceData, meta interface{}) error {
func Exists(d *schema.ResourceData, meta interface{}) (bool, error) {
rendered, err := render(d)
if err != nil {
return false, err
if _, ok := err.(templateRenderError); ok {
log.Printf("[DEBUG] Got error while rendering in Exists: %s", err)
log.Printf("[DEBUG] Returning false so the template re-renders using latest variables from config.")
return false, nil
} else {
return false, err
}
}
return hash(rendered) == d.Id(), nil
}
@ -87,6 +94,8 @@ func Read(d *schema.ResourceData, meta interface{}) error {
return nil
}
type templateRenderError error
var readfile func(string) ([]byte, error) = ioutil.ReadFile // testing hook
func render(d *schema.ResourceData) (string, error) {
@ -105,7 +114,9 @@ func render(d *schema.ResourceData) (string, error) {
rendered, err := execute(string(buf), vars)
if err != nil {
return "", fmt.Errorf("failed to render %v: %v", filename, err)
return "", templateRenderError(
fmt.Errorf("failed to render %v: %v", filename, err),
)
}
return rendered, nil

View File

@ -34,15 +34,7 @@ func TestTemplateRendering(t *testing.T) {
Providers: testProviders,
Steps: []r.TestStep{
r.TestStep{
Config: `
resource "template_file" "t0" {
filename = "mock"
vars = ` + tt.vars + `
}
output "rendered" {
value = "${template_file.t0.rendered}"
}
`,
Config: testTemplateConfig(tt.vars),
Check: func(s *terraform.State) error {
got := s.RootModule().Outputs["rendered"]
if tt.want != got {
@ -55,3 +47,55 @@ output "rendered" {
})
}
}
// https://github.com/hashicorp/terraform/issues/2344
func TestTemplateVariableChange(t *testing.T) {
steps := []struct {
vars string
template string
want string
}{
{`{a="foo"}`, `${a}`, `foo`},
{`{b="bar"}`, `${b}`, `bar`},
}
var testSteps []r.TestStep
for i, step := range steps {
testSteps = append(testSteps, r.TestStep{
PreConfig: func(template string) func() {
return func() {
readfile = func(string) ([]byte, error) {
return []byte(template), nil
}
}
}(step.template),
Config: testTemplateConfig(step.vars),
Check: func(i int, want string) r.TestCheckFunc {
return func(s *terraform.State) error {
got := s.RootModule().Outputs["rendered"]
if want != got {
return fmt.Errorf("[%d] got:\n%q\nwant:\n%q\n", i, got, want)
}
return nil
}
}(i, step.want),
})
}
r.Test(t, r.TestCase{
Providers: testProviders,
Steps: testSteps,
})
}
func testTemplateConfig(vars string) string {
return `
resource "template_file" "t0" {
filename = "mock"
vars = ` + vars + `
}
output "rendered" {
value = "${template_file.t0.rendered}"
}
`
}

View File

@ -60,6 +60,10 @@ type TestCase struct {
// potentially complex update logic. In general, simply create/destroy
// tests will only need one step.
type TestStep struct {
// PreConfig is called before the Config is applied to perform any per-step
// setup that needs to happen
PreConfig func()
// Config a string of the configuration to give to Terraform.
Config string
@ -160,6 +164,10 @@ func testStep(
opts terraform.ContextOpts,
state *terraform.State,
step TestStep) (*terraform.State, error) {
if step.PreConfig != nil {
step.PreConfig()
}
cfgPath, err := ioutil.TempDir("", "tf-test")
if err != nil {
return state, fmt.Errorf(