github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/aws/resource_aws_cloudformation_stack_test.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "math/rand" 6 "testing" 7 "time" 8 9 "github.com/aws/aws-sdk-go/aws" 10 "github.com/aws/aws-sdk-go/service/cloudformation" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/terraform" 13 ) 14 15 func TestAccAWSCloudFormation_basic(t *testing.T) { 16 var stack cloudformation.Stack 17 18 resource.Test(t, resource.TestCase{ 19 PreCheck: func() { testAccPreCheck(t) }, 20 Providers: testAccProviders, 21 CheckDestroy: testAccCheckAWSCloudFormationDestroy, 22 Steps: []resource.TestStep{ 23 resource.TestStep{ 24 Config: testAccAWSCloudFormationConfig, 25 Check: resource.ComposeTestCheckFunc( 26 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.network", &stack), 27 ), 28 }, 29 }, 30 }) 31 } 32 33 func TestAccAWSCloudFormation_yaml(t *testing.T) { 34 var stack cloudformation.Stack 35 36 resource.Test(t, resource.TestCase{ 37 PreCheck: func() { testAccPreCheck(t) }, 38 Providers: testAccProviders, 39 CheckDestroy: testAccCheckAWSCloudFormationDestroy, 40 Steps: []resource.TestStep{ 41 resource.TestStep{ 42 Config: testAccAWSCloudFormationConfig_yaml, 43 Check: resource.ComposeTestCheckFunc( 44 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.yaml", &stack), 45 ), 46 }, 47 }, 48 }) 49 } 50 51 func TestAccAWSCloudFormation_defaultParams(t *testing.T) { 52 var stack cloudformation.Stack 53 54 resource.Test(t, resource.TestCase{ 55 PreCheck: func() { testAccPreCheck(t) }, 56 Providers: testAccProviders, 57 CheckDestroy: testAccCheckAWSCloudFormationDestroy, 58 Steps: []resource.TestStep{ 59 resource.TestStep{ 60 Config: testAccAWSCloudFormationConfig_defaultParams, 61 Check: resource.ComposeTestCheckFunc( 62 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.asg-demo", &stack), 63 ), 64 }, 65 }, 66 }) 67 } 68 69 func TestAccAWSCloudFormation_allAttributes(t *testing.T) { 70 var stack cloudformation.Stack 71 72 expectedPolicyBody := "{\"Statement\":[{\"Action\":\"Update:*\",\"Effect\":\"Deny\",\"Principal\":\"*\",\"Resource\":\"LogicalResourceId/StaticVPC\"},{\"Action\":\"Update:*\",\"Effect\":\"Allow\",\"Principal\":\"*\",\"Resource\":\"*\"}]}" 73 resource.Test(t, resource.TestCase{ 74 PreCheck: func() { testAccPreCheck(t) }, 75 Providers: testAccProviders, 76 CheckDestroy: testAccCheckAWSCloudFormationDestroy, 77 Steps: []resource.TestStep{ 78 resource.TestStep{ 79 Config: testAccAWSCloudFormationConfig_allAttributesWithBodies, 80 Check: resource.ComposeTestCheckFunc( 81 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.full", &stack), 82 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "name", "tf-full-stack"), 83 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "capabilities.#", "1"), 84 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "capabilities.1328347040", "CAPABILITY_IAM"), 85 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "disable_rollback", "false"), 86 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "notification_arns.#", "1"), 87 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "parameters.%", "1"), 88 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "parameters.VpcCIDR", "10.0.0.0/16"), 89 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "policy_body", expectedPolicyBody), 90 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "tags.%", "2"), 91 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "tags.First", "Mickey"), 92 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "tags.Second", "Mouse"), 93 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "timeout_in_minutes", "10"), 94 ), 95 }, 96 resource.TestStep{ 97 Config: testAccAWSCloudFormationConfig_allAttributesWithBodies_modified, 98 Check: resource.ComposeTestCheckFunc( 99 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.full", &stack), 100 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "name", "tf-full-stack"), 101 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "capabilities.#", "1"), 102 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "capabilities.1328347040", "CAPABILITY_IAM"), 103 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "disable_rollback", "false"), 104 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "notification_arns.#", "1"), 105 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "parameters.%", "1"), 106 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "parameters.VpcCIDR", "10.0.0.0/16"), 107 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "policy_body", expectedPolicyBody), 108 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "tags.%", "2"), 109 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "tags.First", "Mickey"), 110 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "tags.Second", "Mouse"), 111 resource.TestCheckResourceAttr("aws_cloudformation_stack.full", "timeout_in_minutes", "10"), 112 ), 113 }, 114 }, 115 }) 116 } 117 118 // Regression for https://github.com/hashicorp/terraform/issues/4332 119 func TestAccAWSCloudFormation_withParams(t *testing.T) { 120 var stack cloudformation.Stack 121 122 resource.Test(t, resource.TestCase{ 123 PreCheck: func() { testAccPreCheck(t) }, 124 Providers: testAccProviders, 125 CheckDestroy: testAccCheckAWSCloudFormationDestroy, 126 Steps: []resource.TestStep{ 127 resource.TestStep{ 128 Config: testAccAWSCloudFormationConfig_withParams, 129 Check: resource.ComposeTestCheckFunc( 130 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.with_params", &stack), 131 ), 132 }, 133 resource.TestStep{ 134 Config: testAccAWSCloudFormationConfig_withParams_modified, 135 Check: resource.ComposeTestCheckFunc( 136 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.with_params", &stack), 137 ), 138 }, 139 }, 140 }) 141 } 142 143 // Regression for https://github.com/hashicorp/terraform/issues/4534 144 func TestAccAWSCloudFormation_withUrl_withParams(t *testing.T) { 145 var stack cloudformation.Stack 146 147 resource.Test(t, resource.TestCase{ 148 PreCheck: func() { testAccPreCheck(t) }, 149 Providers: testAccProviders, 150 CheckDestroy: testAccCheckAWSCloudFormationDestroy, 151 Steps: []resource.TestStep{ 152 resource.TestStep{ 153 Config: testAccAWSCloudFormationConfig_templateUrl_withParams, 154 Check: resource.ComposeTestCheckFunc( 155 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.with-url-and-params", &stack), 156 ), 157 }, 158 resource.TestStep{ 159 Config: testAccAWSCloudFormationConfig_templateUrl_withParams_modified, 160 Check: resource.ComposeTestCheckFunc( 161 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.with-url-and-params", &stack), 162 ), 163 }, 164 }, 165 }) 166 } 167 168 func TestAccAWSCloudFormation_withUrl_withParams_withYaml(t *testing.T) { 169 var stack cloudformation.Stack 170 171 resource.Test(t, resource.TestCase{ 172 PreCheck: func() { testAccPreCheck(t) }, 173 Providers: testAccProviders, 174 CheckDestroy: testAccCheckAWSCloudFormationDestroy, 175 Steps: []resource.TestStep{ 176 resource.TestStep{ 177 Config: testAccAWSCloudFormationConfig_templateUrl_withParams_withYaml, 178 Check: resource.ComposeTestCheckFunc( 179 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.with-url-and-params-and-yaml", &stack), 180 ), 181 }, 182 }, 183 }) 184 } 185 186 func testAccCheckCloudFormationStackExists(n string, stack *cloudformation.Stack) resource.TestCheckFunc { 187 return func(s *terraform.State) error { 188 rs, ok := s.RootModule().Resources[n] 189 if !ok { 190 return fmt.Errorf("Not found: %s", n) 191 } 192 193 conn := testAccProvider.Meta().(*AWSClient).cfconn 194 params := &cloudformation.DescribeStacksInput{ 195 StackName: aws.String(rs.Primary.ID), 196 } 197 resp, err := conn.DescribeStacks(params) 198 if err != nil { 199 return err 200 } 201 if len(resp.Stacks) == 0 { 202 return fmt.Errorf("CloudFormation stack not found") 203 } 204 205 return nil 206 } 207 } 208 209 func testAccCheckAWSCloudFormationDestroy(s *terraform.State) error { 210 conn := testAccProvider.Meta().(*AWSClient).cfconn 211 212 for _, rs := range s.RootModule().Resources { 213 if rs.Type != "aws_cloudformation_stack" { 214 continue 215 } 216 217 params := cloudformation.DescribeStacksInput{ 218 StackName: aws.String(rs.Primary.ID), 219 } 220 221 resp, err := conn.DescribeStacks(¶ms) 222 223 if err != nil { 224 return err 225 } 226 227 for _, s := range resp.Stacks { 228 if *s.StackId == rs.Primary.ID && *s.StackStatus != "DELETE_COMPLETE" { 229 return fmt.Errorf("CloudFormation stack still exists: %q", rs.Primary.ID) 230 } 231 } 232 } 233 234 return nil 235 } 236 237 var testAccAWSCloudFormationConfig = ` 238 resource "aws_cloudformation_stack" "network" { 239 name = "tf-networking-stack" 240 template_body = <<STACK 241 { 242 "Resources" : { 243 "MyVPC": { 244 "Type" : "AWS::EC2::VPC", 245 "Properties" : { 246 "CidrBlock" : "10.0.0.0/16", 247 "Tags" : [ 248 {"Key": "Name", "Value": "Primary_CF_VPC"} 249 ] 250 } 251 } 252 }, 253 "Outputs" : { 254 "DefaultSgId" : { 255 "Description": "The ID of default security group", 256 "Value" : { "Fn::GetAtt" : [ "MyVPC", "DefaultSecurityGroup" ]} 257 }, 258 "VpcID" : { 259 "Description": "The VPC ID", 260 "Value" : { "Ref" : "MyVPC" } 261 } 262 } 263 } 264 STACK 265 }` 266 267 var testAccAWSCloudFormationConfig_yaml = ` 268 resource "aws_cloudformation_stack" "yaml" { 269 name = "tf-yaml-stack" 270 template_body = <<STACK 271 Resources: 272 MyVPC: 273 Type: AWS::EC2::VPC 274 Properties: 275 CidrBlock: 10.0.0.0/16 276 Tags: 277 - 278 Key: Name 279 Value: Primary_CF_VPC 280 281 Outputs: 282 DefaultSgId: 283 Description: The ID of default security group 284 Value: !GetAtt MyVPC.DefaultSecurityGroup 285 VpcID: 286 Description: The VPC ID 287 Value: !Ref MyVPC 288 STACK 289 }` 290 291 var testAccAWSCloudFormationConfig_defaultParams = ` 292 resource "aws_cloudformation_stack" "asg-demo" { 293 name = "tf-asg-demo-stack" 294 template_body = <<BODY 295 { 296 "Parameters": { 297 "TopicName": { 298 "Type": "String" 299 }, 300 "VPCCIDR": { 301 "Type": "String", 302 "Default": "10.10.0.0/16" 303 } 304 }, 305 "Resources": { 306 "NotificationTopic": { 307 "Type": "AWS::SNS::Topic", 308 "Properties": { 309 "TopicName": { 310 "Ref": "TopicName" 311 } 312 } 313 }, 314 "MyVPC": { 315 "Type": "AWS::EC2::VPC", 316 "Properties": { 317 "CidrBlock": { 318 "Ref": "VPCCIDR" 319 }, 320 "Tags": [ 321 { 322 "Key": "Name", 323 "Value": "Primary_CF_VPC" 324 } 325 ] 326 } 327 } 328 }, 329 "Outputs": { 330 "VPCCIDR": { 331 "Value": { 332 "Ref": "VPCCIDR" 333 } 334 } 335 } 336 } 337 BODY 338 339 parameters { 340 TopicName = "ExampleTopic" 341 } 342 } 343 ` 344 345 var testAccAWSCloudFormationConfig_allAttributesWithBodies_tpl = ` 346 resource "aws_cloudformation_stack" "full" { 347 name = "tf-full-stack" 348 template_body = <<STACK 349 { 350 "Parameters" : { 351 "VpcCIDR" : { 352 "Description" : "CIDR to be used for the VPC", 353 "Type" : "String" 354 } 355 }, 356 "Resources" : { 357 "MyVPC": { 358 "Type" : "AWS::EC2::VPC", 359 "Properties" : { 360 "CidrBlock" : {"Ref": "VpcCIDR"}, 361 "Tags" : [ 362 {"Key": "Name", "Value": "%s"} 363 ] 364 } 365 }, 366 "StaticVPC": { 367 "Type" : "AWS::EC2::VPC", 368 "Properties" : { 369 "CidrBlock" : {"Ref": "VpcCIDR"}, 370 "Tags" : [ 371 {"Key": "Name", "Value": "Static_CF_VPC"} 372 ] 373 } 374 }, 375 "InstanceRole" : { 376 "Type" : "AWS::IAM::Role", 377 "Properties" : { 378 "AssumeRolePolicyDocument": { 379 "Version": "2012-10-17", 380 "Statement": [ { 381 "Effect": "Allow", 382 "Principal": { "Service": "ec2.amazonaws.com" }, 383 "Action": "sts:AssumeRole" 384 } ] 385 }, 386 "Path" : "/", 387 "Policies" : [ { 388 "PolicyName": "terraformtest", 389 "PolicyDocument": { 390 "Version": "2012-10-17", 391 "Statement": [ { 392 "Effect": "Allow", 393 "Action": [ "ec2:DescribeSnapshots" ], 394 "Resource": [ "*" ] 395 } ] 396 } 397 } ] 398 } 399 } 400 } 401 } 402 STACK 403 parameters { 404 VpcCIDR = "10.0.0.0/16" 405 } 406 407 policy_body = <<POLICY 408 %s 409 POLICY 410 capabilities = ["CAPABILITY_IAM"] 411 notification_arns = ["${aws_sns_topic.cf-updates.arn}"] 412 on_failure = "DELETE" 413 timeout_in_minutes = 10 414 tags { 415 First = "Mickey" 416 Second = "Mouse" 417 } 418 } 419 420 resource "aws_sns_topic" "cf-updates" { 421 name = "tf-cf-notifications" 422 } 423 ` 424 425 var policyBody = ` 426 { 427 "Statement" : [ 428 { 429 "Effect" : "Deny", 430 "Action" : "Update:*", 431 "Principal": "*", 432 "Resource" : "LogicalResourceId/StaticVPC" 433 }, 434 { 435 "Effect" : "Allow", 436 "Action" : "Update:*", 437 "Principal": "*", 438 "Resource" : "*" 439 } 440 ] 441 } 442 ` 443 444 var testAccAWSCloudFormationConfig_allAttributesWithBodies = fmt.Sprintf( 445 testAccAWSCloudFormationConfig_allAttributesWithBodies_tpl, 446 "Primary_CF_VPC", 447 policyBody) 448 var testAccAWSCloudFormationConfig_allAttributesWithBodies_modified = fmt.Sprintf( 449 testAccAWSCloudFormationConfig_allAttributesWithBodies_tpl, 450 "Primary_CloudFormation_VPC", 451 policyBody) 452 453 var tpl_testAccAWSCloudFormationConfig_withParams = ` 454 resource "aws_cloudformation_stack" "with_params" { 455 name = "tf-stack-with-params" 456 parameters { 457 VpcCIDR = "%s" 458 } 459 template_body = <<STACK 460 { 461 "Parameters" : { 462 "VpcCIDR" : { 463 "Description" : "CIDR to be used for the VPC", 464 "Type" : "String" 465 } 466 }, 467 "Resources" : { 468 "MyVPC": { 469 "Type" : "AWS::EC2::VPC", 470 "Properties" : { 471 "CidrBlock" : {"Ref": "VpcCIDR"}, 472 "Tags" : [ 473 {"Key": "Name", "Value": "Primary_CF_VPC"} 474 ] 475 } 476 } 477 } 478 } 479 STACK 480 481 on_failure = "DELETE" 482 timeout_in_minutes = 1 483 } 484 ` 485 486 var testAccAWSCloudFormationConfig_withParams = fmt.Sprintf( 487 tpl_testAccAWSCloudFormationConfig_withParams, 488 "10.0.0.0/16") 489 var testAccAWSCloudFormationConfig_withParams_modified = fmt.Sprintf( 490 tpl_testAccAWSCloudFormationConfig_withParams, 491 "12.0.0.0/16") 492 493 var tpl_testAccAWSCloudFormationConfig_templateUrl_withParams = ` 494 resource "aws_s3_bucket" "b" { 495 bucket = "%s" 496 acl = "public-read" 497 policy = <<POLICY 498 { 499 "Version":"2008-10-17", 500 "Statement": [ 501 { 502 "Sid":"AllowPublicRead", 503 "Effect":"Allow", 504 "Principal": { 505 "AWS": "*" 506 }, 507 "Action": "s3:GetObject", 508 "Resource": "arn:aws:s3:::%s/*" 509 } 510 ] 511 } 512 POLICY 513 514 website { 515 index_document = "index.html" 516 error_document = "error.html" 517 } 518 } 519 520 resource "aws_s3_bucket_object" "object" { 521 bucket = "${aws_s3_bucket.b.id}" 522 key = "tf-cf-stack.json" 523 source = "test-fixtures/cloudformation-template.json" 524 } 525 526 resource "aws_cloudformation_stack" "with-url-and-params" { 527 name = "tf-stack-template-url-with-params" 528 parameters { 529 VpcCIDR = "%s" 530 } 531 template_url = "https://${aws_s3_bucket.b.id}.s3-us-west-2.amazonaws.com/${aws_s3_bucket_object.object.key}" 532 on_failure = "DELETE" 533 timeout_in_minutes = 1 534 } 535 ` 536 537 var tpl_testAccAWSCloudFormationConfig_templateUrl_withParams_withYaml = ` 538 resource "aws_s3_bucket" "b" { 539 bucket = "%s" 540 acl = "public-read" 541 policy = <<POLICY 542 { 543 "Version":"2008-10-17", 544 "Statement": [ 545 { 546 "Sid":"AllowPublicRead", 547 "Effect":"Allow", 548 "Principal": { 549 "AWS": "*" 550 }, 551 "Action": "s3:GetObject", 552 "Resource": "arn:aws:s3:::%s/*" 553 } 554 ] 555 } 556 POLICY 557 558 website { 559 index_document = "index.html" 560 error_document = "error.html" 561 } 562 } 563 564 resource "aws_s3_bucket_object" "object" { 565 bucket = "${aws_s3_bucket.b.id}" 566 key = "tf-cf-stack.yaml" 567 source = "test-fixtures/cloudformation-template.yaml" 568 } 569 570 resource "aws_cloudformation_stack" "with-url-and-params-and-yaml" { 571 name = "tf-stack-template-url-with-params-and-yaml" 572 parameters { 573 VpcCIDR = "%s" 574 } 575 template_url = "https://${aws_s3_bucket.b.id}.s3-us-west-2.amazonaws.com/${aws_s3_bucket_object.object.key}" 576 on_failure = "DELETE" 577 timeout_in_minutes = 1 578 } 579 ` 580 581 var cfRandInt = rand.New(rand.NewSource(time.Now().UnixNano())).Int() 582 var cfBucketName = "tf-stack-with-url-and-params-" + fmt.Sprintf("%d", cfRandInt) 583 584 var testAccAWSCloudFormationConfig_templateUrl_withParams = fmt.Sprintf( 585 tpl_testAccAWSCloudFormationConfig_templateUrl_withParams, 586 cfBucketName, cfBucketName, "11.0.0.0/16") 587 var testAccAWSCloudFormationConfig_templateUrl_withParams_modified = fmt.Sprintf( 588 tpl_testAccAWSCloudFormationConfig_templateUrl_withParams, 589 cfBucketName, cfBucketName, "13.0.0.0/16") 590 var testAccAWSCloudFormationConfig_templateUrl_withParams_withYaml = fmt.Sprintf( 591 tpl_testAccAWSCloudFormationConfig_templateUrl_withParams_withYaml, 592 cfBucketName, cfBucketName, "13.0.0.0/16")