diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index 2bd97fd05..0462096ba 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 b42ca8211..2117fc3f0 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 000000000..c8b83d7c0 --- /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}" + } +}