github.com/alkar/terraform@v0.9.6-0.20170517124458-a4cddf6ebf59/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 { 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 { 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 { 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 { 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 { 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 { 128 Config: testAccAWSCloudFormationConfig_withParams, 129 Check: resource.ComposeTestCheckFunc( 130 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.with_params", &stack), 131 ), 132 }, 133 { 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 cfRandInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int() 147 cfBucketName := fmt.Sprintf("tf-stack-with-url-and-params-%d", cfRandInt) 148 149 resource.Test(t, resource.TestCase{ 150 PreCheck: func() { testAccPreCheck(t) }, 151 Providers: testAccProviders, 152 CheckDestroy: testAccCheckAWSCloudFormationDestroy, 153 Steps: []resource.TestStep{ 154 { 155 Config: testAccAWSCloudFormationConfig_templateUrl_withParams(cfBucketName, "tf-cf-stack.json", "11.0.0.0/16"), 156 Check: resource.ComposeTestCheckFunc( 157 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.with-url-and-params", &stack), 158 ), 159 }, 160 { 161 Config: testAccAWSCloudFormationConfig_templateUrl_withParams(cfBucketName, "tf-cf-stack.json", "13.0.0.0/16"), 162 Check: resource.ComposeTestCheckFunc( 163 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.with-url-and-params", &stack), 164 ), 165 }, 166 }, 167 }) 168 } 169 170 func TestAccAWSCloudFormation_withUrl_withParams_withYaml(t *testing.T) { 171 var stack cloudformation.Stack 172 cfRandInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int() 173 cfBucketName := fmt.Sprintf("tf-stack-with-url-and-params-%d", cfRandInt) 174 175 resource.Test(t, resource.TestCase{ 176 PreCheck: func() { testAccPreCheck(t) }, 177 Providers: testAccProviders, 178 CheckDestroy: testAccCheckAWSCloudFormationDestroy, 179 Steps: []resource.TestStep{ 180 { 181 Config: testAccAWSCloudFormationConfig_templateUrl_withParams_withYaml(cfBucketName, "tf-cf-stack.yaml", "13.0.0.0/16"), 182 Check: resource.ComposeTestCheckFunc( 183 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.with-url-and-params-and-yaml", &stack), 184 ), 185 }, 186 }, 187 }) 188 } 189 190 // Test for https://github.com/hashicorp/terraform/issues/5653 191 func TestAccAWSCloudFormation_withUrl_withParams_noUpdate(t *testing.T) { 192 var stack cloudformation.Stack 193 cfRandInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int() 194 cfBucketName := fmt.Sprintf("tf-stack-with-url-and-params-%d", cfRandInt) 195 196 resource.Test(t, resource.TestCase{ 197 PreCheck: func() { testAccPreCheck(t) }, 198 Providers: testAccProviders, 199 CheckDestroy: testAccCheckAWSCloudFormationDestroy, 200 Steps: []resource.TestStep{ 201 { 202 Config: testAccAWSCloudFormationConfig_templateUrl_withParams(cfBucketName, "tf-cf-stack-1.json", "11.0.0.0/16"), 203 Check: resource.ComposeTestCheckFunc( 204 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.with-url-and-params", &stack), 205 ), 206 }, 207 { 208 Config: testAccAWSCloudFormationConfig_templateUrl_withParams(cfBucketName, "tf-cf-stack-2.json", "11.0.0.0/16"), 209 Check: resource.ComposeTestCheckFunc( 210 testAccCheckCloudFormationStackExists("aws_cloudformation_stack.with-url-and-params", &stack), 211 ), 212 }, 213 }, 214 }) 215 } 216 217 func testAccCheckCloudFormationStackExists(n string, stack *cloudformation.Stack) resource.TestCheckFunc { 218 return func(s *terraform.State) error { 219 rs, ok := s.RootModule().Resources[n] 220 if !ok { 221 return fmt.Errorf("Not found: %s", n) 222 } 223 224 conn := testAccProvider.Meta().(*AWSClient).cfconn 225 params := &cloudformation.DescribeStacksInput{ 226 StackName: aws.String(rs.Primary.ID), 227 } 228 resp, err := conn.DescribeStacks(params) 229 if err != nil { 230 return err 231 } 232 if len(resp.Stacks) == 0 { 233 return fmt.Errorf("CloudFormation stack not found") 234 } 235 236 return nil 237 } 238 } 239 240 func testAccCheckAWSCloudFormationDestroy(s *terraform.State) error { 241 conn := testAccProvider.Meta().(*AWSClient).cfconn 242 243 for _, rs := range s.RootModule().Resources { 244 if rs.Type != "aws_cloudformation_stack" { 245 continue 246 } 247 248 params := cloudformation.DescribeStacksInput{ 249 StackName: aws.String(rs.Primary.ID), 250 } 251 252 resp, err := conn.DescribeStacks(¶ms) 253 254 if err != nil { 255 return err 256 } 257 258 for _, s := range resp.Stacks { 259 if *s.StackId == rs.Primary.ID && *s.StackStatus != "DELETE_COMPLETE" { 260 return fmt.Errorf("CloudFormation stack still exists: %q", rs.Primary.ID) 261 } 262 } 263 } 264 265 return nil 266 } 267 268 var testAccAWSCloudFormationConfig = ` 269 resource "aws_cloudformation_stack" "network" { 270 name = "tf-networking-stack" 271 template_body = <<STACK 272 { 273 "Resources" : { 274 "MyVPC": { 275 "Type" : "AWS::EC2::VPC", 276 "Properties" : { 277 "CidrBlock" : "10.0.0.0/16", 278 "Tags" : [ 279 {"Key": "Name", "Value": "Primary_CF_VPC"} 280 ] 281 } 282 } 283 }, 284 "Outputs" : { 285 "DefaultSgId" : { 286 "Description": "The ID of default security group", 287 "Value" : { "Fn::GetAtt" : [ "MyVPC", "DefaultSecurityGroup" ]} 288 }, 289 "VpcID" : { 290 "Description": "The VPC ID", 291 "Value" : { "Ref" : "MyVPC" } 292 } 293 } 294 } 295 STACK 296 }` 297 298 var testAccAWSCloudFormationConfig_yaml = ` 299 resource "aws_cloudformation_stack" "yaml" { 300 name = "tf-yaml-stack" 301 template_body = <<STACK 302 Resources: 303 MyVPC: 304 Type: AWS::EC2::VPC 305 Properties: 306 CidrBlock: 10.0.0.0/16 307 Tags: 308 - 309 Key: Name 310 Value: Primary_CF_VPC 311 312 Outputs: 313 DefaultSgId: 314 Description: The ID of default security group 315 Value: !GetAtt MyVPC.DefaultSecurityGroup 316 VpcID: 317 Description: The VPC ID 318 Value: !Ref MyVPC 319 STACK 320 }` 321 322 var testAccAWSCloudFormationConfig_defaultParams = ` 323 resource "aws_cloudformation_stack" "asg-demo" { 324 name = "tf-asg-demo-stack" 325 template_body = <<BODY 326 { 327 "Parameters": { 328 "TopicName": { 329 "Type": "String" 330 }, 331 "VPCCIDR": { 332 "Type": "String", 333 "Default": "10.10.0.0/16" 334 } 335 }, 336 "Resources": { 337 "NotificationTopic": { 338 "Type": "AWS::SNS::Topic", 339 "Properties": { 340 "TopicName": { 341 "Ref": "TopicName" 342 } 343 } 344 }, 345 "MyVPC": { 346 "Type": "AWS::EC2::VPC", 347 "Properties": { 348 "CidrBlock": { 349 "Ref": "VPCCIDR" 350 }, 351 "Tags": [ 352 { 353 "Key": "Name", 354 "Value": "Primary_CF_VPC" 355 } 356 ] 357 } 358 } 359 }, 360 "Outputs": { 361 "VPCCIDR": { 362 "Value": { 363 "Ref": "VPCCIDR" 364 } 365 } 366 } 367 } 368 BODY 369 370 parameters { 371 TopicName = "ExampleTopic" 372 } 373 } 374 ` 375 376 var testAccAWSCloudFormationConfig_allAttributesWithBodies_tpl = ` 377 resource "aws_cloudformation_stack" "full" { 378 name = "tf-full-stack" 379 template_body = <<STACK 380 { 381 "Parameters" : { 382 "VpcCIDR" : { 383 "Description" : "CIDR to be used for the VPC", 384 "Type" : "String" 385 } 386 }, 387 "Resources" : { 388 "MyVPC": { 389 "Type" : "AWS::EC2::VPC", 390 "Properties" : { 391 "CidrBlock" : {"Ref": "VpcCIDR"}, 392 "Tags" : [ 393 {"Key": "Name", "Value": "%s"} 394 ] 395 } 396 }, 397 "StaticVPC": { 398 "Type" : "AWS::EC2::VPC", 399 "Properties" : { 400 "CidrBlock" : {"Ref": "VpcCIDR"}, 401 "Tags" : [ 402 {"Key": "Name", "Value": "Static_CF_VPC"} 403 ] 404 } 405 }, 406 "InstanceRole" : { 407 "Type" : "AWS::IAM::Role", 408 "Properties" : { 409 "AssumeRolePolicyDocument": { 410 "Version": "2012-10-17", 411 "Statement": [ { 412 "Effect": "Allow", 413 "Principal": { "Service": "ec2.amazonaws.com" }, 414 "Action": "sts:AssumeRole" 415 } ] 416 }, 417 "Path" : "/", 418 "Policies" : [ { 419 "PolicyName": "terraformtest", 420 "PolicyDocument": { 421 "Version": "2012-10-17", 422 "Statement": [ { 423 "Effect": "Allow", 424 "Action": [ "ec2:DescribeSnapshots" ], 425 "Resource": [ "*" ] 426 } ] 427 } 428 } ] 429 } 430 } 431 } 432 } 433 STACK 434 parameters { 435 VpcCIDR = "10.0.0.0/16" 436 } 437 438 policy_body = <<POLICY 439 %s 440 POLICY 441 capabilities = ["CAPABILITY_IAM"] 442 notification_arns = ["${aws_sns_topic.cf-updates.arn}"] 443 on_failure = "DELETE" 444 timeout_in_minutes = 10 445 tags { 446 First = "Mickey" 447 Second = "Mouse" 448 } 449 } 450 451 resource "aws_sns_topic" "cf-updates" { 452 name = "tf-cf-notifications" 453 } 454 ` 455 456 var policyBody = ` 457 { 458 "Statement" : [ 459 { 460 "Effect" : "Deny", 461 "Action" : "Update:*", 462 "Principal": "*", 463 "Resource" : "LogicalResourceId/StaticVPC" 464 }, 465 { 466 "Effect" : "Allow", 467 "Action" : "Update:*", 468 "Principal": "*", 469 "Resource" : "*" 470 } 471 ] 472 } 473 ` 474 475 var testAccAWSCloudFormationConfig_allAttributesWithBodies = fmt.Sprintf( 476 testAccAWSCloudFormationConfig_allAttributesWithBodies_tpl, 477 "Primary_CF_VPC", 478 policyBody) 479 var testAccAWSCloudFormationConfig_allAttributesWithBodies_modified = fmt.Sprintf( 480 testAccAWSCloudFormationConfig_allAttributesWithBodies_tpl, 481 "Primary_CloudFormation_VPC", 482 policyBody) 483 484 var tpl_testAccAWSCloudFormationConfig_withParams = ` 485 resource "aws_cloudformation_stack" "with_params" { 486 name = "tf-stack-with-params" 487 parameters { 488 VpcCIDR = "%s" 489 } 490 template_body = <<STACK 491 { 492 "Parameters" : { 493 "VpcCIDR" : { 494 "Description" : "CIDR to be used for the VPC", 495 "Type" : "String" 496 } 497 }, 498 "Resources" : { 499 "MyVPC": { 500 "Type" : "AWS::EC2::VPC", 501 "Properties" : { 502 "CidrBlock" : {"Ref": "VpcCIDR"}, 503 "Tags" : [ 504 {"Key": "Name", "Value": "Primary_CF_VPC"} 505 ] 506 } 507 } 508 } 509 } 510 STACK 511 512 on_failure = "DELETE" 513 timeout_in_minutes = 1 514 } 515 ` 516 517 var testAccAWSCloudFormationConfig_withParams = fmt.Sprintf( 518 tpl_testAccAWSCloudFormationConfig_withParams, 519 "10.0.0.0/16") 520 var testAccAWSCloudFormationConfig_withParams_modified = fmt.Sprintf( 521 tpl_testAccAWSCloudFormationConfig_withParams, 522 "12.0.0.0/16") 523 524 func testAccAWSCloudFormationConfig_templateUrl_withParams(bucketName, bucketKey, vpcCidr string) string { 525 return fmt.Sprintf(` 526 resource "aws_s3_bucket" "b" { 527 bucket = "%s" 528 acl = "public-read" 529 policy = <<POLICY 530 { 531 "Version":"2008-10-17", 532 "Statement": [ 533 { 534 "Sid":"AllowPublicRead", 535 "Effect":"Allow", 536 "Principal": { 537 "AWS": "*" 538 }, 539 "Action": "s3:GetObject", 540 "Resource": "arn:aws:s3:::%s/*" 541 } 542 ] 543 } 544 POLICY 545 546 website { 547 index_document = "index.html" 548 error_document = "error.html" 549 } 550 } 551 552 resource "aws_s3_bucket_object" "object" { 553 bucket = "${aws_s3_bucket.b.id}" 554 key = "%s" 555 source = "test-fixtures/cloudformation-template.json" 556 } 557 558 resource "aws_cloudformation_stack" "with-url-and-params" { 559 name = "tf-stack-template-url-with-params" 560 parameters { 561 VpcCIDR = "%s" 562 } 563 template_url = "https://${aws_s3_bucket.b.id}.s3-us-west-2.amazonaws.com/${aws_s3_bucket_object.object.key}" 564 on_failure = "DELETE" 565 timeout_in_minutes = 1 566 } 567 `, bucketName, bucketName, bucketKey, vpcCidr) 568 } 569 570 func testAccAWSCloudFormationConfig_templateUrl_withParams_withYaml(bucketName, bucketKey, vpcCidr string) string { 571 return fmt.Sprintf(` 572 resource "aws_s3_bucket" "b" { 573 bucket = "%s" 574 acl = "public-read" 575 policy = <<POLICY 576 { 577 "Version":"2008-10-17", 578 "Statement": [ 579 { 580 "Sid":"AllowPublicRead", 581 "Effect":"Allow", 582 "Principal": { 583 "AWS": "*" 584 }, 585 "Action": "s3:GetObject", 586 "Resource": "arn:aws:s3:::%s/*" 587 } 588 ] 589 } 590 POLICY 591 592 website { 593 index_document = "index.html" 594 error_document = "error.html" 595 } 596 } 597 598 resource "aws_s3_bucket_object" "object" { 599 bucket = "${aws_s3_bucket.b.id}" 600 key = "%s" 601 source = "test-fixtures/cloudformation-template.yaml" 602 } 603 604 resource "aws_cloudformation_stack" "with-url-and-params-and-yaml" { 605 name = "tf-stack-template-url-with-params-and-yaml" 606 parameters { 607 VpcCIDR = "%s" 608 } 609 template_url = "https://${aws_s3_bucket.b.id}.s3-us-west-2.amazonaws.com/${aws_s3_bucket_object.object.key}" 610 on_failure = "DELETE" 611 timeout_in_minutes = 1 612 } 613 `, bucketName, bucketName, bucketKey, vpcCidr) 614 }