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(&params)
   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")