Merge pull request #5603 from TimeIncOSS/fix/4913

aws: Fix CloudFormation update for parameters & capabilities if not modified
This commit is contained in:
Radek Simko 2016-03-13 08:23:12 +00:00
commit 0929c88e64
2 changed files with 124 additions and 10 deletions

View File

@ -268,7 +268,7 @@ func resourceAwsCloudFormationStackUpdate(d *schema.ResourceData, meta interface
StackName: aws.String(d.Get("name").(string)), 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 { if v, ok := d.GetOk("template_url"); ok {
input.TemplateURL = aws.String(v.(string)) input.TemplateURL = aws.String(v.(string))
} }
@ -276,15 +276,20 @@ func resourceAwsCloudFormationStackUpdate(d *schema.ResourceData, meta interface
input.TemplateBody = aws.String(normalizeJson(v.(string))) input.TemplateBody = aws.String(normalizeJson(v.(string)))
} }
if d.HasChange("capabilities") { // Capabilities must be present whether they are changed or not
input.Capabilities = expandStringList(d.Get("capabilities").(*schema.Set).List()) if v, ok := d.GetOk("capabilities"); ok {
input.Capabilities = expandStringList(v.(*schema.Set).List())
} }
if d.HasChange("notification_arns") { if d.HasChange("notification_arns") {
input.NotificationARNs = expandStringList(d.Get("notification_arns").(*schema.Set).List()) 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") { if d.HasChange("policy_body") {
input.StackPolicyBody = aws.String(normalizeJson(d.Get("policy_body").(string))) input.StackPolicyBody = aws.String(normalizeJson(d.Get("policy_body").(string)))
} }

View File

@ -51,15 +51,46 @@ func TestAccAWSCloudFormation_defaultParams(t *testing.T) {
func TestAccAWSCloudFormation_allAttributes(t *testing.T) { func TestAccAWSCloudFormation_allAttributes(t *testing.T) {
var stack cloudformation.Stack 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{ resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) }, PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders, Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCloudFormationDestroy, CheckDestroy: testAccCheckAWSCloudFormationDestroy,
Steps: []resource.TestStep{ Steps: []resource.TestStep{
resource.TestStep{ resource.TestStep{
Config: testAccAWSCloudFormationConfig_allAttributes, Config: testAccAWSCloudFormationConfig_allAttributesWithBodies,
Check: resource.ComposeTestCheckFunc( Check: resource.ComposeTestCheckFunc(
testAccCheckCloudFormationStackExists("aws_cloudformation_stack.full", &stack), 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" { resource "aws_cloudformation_stack" "full" {
name = "tf-full-stack" name = "tf-full-stack"
template_body = <<STACK template_body = <<STACK
{ {
"Parameters" : {
"VpcCIDR" : {
"Description" : "CIDR to be used for the VPC",
"Type" : "String"
}
},
"Resources" : { "Resources" : {
"MyVPC": { "MyVPC": {
"Type" : "AWS::EC2::VPC", "Type" : "AWS::EC2::VPC",
"Properties" : { "Properties" : {
"CidrBlock" : "10.0.0.0/16", "CidrBlock" : {"Ref": "VpcCIDR"},
"Tags" : [ "Tags" : [
{"Key": "Name", "Value": "Primary_CF_VPC"} {"Key": "Name", "Value": "%s"}
] ]
} }
},
"StaticVPC": {
"Type" : "AWS::EC2::VPC",
"Properties" : {
"CidrBlock" : {"Ref": "VpcCIDR"},
"Tags" : [
{"Key": "Name", "Value": "Static_CF_VPC"}
]
}
},
"InstanceRole" : {
"Type" : "AWS::IAM::Role",
"Properties" : {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [ {
"Effect": "Allow",
"Principal": { "Service": "ec2.amazonaws.com" },
"Action": "sts:AssumeRole"
} ]
},
"Path" : "/",
"Policies" : [ {
"PolicyName": "terraformtest",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [ {
"Effect": "Allow",
"Action": [ "ec2:DescribeSnapshots" ],
"Resource": [ "*" ]
} ]
}
} ]
}
} }
} }
} }
STACK STACK
parameters {
VpcCIDR = "10.0.0.0/16"
}
policy_body = <<POLICY
%s
POLICY
capabilities = ["CAPABILITY_IAM"] capabilities = ["CAPABILITY_IAM"]
notification_arns = ["${aws_sns_topic.cf-updates.arn}"] notification_arns = ["${aws_sns_topic.cf-updates.arn}"]
on_failure = "DELETE" on_failure = "DELETE"
timeout_in_minutes = 1 timeout_in_minutes = 10
tags {
First = "Mickey"
Second = "Mouse"
}
} }
resource "aws_sns_topic" "cf-updates" { resource "aws_sns_topic" "cf-updates" {
@ -281,6 +362,34 @@ resource "aws_sns_topic" "cf-updates" {
} }
` `
var policyBody = `
{
"Statement" : [
{
"Effect" : "Deny",
"Action" : "Update:*",
"Principal": "*",
"Resource" : "LogicalResourceId/StaticVPC"
},
{
"Effect" : "Allow",
"Action" : "Update:*",
"Principal": "*",
"Resource" : "*"
}
]
}
`
var testAccAWSCloudFormationConfig_allAttributesWithBodies = fmt.Sprintf(
testAccAWSCloudFormationConfig_allAttributesWithBodies_tpl,
"Primary_CF_VPC",
policyBody)
var testAccAWSCloudFormationConfig_allAttributesWithBodies_modified = fmt.Sprintf(
testAccAWSCloudFormationConfig_allAttributesWithBodies_tpl,
"Primary_CloudFormation_VPC",
policyBody)
var tpl_testAccAWSCloudFormationConfig_withParams = ` var tpl_testAccAWSCloudFormationConfig_withParams = `
resource "aws_cloudformation_stack" "with_params" { resource "aws_cloudformation_stack" "with_params" {
name = "tf-stack-with-params" name = "tf-stack-with-params"