From 08a9c8e2c2212671cd46d147c2ac66a7451beeba Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 31 Aug 2016 11:36:51 -0700 Subject: [PATCH 1/3] terraform: self.count works in interpolations [GH-5283] --- terraform/context_apply_test.go | 53 +++++++++++++++++++ terraform/interpolate.go | 17 +++++- .../main.tf | 7 +++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 terraform/test-fixtures/apply-provisioner-multi-self-ref-count/main.tf diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index 2bd97fd051..0462096baa 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -2405,6 +2405,59 @@ func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) { } } +func TestContext2Apply_provisionerMultiSelfRefCount(t *testing.T) { + var lock sync.Mutex + commands := make([]string, 0, 5) + + m := testModule(t, "apply-provisioner-multi-self-ref-count") + p := testProvider("aws") + pr := testProvisioner() + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { + lock.Lock() + defer lock.Unlock() + + val, ok := c.Config["command"] + if !ok { + t.Fatalf("bad value for command: %v %#v", val, c) + } + + commands = append(commands, val.(string)) + return nil + } + + ctx := testContext2(t, &ContextOpts{ + Module: m, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + Provisioners: map[string]ResourceProvisionerFactory{ + "shell": testProvisionerFuncFixed(pr), + }, + }) + + if _, err := ctx.Plan(); err != nil { + t.Fatalf("err: %s", err) + } + + if _, err := ctx.Apply(); err != nil { + t.Fatalf("err: %s", err) + } + + // Verify apply was invoked + if !pr.ApplyCalled { + t.Fatalf("provisioner not invoked") + } + + // Verify our result + sort.Strings(commands) + expectedCommands := []string{"3", "3", "3"} + if !reflect.DeepEqual(commands, expectedCommands) { + t.Fatalf("bad: %#v", commands) + } +} + // Provisioner should NOT run on a diff, only create func TestContext2Apply_Provisioner_Diff(t *testing.T) { m := testModule(t, "apply-provisioner-diff") diff --git a/terraform/interpolate.go b/terraform/interpolate.go index b42ca8211a..2117fc3f02 100644 --- a/terraform/interpolate.go +++ b/terraform/interpolate.go @@ -265,6 +265,7 @@ func (i *Interpolater) valueSelfVar( return fmt.Errorf( "%s: invalid scope, self variables are only valid on resources", n) } + rv, err := config.NewResourceVariable(fmt.Sprintf( "%s.%s.%d.%s", scope.Resource.Type, @@ -359,11 +360,25 @@ func (i *Interpolater) computeResourceVariable( // Get the information about this resource variable, and verify // that it exists and such. - module, _, err := i.resourceVariableInfo(scope, v) + module, cr, err := i.resourceVariableInfo(scope, v) if err != nil { return nil, err } + // If we're requesting "count" its a special variable that we grab + // directly from the config itself. + if v.Field == "count" { + count, err := cr.Count() + if err != nil { + return nil, fmt.Errorf( + "Error reading %s count: %s", + v.ResourceId(), + err) + } + + return &ast.Variable{Type: ast.TypeInt, Value: count}, nil + } + // If we have no module in the state yet or count, return empty if module == nil || len(module.Resources) == 0 { return nil, nil diff --git a/terraform/test-fixtures/apply-provisioner-multi-self-ref-count/main.tf b/terraform/test-fixtures/apply-provisioner-multi-self-ref-count/main.tf new file mode 100644 index 0000000000..c8b83d7c0b --- /dev/null +++ b/terraform/test-fixtures/apply-provisioner-multi-self-ref-count/main.tf @@ -0,0 +1,7 @@ +resource "aws_instance" "foo" { + count = 3 + + provisioner "shell" { + command = "${self.count}" + } +} From d2e15ab69ac8df57033bae9b7e3f8532a8cbff90 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 31 Aug 2016 11:49:25 -0700 Subject: [PATCH 2/3] terraform: add test explicitly for referencing count --- terraform/context_apply_test.go | 33 +++++++++++++++++++ terraform/terraform_test.go | 16 +++++++++ .../test-fixtures/apply-ref-count/main.tf | 7 ++++ 3 files changed, 56 insertions(+) create mode 100644 terraform/test-fixtures/apply-ref-count/main.tf diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index 0462096baa..1d7c15f926 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -149,6 +149,39 @@ module.test: } } +func TestContext2Apply_refCount(t *testing.T) { + m := testModule(t, "apply-ref-count") + p := testProvider("aws") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + ctx := testContext2(t, &ContextOpts{ + Module: m, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + }) + + if _, err := ctx.Plan(); err != nil { + t.Fatalf("err: %s", err) + } + + state, err := ctx.Apply() + if err != nil { + t.Fatalf("err: %s", err) + } + + mod := state.RootModule() + if len(mod.Resources) < 2 { + t.Fatalf("bad: %#v", mod.Resources) + } + + actual := strings.TrimSpace(state.String()) + expected := strings.TrimSpace(testTerraformApplyRefCountStr) + if actual != expected { + t.Fatalf("bad: \n%s", actual) + } +} + func TestContext2Apply_providerAlias(t *testing.T) { m := testModule(t, "apply-provider-alias") p := testProvider("aws") diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index e6dc575e52..4208eedecb 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -238,6 +238,22 @@ aws_instance.foo: type = aws_instance ` +const testTerraformApplyRefCountStr = ` +aws_instance.bar: + ID = foo + foo = 3 + type = aws_instance + + Dependencies: + aws_instance.foo +aws_instance.foo.0: + ID = foo +aws_instance.foo.1: + ID = foo +aws_instance.foo.2: + ID = foo +` + const testTerraformApplyProviderAliasStr = ` aws_instance.bar: ID = foo diff --git a/terraform/test-fixtures/apply-ref-count/main.tf b/terraform/test-fixtures/apply-ref-count/main.tf new file mode 100644 index 0000000000..8669ba5724 --- /dev/null +++ b/terraform/test-fixtures/apply-ref-count/main.tf @@ -0,0 +1,7 @@ +resource "aws_instance" "foo" { + count = 3 +} + +resource "aws_instance" "bar" { + foo = "${aws_instance.foo.count}" +} From 60f212b73e1cfe7d2dd5416ea4eb34679b0bb13d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 31 Aug 2016 11:54:14 -0700 Subject: [PATCH 3/3] terraform: test for referencing counts that are from vars --- terraform/context_apply_test.go | 28 +++++++++++++++++++ terraform/terraform_test.go | 14 ++++++++++ .../apply-count-variable-ref/main.tf | 11 ++++++++ 3 files changed, 53 insertions(+) create mode 100644 terraform/test-fixtures/apply-count-variable-ref/main.tf diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index 1d7c15f926..c9e09bedcf 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -1156,6 +1156,34 @@ func TestContext2Apply_countVariable(t *testing.T) { } } +func TestContext2Apply_countVariableRef(t *testing.T) { + m := testModule(t, "apply-count-variable-ref") + p := testProvider("aws") + p.ApplyFn = testApplyFn + p.DiffFn = testDiffFn + ctx := testContext2(t, &ContextOpts{ + Module: m, + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(p), + }, + }) + + if _, err := ctx.Plan(); err != nil { + t.Fatalf("err: %s", err) + } + + state, err := ctx.Apply() + if err != nil { + t.Fatalf("err: %s", err) + } + + actual := strings.TrimSpace(state.String()) + expected := strings.TrimSpace(testTerraformApplyCountVariableRefStr) + if actual != expected { + t.Fatalf("bad: \n%s", actual) + } +} + func TestContext2Apply_mapVariableOverride(t *testing.T) { m := testModule(t, "apply-map-var-override") p := testProvider("aws") diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index 4208eedecb..f8244ce00e 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -386,6 +386,20 @@ aws_instance.foo.1: type = aws_instance ` +const testTerraformApplyCountVariableRefStr = ` +aws_instance.bar: + ID = foo + foo = 2 + type = aws_instance + + Dependencies: + aws_instance.foo +aws_instance.foo.0: + ID = foo +aws_instance.foo.1: + ID = foo +` + const testTerraformApplyMinimalStr = ` aws_instance.bar: ID = foo diff --git a/terraform/test-fixtures/apply-count-variable-ref/main.tf b/terraform/test-fixtures/apply-count-variable-ref/main.tf new file mode 100644 index 0000000000..52c70d90d2 --- /dev/null +++ b/terraform/test-fixtures/apply-count-variable-ref/main.tf @@ -0,0 +1,11 @@ +variable "foo" { + default = "2" +} + +resource "aws_instance" "foo" { + count = "${var.foo}" +} + +resource "aws_instance" "bar" { + foo = "${aws_instance.foo.count}" +}