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