diff --git a/builtin/providers/aws/resource_aws_cloudformation_stack.go b/builtin/providers/aws/resource_aws_cloudformation_stack.go index d3c678780..fc9dc3736 100644 --- a/builtin/providers/aws/resource_aws_cloudformation_stack.go +++ b/builtin/providers/aws/resource_aws_cloudformation_stack.go @@ -268,7 +268,7 @@ func resourceAwsCloudFormationStackUpdate(d *schema.ResourceData, meta interface StackName: aws.String(d.Get("name").(string)), } - // Either TemplateBody or TemplateURL are required for each change + // Either TemplateBody, TemplateURL or UsePreviousTemplate are required if v, ok := d.GetOk("template_url"); ok { input.TemplateURL = aws.String(v.(string)) } @@ -276,15 +276,20 @@ func resourceAwsCloudFormationStackUpdate(d *schema.ResourceData, meta interface input.TemplateBody = aws.String(normalizeJson(v.(string))) } - if d.HasChange("capabilities") { - input.Capabilities = expandStringList(d.Get("capabilities").(*schema.Set).List()) + // Capabilities must be present whether they are changed or not + if v, ok := d.GetOk("capabilities"); ok { + input.Capabilities = expandStringList(v.(*schema.Set).List()) } + if d.HasChange("notification_arns") { input.NotificationARNs = expandStringList(d.Get("notification_arns").(*schema.Set).List()) } - if d.HasChange("parameters") { - input.Parameters = expandCloudFormationParameters(d.Get("parameters").(map[string]interface{})) + + // Parameters must be present whether they are changed or not + if v, ok := d.GetOk("parameters"); ok { + input.Parameters = expandCloudFormationParameters(v.(map[string]interface{})) } + if d.HasChange("policy_body") { input.StackPolicyBody = aws.String(normalizeJson(d.Get("policy_body").(string))) } diff --git a/builtin/providers/aws/resource_aws_cloudformation_stack_test.go b/builtin/providers/aws/resource_aws_cloudformation_stack_test.go index f4d21dae8..33da17db2 100644 --- a/builtin/providers/aws/resource_aws_cloudformation_stack_test.go +++ b/builtin/providers/aws/resource_aws_cloudformation_stack_test.go @@ -51,15 +51,46 @@ func TestAccAWSCloudFormation_defaultParams(t *testing.T) { func TestAccAWSCloudFormation_allAttributes(t *testing.T) { var stack cloudformation.Stack + expectedPolicyBody := "{\"Statement\":[{\"Action\":\"Update:*\",\"Effect\":\"Deny\",\"Principal\":\"*\",\"Resource\":\"LogicalResourceId/StaticVPC\"},{\"Action\":\"Update:*\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"*\"}]}" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSCloudFormationDestroy, Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccAWSCloudFormationConfig_allAttributes, + Config: testAccAWSCloudFormationConfig_allAttributesWithBodies, Check: resource.ComposeTestCheckFunc( testAccCheckCloudFormationStackExists("aws_cloudformation_stack.full", &stack), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "name", "tf-full-stack"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "capabilities.#", "1"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "capabilities.1328347040", "CAPABILITY_IAM"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "disable_rollback", "false"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "notification_arns.#", "1"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "parameters.#", "1"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "parameters.VpcCIDR", "10.0.0.0/16"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "policy_body", expectedPolicyBody), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "tags.#", "2"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "tags.First", "Mickey"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "tags.Second", "Mouse"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "timeout_in_minutes", "10"), + ), + }, + resource.TestStep{ + Config: testAccAWSCloudFormationConfig_allAttributesWithBodies_modified, + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudFormationStackExists("aws_cloudformation_stack.full", &stack), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "name", "tf-full-stack"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "capabilities.#", "1"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "capabilities.1328347040", "CAPABILITY_IAM"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "disable_rollback", "false"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "notification_arns.#", "1"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "parameters.#", "1"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "parameters.VpcCIDR", "10.0.0.0/16"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "policy_body", expectedPolicyBody), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "tags.#", "2"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "tags.First", "Mickey"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "tags.Second", "Mouse"), + resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "timeout_in_minutes", "10"), ), }, }, @@ -251,29 +282,79 @@ BODY } ` -var testAccAWSCloudFormationConfig_allAttributes = ` +var testAccAWSCloudFormationConfig_allAttributesWithBodies_tpl = ` resource "aws_cloudformation_stack" "full" { name = "tf-full-stack" template_body = <