Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
0527e88d46
541 changed files with 75504 additions and 51429 deletions
|
|
@ -1,9 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
template = {
|
||||
"Resources": {
|
||||
"EC2EIP": {
|
||||
"Type": "AWS::EC2::EIP"
|
||||
}
|
||||
}
|
||||
}
|
||||
template = {"Resources": {"EC2EIP": {"Type": "AWS::EC2::EIP"}}}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,11 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
template = {
|
||||
"Resources": {
|
||||
"EC2EIP": {
|
||||
"Type": "AWS::EC2::EIP"
|
||||
}
|
||||
},
|
||||
"Resources": {"EC2EIP": {"Type": "AWS::EC2::EIP"}},
|
||||
"Outputs": {
|
||||
"EIP": {
|
||||
"Description": "EIP for joining",
|
||||
"Value": {
|
||||
"Fn::Join": [
|
||||
":",
|
||||
[
|
||||
"test eip",
|
||||
{"Ref": "EC2EIP"}
|
||||
]
|
||||
]
|
||||
}
|
||||
"Value": {"Fn::Join": [":", ["test eip", {"Ref": "EC2EIP"}]]},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,38 +2,45 @@ from __future__ import unicode_literals
|
|||
|
||||
template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
|
||||
"Description": "AWS CloudFormation Sample Template to create a KMS Key. The Fn::GetAtt is used to retrieve the ARN",
|
||||
|
||||
"Resources" : {
|
||||
"myKey" : {
|
||||
"Type" : "AWS::KMS::Key",
|
||||
"Properties" : {
|
||||
"Resources": {
|
||||
"myKey": {
|
||||
"Type": "AWS::KMS::Key",
|
||||
"Properties": {
|
||||
"Description": "Sample KmsKey",
|
||||
"EnableKeyRotation": False,
|
||||
"Enabled": True,
|
||||
"KeyPolicy" : {
|
||||
"KeyPolicy": {
|
||||
"Version": "2012-10-17",
|
||||
"Id": "key-default-1",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Enable IAM User Permissions",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": { "Fn::Join" : ["" , ["arn:aws:iam::", {"Ref" : "AWS::AccountId"} ,":root" ]] }
|
||||
},
|
||||
"Action": "kms:*",
|
||||
"Resource": "*"
|
||||
"Sid": "Enable IAM User Permissions",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": {
|
||||
"Fn::Join": [
|
||||
"",
|
||||
[
|
||||
"arn:aws:iam::",
|
||||
{"Ref": "AWS::AccountId"},
|
||||
":root",
|
||||
],
|
||||
]
|
||||
}
|
||||
},
|
||||
"Action": "kms:*",
|
||||
"Resource": "*",
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
"Outputs" : {
|
||||
"KeyArn" : {
|
||||
"Outputs": {
|
||||
"KeyArn": {
|
||||
"Description": "Generated Key Arn",
|
||||
"Value" : { "Fn::GetAtt" : [ "myKey", "Arn" ] }
|
||||
"Value": {"Fn::GetAtt": ["myKey", "Arn"]},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ from __future__ import unicode_literals
|
|||
|
||||
template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
|
||||
"Description": "AWS CloudFormation Sample Template RDS_MySQL_With_Read_Replica: Sample template showing how to create a highly-available, RDS DBInstance with a read replica. **WARNING** This template creates an Amazon Relational Database Service database instance and Amazon CloudWatch alarms. You will be billed for the AWS resources used if you create a stack from this template.",
|
||||
|
||||
"Parameters": {
|
||||
"DBName": {
|
||||
"Default": "MyDatabase",
|
||||
|
|
@ -13,13 +11,9 @@ template = {
|
|||
"MinLength": "1",
|
||||
"MaxLength": "64",
|
||||
"AllowedPattern": "[a-zA-Z][a-zA-Z0-9]*",
|
||||
"ConstraintDescription": "must begin with a letter and contain only alphanumeric characters."
|
||||
"ConstraintDescription": "must begin with a letter and contain only alphanumeric characters.",
|
||||
},
|
||||
|
||||
"DBInstanceIdentifier": {
|
||||
"Type": "String"
|
||||
},
|
||||
|
||||
"DBInstanceIdentifier": {"Type": "String"},
|
||||
"DBUser": {
|
||||
"NoEcho": "true",
|
||||
"Description": "The database admin account username",
|
||||
|
|
@ -27,9 +21,8 @@ template = {
|
|||
"MinLength": "1",
|
||||
"MaxLength": "16",
|
||||
"AllowedPattern": "[a-zA-Z][a-zA-Z0-9]*",
|
||||
"ConstraintDescription": "must begin with a letter and contain only alphanumeric characters."
|
||||
"ConstraintDescription": "must begin with a letter and contain only alphanumeric characters.",
|
||||
},
|
||||
|
||||
"DBPassword": {
|
||||
"NoEcho": "true",
|
||||
"Description": "The database admin account password",
|
||||
|
|
@ -37,112 +30,121 @@ template = {
|
|||
"MinLength": "1",
|
||||
"MaxLength": "41",
|
||||
"AllowedPattern": "[a-zA-Z0-9]+",
|
||||
"ConstraintDescription": "must contain only alphanumeric characters."
|
||||
"ConstraintDescription": "must contain only alphanumeric characters.",
|
||||
},
|
||||
|
||||
"DBAllocatedStorage": {
|
||||
"Default": "5",
|
||||
"Description": "The size of the database (Gb)",
|
||||
"Type": "Number",
|
||||
"MinValue": "5",
|
||||
"MaxValue": "1024",
|
||||
"ConstraintDescription": "must be between 5 and 1024Gb."
|
||||
"ConstraintDescription": "must be between 5 and 1024Gb.",
|
||||
},
|
||||
|
||||
"DBInstanceClass": {
|
||||
"Description": "The database instance type",
|
||||
"Type": "String",
|
||||
"Default": "db.m1.small",
|
||||
"AllowedValues": ["db.t1.micro", "db.m1.small", "db.m1.medium", "db.m1.large", "db.m1.xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge", "db.m3.medium", "db.m3.large", "db.m3.xlarge", "db.m3.2xlarge", "db.r3.large", "db.r3.xlarge", "db.r3.2xlarge", "db.r3.4xlarge", "db.r3.8xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge", "db.cr1.8xlarge"],
|
||||
"ConstraintDescription": "must select a valid database instance type."
|
||||
"AllowedValues": [
|
||||
"db.t1.micro",
|
||||
"db.m1.small",
|
||||
"db.m1.medium",
|
||||
"db.m1.large",
|
||||
"db.m1.xlarge",
|
||||
"db.m2.xlarge",
|
||||
"db.m2.2xlarge",
|
||||
"db.m2.4xlarge",
|
||||
"db.m3.medium",
|
||||
"db.m3.large",
|
||||
"db.m3.xlarge",
|
||||
"db.m3.2xlarge",
|
||||
"db.r3.large",
|
||||
"db.r3.xlarge",
|
||||
"db.r3.2xlarge",
|
||||
"db.r3.4xlarge",
|
||||
"db.r3.8xlarge",
|
||||
"db.m2.xlarge",
|
||||
"db.m2.2xlarge",
|
||||
"db.m2.4xlarge",
|
||||
"db.cr1.8xlarge",
|
||||
],
|
||||
"ConstraintDescription": "must select a valid database instance type.",
|
||||
},
|
||||
|
||||
"EC2SecurityGroup": {
|
||||
"Description": "The EC2 security group that contains instances that need access to the database",
|
||||
"Default": "default",
|
||||
"Type": "String",
|
||||
"AllowedPattern": "[a-zA-Z0-9\\-]+",
|
||||
"ConstraintDescription": "must be a valid security group name."
|
||||
"ConstraintDescription": "must be a valid security group name.",
|
||||
},
|
||||
|
||||
"MultiAZ": {
|
||||
"Description": "Multi-AZ master database",
|
||||
"Type": "String",
|
||||
"Default": "false",
|
||||
"AllowedValues": ["true", "false"],
|
||||
"ConstraintDescription": "must be true or false."
|
||||
}
|
||||
"ConstraintDescription": "must be true or false.",
|
||||
},
|
||||
},
|
||||
|
||||
"Conditions": {
|
||||
"Is-EC2-VPC": {"Fn::Or": [{"Fn::Equals": [{"Ref": "AWS::Region"}, "eu-central-1"]},
|
||||
{"Fn::Equals": [{"Ref": "AWS::Region"}, "cn-north-1"]}]},
|
||||
"Is-EC2-Classic": {"Fn::Not": [{"Condition": "Is-EC2-VPC"}]}
|
||||
"Is-EC2-VPC": {
|
||||
"Fn::Or": [
|
||||
{"Fn::Equals": [{"Ref": "AWS::Region"}, "eu-central-1"]},
|
||||
{"Fn::Equals": [{"Ref": "AWS::Region"}, "cn-north-1"]},
|
||||
]
|
||||
},
|
||||
"Is-EC2-Classic": {"Fn::Not": [{"Condition": "Is-EC2-VPC"}]},
|
||||
},
|
||||
|
||||
"Resources": {
|
||||
"DBParameterGroup": {
|
||||
"Type": "AWS::RDS::DBParameterGroup",
|
||||
"Properties": {
|
||||
"Description": "DB Parameter Goup",
|
||||
"Family": "MySQL5.1",
|
||||
"Parameters": {
|
||||
"BACKLOG_QUEUE_LIMIT": "2048"
|
||||
}
|
||||
}
|
||||
"Parameters": {"BACKLOG_QUEUE_LIMIT": "2048"},
|
||||
},
|
||||
},
|
||||
|
||||
"DBEC2SecurityGroup": {
|
||||
"Type": "AWS::EC2::SecurityGroup",
|
||||
"Condition": "Is-EC2-VPC",
|
||||
"Properties": {
|
||||
"GroupDescription": "Open database for access",
|
||||
"SecurityGroupIngress": [{
|
||||
"IpProtocol": "tcp",
|
||||
"FromPort": "3306",
|
||||
"ToPort": "3306",
|
||||
"SourceSecurityGroupName": {"Ref": "EC2SecurityGroup"}
|
||||
}]
|
||||
}
|
||||
"SecurityGroupIngress": [
|
||||
{
|
||||
"IpProtocol": "tcp",
|
||||
"FromPort": "3306",
|
||||
"ToPort": "3306",
|
||||
"SourceSecurityGroupName": {"Ref": "EC2SecurityGroup"},
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
"DBSecurityGroup": {
|
||||
"Type": "AWS::RDS::DBSecurityGroup",
|
||||
"Condition": "Is-EC2-Classic",
|
||||
"Properties": {
|
||||
"DBSecurityGroupIngress": [{
|
||||
"EC2SecurityGroupName": {"Ref": "EC2SecurityGroup"}
|
||||
}],
|
||||
"GroupDescription": "database access"
|
||||
}
|
||||
"DBSecurityGroupIngress": [
|
||||
{"EC2SecurityGroupName": {"Ref": "EC2SecurityGroup"}}
|
||||
],
|
||||
"GroupDescription": "database access",
|
||||
},
|
||||
},
|
||||
|
||||
"my_vpc": {
|
||||
"Type": "AWS::EC2::VPC",
|
||||
"Properties": {
|
||||
"CidrBlock": "10.0.0.0/16",
|
||||
}
|
||||
},
|
||||
|
||||
"my_vpc": {"Type": "AWS::EC2::VPC", "Properties": {"CidrBlock": "10.0.0.0/16"}},
|
||||
"EC2Subnet": {
|
||||
"Type": "AWS::EC2::Subnet",
|
||||
"Condition": "Is-EC2-VPC",
|
||||
"Properties": {
|
||||
"AvailabilityZone": "eu-central-1a",
|
||||
"CidrBlock": "10.0.1.0/24",
|
||||
"VpcId": {"Ref": "my_vpc"}
|
||||
}
|
||||
"VpcId": {"Ref": "my_vpc"},
|
||||
},
|
||||
},
|
||||
|
||||
"DBSubnet": {
|
||||
"Type": "AWS::RDS::DBSubnetGroup",
|
||||
"Condition": "Is-EC2-VPC",
|
||||
"Properties": {
|
||||
"DBSubnetGroupDescription": "my db subnet group",
|
||||
"SubnetIds": [{"Ref": "EC2Subnet"}],
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
"MasterDB": {
|
||||
"Type": "AWS::RDS::DBInstance",
|
||||
"Properties": {
|
||||
|
|
@ -151,54 +153,79 @@ template = {
|
|||
"AllocatedStorage": {"Ref": "DBAllocatedStorage"},
|
||||
"DBInstanceClass": {"Ref": "DBInstanceClass"},
|
||||
"Engine": "MySQL",
|
||||
"DBSubnetGroupName": {"Fn::If": ["Is-EC2-VPC", {"Ref": "DBSubnet"}, {"Ref": "AWS::NoValue"}]},
|
||||
"DBSubnetGroupName": {
|
||||
"Fn::If": [
|
||||
"Is-EC2-VPC",
|
||||
{"Ref": "DBSubnet"},
|
||||
{"Ref": "AWS::NoValue"},
|
||||
]
|
||||
},
|
||||
"MasterUsername": {"Ref": "DBUser"},
|
||||
"MasterUserPassword": {"Ref": "DBPassword"},
|
||||
"MultiAZ": {"Ref": "MultiAZ"},
|
||||
"Tags": [{"Key": "Name", "Value": "Master Database"}],
|
||||
"VPCSecurityGroups": {"Fn::If": ["Is-EC2-VPC", [{"Fn::GetAtt": ["DBEC2SecurityGroup", "GroupId"]}], {"Ref": "AWS::NoValue"}]},
|
||||
"DBSecurityGroups": {"Fn::If": ["Is-EC2-Classic", [{"Ref": "DBSecurityGroup"}], {"Ref": "AWS::NoValue"}]}
|
||||
"VPCSecurityGroups": {
|
||||
"Fn::If": [
|
||||
"Is-EC2-VPC",
|
||||
[{"Fn::GetAtt": ["DBEC2SecurityGroup", "GroupId"]}],
|
||||
{"Ref": "AWS::NoValue"},
|
||||
]
|
||||
},
|
||||
"DBSecurityGroups": {
|
||||
"Fn::If": [
|
||||
"Is-EC2-Classic",
|
||||
[{"Ref": "DBSecurityGroup"}],
|
||||
{"Ref": "AWS::NoValue"},
|
||||
]
|
||||
},
|
||||
},
|
||||
"DeletionPolicy": "Snapshot"
|
||||
"DeletionPolicy": "Snapshot",
|
||||
},
|
||||
|
||||
"ReplicaDB": {
|
||||
"Type": "AWS::RDS::DBInstance",
|
||||
"Properties": {
|
||||
"SourceDBInstanceIdentifier": {"Ref": "MasterDB"},
|
||||
"DBInstanceClass": {"Ref": "DBInstanceClass"},
|
||||
"Tags": [{"Key": "Name", "Value": "Read Replica Database"}]
|
||||
}
|
||||
}
|
||||
"Tags": [{"Key": "Name", "Value": "Read Replica Database"}],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"Outputs": {
|
||||
"EC2Platform": {
|
||||
"Description": "Platform in which this stack is deployed",
|
||||
"Value": {"Fn::If": ["Is-EC2-VPC", "EC2-VPC", "EC2-Classic"]}
|
||||
"Value": {"Fn::If": ["Is-EC2-VPC", "EC2-VPC", "EC2-Classic"]},
|
||||
},
|
||||
|
||||
"MasterJDBCConnectionString": {
|
||||
"Description": "JDBC connection string for the master database",
|
||||
"Value": {"Fn::Join": ["", ["jdbc:mysql://",
|
||||
{"Fn::GetAtt": [
|
||||
"MasterDB", "Endpoint.Address"]},
|
||||
":",
|
||||
{"Fn::GetAtt": [
|
||||
"MasterDB", "Endpoint.Port"]},
|
||||
"/",
|
||||
{"Ref": "DBName"}]]}
|
||||
"Value": {
|
||||
"Fn::Join": [
|
||||
"",
|
||||
[
|
||||
"jdbc:mysql://",
|
||||
{"Fn::GetAtt": ["MasterDB", "Endpoint.Address"]},
|
||||
":",
|
||||
{"Fn::GetAtt": ["MasterDB", "Endpoint.Port"]},
|
||||
"/",
|
||||
{"Ref": "DBName"},
|
||||
],
|
||||
]
|
||||
},
|
||||
},
|
||||
"ReplicaJDBCConnectionString": {
|
||||
"Description": "JDBC connection string for the replica database",
|
||||
"Value": {"Fn::Join": ["", ["jdbc:mysql://",
|
||||
{"Fn::GetAtt": [
|
||||
"ReplicaDB", "Endpoint.Address"]},
|
||||
":",
|
||||
{"Fn::GetAtt": [
|
||||
"ReplicaDB", "Endpoint.Port"]},
|
||||
"/",
|
||||
{"Ref": "DBName"}]]}
|
||||
}
|
||||
}
|
||||
"Value": {
|
||||
"Fn::Join": [
|
||||
"",
|
||||
[
|
||||
"jdbc:mysql://",
|
||||
{"Fn::GetAtt": ["ReplicaDB", "Endpoint.Address"]},
|
||||
":",
|
||||
{"Fn::GetAtt": ["ReplicaDB", "Endpoint.Port"]},
|
||||
"/",
|
||||
{"Ref": "DBName"},
|
||||
],
|
||||
]
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ from __future__ import unicode_literals
|
|||
|
||||
template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
|
||||
"Description": "AWS CloudFormation Sample Template RDS_MySQL_With_Read_Replica: Sample template showing how to create a highly-available, RDS DBInstance with a read replica. **WARNING** This template creates an Amazon Relational Database Service database instance and Amazon CloudWatch alarms. You will be billed for the AWS resources used if you create a stack from this template.",
|
||||
|
||||
"Parameters": {
|
||||
"DBName": {
|
||||
"Default": "MyDatabase",
|
||||
|
|
@ -13,13 +11,9 @@ template = {
|
|||
"MinLength": "1",
|
||||
"MaxLength": "64",
|
||||
"AllowedPattern": "[a-zA-Z][a-zA-Z0-9]*",
|
||||
"ConstraintDescription": "must begin with a letter and contain only alphanumeric characters."
|
||||
"ConstraintDescription": "must begin with a letter and contain only alphanumeric characters.",
|
||||
},
|
||||
|
||||
"DBInstanceIdentifier": {
|
||||
"Type": "String"
|
||||
},
|
||||
|
||||
"DBInstanceIdentifier": {"Type": "String"},
|
||||
"DBUser": {
|
||||
"NoEcho": "true",
|
||||
"Description": "The database admin account username",
|
||||
|
|
@ -27,9 +21,8 @@ template = {
|
|||
"MinLength": "1",
|
||||
"MaxLength": "16",
|
||||
"AllowedPattern": "[a-zA-Z][a-zA-Z0-9]*",
|
||||
"ConstraintDescription": "must begin with a letter and contain only alphanumeric characters."
|
||||
"ConstraintDescription": "must begin with a letter and contain only alphanumeric characters.",
|
||||
},
|
||||
|
||||
"DBPassword": {
|
||||
"NoEcho": "true",
|
||||
"Description": "The database admin account password",
|
||||
|
|
@ -37,101 +30,113 @@ template = {
|
|||
"MinLength": "1",
|
||||
"MaxLength": "41",
|
||||
"AllowedPattern": "[a-zA-Z0-9]+",
|
||||
"ConstraintDescription": "must contain only alphanumeric characters."
|
||||
"ConstraintDescription": "must contain only alphanumeric characters.",
|
||||
},
|
||||
|
||||
"DBAllocatedStorage": {
|
||||
"Default": "5",
|
||||
"Description": "The size of the database (Gb)",
|
||||
"Type": "Number",
|
||||
"MinValue": "5",
|
||||
"MaxValue": "1024",
|
||||
"ConstraintDescription": "must be between 5 and 1024Gb."
|
||||
"ConstraintDescription": "must be between 5 and 1024Gb.",
|
||||
},
|
||||
|
||||
"DBInstanceClass": {
|
||||
"Description": "The database instance type",
|
||||
"Type": "String",
|
||||
"Default": "db.m1.small",
|
||||
"AllowedValues": ["db.t1.micro", "db.m1.small", "db.m1.medium", "db.m1.large", "db.m1.xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge", "db.m3.medium", "db.m3.large", "db.m3.xlarge", "db.m3.2xlarge", "db.r3.large", "db.r3.xlarge", "db.r3.2xlarge", "db.r3.4xlarge", "db.r3.8xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge", "db.cr1.8xlarge"],
|
||||
"ConstraintDescription": "must select a valid database instance type."
|
||||
"AllowedValues": [
|
||||
"db.t1.micro",
|
||||
"db.m1.small",
|
||||
"db.m1.medium",
|
||||
"db.m1.large",
|
||||
"db.m1.xlarge",
|
||||
"db.m2.xlarge",
|
||||
"db.m2.2xlarge",
|
||||
"db.m2.4xlarge",
|
||||
"db.m3.medium",
|
||||
"db.m3.large",
|
||||
"db.m3.xlarge",
|
||||
"db.m3.2xlarge",
|
||||
"db.r3.large",
|
||||
"db.r3.xlarge",
|
||||
"db.r3.2xlarge",
|
||||
"db.r3.4xlarge",
|
||||
"db.r3.8xlarge",
|
||||
"db.m2.xlarge",
|
||||
"db.m2.2xlarge",
|
||||
"db.m2.4xlarge",
|
||||
"db.cr1.8xlarge",
|
||||
],
|
||||
"ConstraintDescription": "must select a valid database instance type.",
|
||||
},
|
||||
|
||||
"EC2SecurityGroup": {
|
||||
"Description": "The EC2 security group that contains instances that need access to the database",
|
||||
"Default": "default",
|
||||
"Type": "String",
|
||||
"AllowedPattern": "[a-zA-Z0-9\\-]+",
|
||||
"ConstraintDescription": "must be a valid security group name."
|
||||
"ConstraintDescription": "must be a valid security group name.",
|
||||
},
|
||||
|
||||
"MultiAZ": {
|
||||
"Description": "Multi-AZ master database",
|
||||
"Type": "String",
|
||||
"Default": "false",
|
||||
"AllowedValues": ["true", "false"],
|
||||
"ConstraintDescription": "must be true or false."
|
||||
}
|
||||
"ConstraintDescription": "must be true or false.",
|
||||
},
|
||||
},
|
||||
|
||||
"Conditions": {
|
||||
"Is-EC2-VPC": {"Fn::Or": [{"Fn::Equals": [{"Ref": "AWS::Region"}, "eu-central-1"]},
|
||||
{"Fn::Equals": [{"Ref": "AWS::Region"}, "cn-north-1"]}]},
|
||||
"Is-EC2-Classic": {"Fn::Not": [{"Condition": "Is-EC2-VPC"}]}
|
||||
"Is-EC2-VPC": {
|
||||
"Fn::Or": [
|
||||
{"Fn::Equals": [{"Ref": "AWS::Region"}, "eu-central-1"]},
|
||||
{"Fn::Equals": [{"Ref": "AWS::Region"}, "cn-north-1"]},
|
||||
]
|
||||
},
|
||||
"Is-EC2-Classic": {"Fn::Not": [{"Condition": "Is-EC2-VPC"}]},
|
||||
},
|
||||
|
||||
"Resources": {
|
||||
"DBEC2SecurityGroup": {
|
||||
"Type": "AWS::EC2::SecurityGroup",
|
||||
"Condition": "Is-EC2-VPC",
|
||||
"Properties": {
|
||||
"GroupDescription": "Open database for access",
|
||||
"SecurityGroupIngress": [{
|
||||
"IpProtocol": "tcp",
|
||||
"FromPort": "3306",
|
||||
"ToPort": "3306",
|
||||
"SourceSecurityGroupName": {"Ref": "EC2SecurityGroup"}
|
||||
}]
|
||||
}
|
||||
"SecurityGroupIngress": [
|
||||
{
|
||||
"IpProtocol": "tcp",
|
||||
"FromPort": "3306",
|
||||
"ToPort": "3306",
|
||||
"SourceSecurityGroupName": {"Ref": "EC2SecurityGroup"},
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
"DBSecurityGroup": {
|
||||
"Type": "AWS::RDS::DBSecurityGroup",
|
||||
"Condition": "Is-EC2-Classic",
|
||||
"Properties": {
|
||||
"DBSecurityGroupIngress": [{
|
||||
"EC2SecurityGroupName": {"Ref": "EC2SecurityGroup"}
|
||||
}],
|
||||
"GroupDescription": "database access"
|
||||
}
|
||||
"DBSecurityGroupIngress": [
|
||||
{"EC2SecurityGroupName": {"Ref": "EC2SecurityGroup"}}
|
||||
],
|
||||
"GroupDescription": "database access",
|
||||
},
|
||||
},
|
||||
|
||||
"my_vpc": {
|
||||
"Type": "AWS::EC2::VPC",
|
||||
"Properties": {
|
||||
"CidrBlock": "10.0.0.0/16",
|
||||
}
|
||||
},
|
||||
|
||||
"my_vpc": {"Type": "AWS::EC2::VPC", "Properties": {"CidrBlock": "10.0.0.0/16"}},
|
||||
"EC2Subnet": {
|
||||
"Type": "AWS::EC2::Subnet",
|
||||
"Condition": "Is-EC2-VPC",
|
||||
"Properties": {
|
||||
"AvailabilityZone": "eu-central-1a",
|
||||
"CidrBlock": "10.0.1.0/24",
|
||||
"VpcId": {"Ref": "my_vpc"}
|
||||
}
|
||||
"VpcId": {"Ref": "my_vpc"},
|
||||
},
|
||||
},
|
||||
|
||||
"DBSubnet": {
|
||||
"Type": "AWS::RDS::DBSubnetGroup",
|
||||
"Condition": "Is-EC2-VPC",
|
||||
"Properties": {
|
||||
"DBSubnetGroupDescription": "my db subnet group",
|
||||
"SubnetIds": [{"Ref": "EC2Subnet"}],
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
"MasterDB": {
|
||||
"Type": "AWS::RDS::DBInstance",
|
||||
"Properties": {
|
||||
|
|
@ -140,54 +145,79 @@ template = {
|
|||
"AllocatedStorage": {"Ref": "DBAllocatedStorage"},
|
||||
"DBInstanceClass": {"Ref": "DBInstanceClass"},
|
||||
"Engine": "MySQL",
|
||||
"DBSubnetGroupName": {"Fn::If": ["Is-EC2-VPC", {"Ref": "DBSubnet"}, {"Ref": "AWS::NoValue"}]},
|
||||
"DBSubnetGroupName": {
|
||||
"Fn::If": [
|
||||
"Is-EC2-VPC",
|
||||
{"Ref": "DBSubnet"},
|
||||
{"Ref": "AWS::NoValue"},
|
||||
]
|
||||
},
|
||||
"MasterUsername": {"Ref": "DBUser"},
|
||||
"MasterUserPassword": {"Ref": "DBPassword"},
|
||||
"MultiAZ": {"Ref": "MultiAZ"},
|
||||
"Tags": [{"Key": "Name", "Value": "Master Database"}],
|
||||
"VPCSecurityGroups": {"Fn::If": ["Is-EC2-VPC", [{"Fn::GetAtt": ["DBEC2SecurityGroup", "GroupId"]}], {"Ref": "AWS::NoValue"}]},
|
||||
"DBSecurityGroups": {"Fn::If": ["Is-EC2-Classic", [{"Ref": "DBSecurityGroup"}], {"Ref": "AWS::NoValue"}]}
|
||||
"VPCSecurityGroups": {
|
||||
"Fn::If": [
|
||||
"Is-EC2-VPC",
|
||||
[{"Fn::GetAtt": ["DBEC2SecurityGroup", "GroupId"]}],
|
||||
{"Ref": "AWS::NoValue"},
|
||||
]
|
||||
},
|
||||
"DBSecurityGroups": {
|
||||
"Fn::If": [
|
||||
"Is-EC2-Classic",
|
||||
[{"Ref": "DBSecurityGroup"}],
|
||||
{"Ref": "AWS::NoValue"},
|
||||
]
|
||||
},
|
||||
},
|
||||
"DeletionPolicy": "Snapshot"
|
||||
"DeletionPolicy": "Snapshot",
|
||||
},
|
||||
|
||||
"ReplicaDB": {
|
||||
"Type": "AWS::RDS::DBInstance",
|
||||
"Properties": {
|
||||
"SourceDBInstanceIdentifier": {"Ref": "MasterDB"},
|
||||
"DBInstanceClass": {"Ref": "DBInstanceClass"},
|
||||
"Tags": [{"Key": "Name", "Value": "Read Replica Database"}]
|
||||
}
|
||||
}
|
||||
"Tags": [{"Key": "Name", "Value": "Read Replica Database"}],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"Outputs": {
|
||||
"EC2Platform": {
|
||||
"Description": "Platform in which this stack is deployed",
|
||||
"Value": {"Fn::If": ["Is-EC2-VPC", "EC2-VPC", "EC2-Classic"]}
|
||||
"Value": {"Fn::If": ["Is-EC2-VPC", "EC2-VPC", "EC2-Classic"]},
|
||||
},
|
||||
|
||||
"MasterJDBCConnectionString": {
|
||||
"Description": "JDBC connection string for the master database",
|
||||
"Value": {"Fn::Join": ["", ["jdbc:mysql://",
|
||||
{"Fn::GetAtt": [
|
||||
"MasterDB", "Endpoint.Address"]},
|
||||
":",
|
||||
{"Fn::GetAtt": [
|
||||
"MasterDB", "Endpoint.Port"]},
|
||||
"/",
|
||||
{"Ref": "DBName"}]]}
|
||||
"Value": {
|
||||
"Fn::Join": [
|
||||
"",
|
||||
[
|
||||
"jdbc:mysql://",
|
||||
{"Fn::GetAtt": ["MasterDB", "Endpoint.Address"]},
|
||||
":",
|
||||
{"Fn::GetAtt": ["MasterDB", "Endpoint.Port"]},
|
||||
"/",
|
||||
{"Ref": "DBName"},
|
||||
],
|
||||
]
|
||||
},
|
||||
},
|
||||
"ReplicaJDBCConnectionString": {
|
||||
"Description": "JDBC connection string for the replica database",
|
||||
"Value": {"Fn::Join": ["", ["jdbc:mysql://",
|
||||
{"Fn::GetAtt": [
|
||||
"ReplicaDB", "Endpoint.Address"]},
|
||||
":",
|
||||
{"Fn::GetAtt": [
|
||||
"ReplicaDB", "Endpoint.Port"]},
|
||||
"/",
|
||||
{"Ref": "DBName"}]]}
|
||||
}
|
||||
}
|
||||
"Value": {
|
||||
"Fn::Join": [
|
||||
"",
|
||||
[
|
||||
"jdbc:mysql://",
|
||||
{"Fn::GetAtt": ["ReplicaDB", "Endpoint.Address"]},
|
||||
":",
|
||||
{"Fn::GetAtt": ["ReplicaDB", "Endpoint.Port"]},
|
||||
"/",
|
||||
{"Ref": "DBName"},
|
||||
],
|
||||
]
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,35 +7,35 @@ template = {
|
|||
"Description": "The name of the first database to be created when the cluster is created",
|
||||
"Type": "String",
|
||||
"Default": "dev",
|
||||
"AllowedPattern": "([a-z]|[0-9])+"
|
||||
"AllowedPattern": "([a-z]|[0-9])+",
|
||||
},
|
||||
"ClusterType": {
|
||||
"Description": "The type of cluster",
|
||||
"Type": "String",
|
||||
"Default": "single-node",
|
||||
"AllowedValues": ["single-node", "multi-node"]
|
||||
"AllowedValues": ["single-node", "multi-node"],
|
||||
},
|
||||
"NumberOfNodes": {
|
||||
"Description": "The number of compute nodes in the cluster. For multi-node clusters, the NumberOfNodes parameter must be greater than 1",
|
||||
"Type": "Number",
|
||||
"Default": "1"
|
||||
"Default": "1",
|
||||
},
|
||||
"NodeType": {
|
||||
"Description": "The type of node to be provisioned",
|
||||
"Type": "String",
|
||||
"Default": "dw1.xlarge",
|
||||
"AllowedValues": ["dw1.xlarge", "dw1.8xlarge", "dw2.large", "dw2.8xlarge"]
|
||||
"AllowedValues": ["dw1.xlarge", "dw1.8xlarge", "dw2.large", "dw2.8xlarge"],
|
||||
},
|
||||
"MasterUsername": {
|
||||
"Description": "The user name that is associated with the master user account for the cluster that is being created",
|
||||
"Type": "String",
|
||||
"Default": "defaultuser",
|
||||
"AllowedPattern": "([a-z])([a-z]|[0-9])*"
|
||||
"AllowedPattern": "([a-z])([a-z]|[0-9])*",
|
||||
},
|
||||
"MasterUserPassword": {
|
||||
"MasterUserPassword": {
|
||||
"Description": "The password that is associated with the master user account for the cluster that is being created.",
|
||||
"Type": "String",
|
||||
"NoEcho": "true"
|
||||
"NoEcho": "true",
|
||||
},
|
||||
"InboundTraffic": {
|
||||
"Description": "Allow inbound traffic to the cluster from this CIDR range.",
|
||||
|
|
@ -44,18 +44,16 @@ template = {
|
|||
"MaxLength": "18",
|
||||
"Default": "0.0.0.0/0",
|
||||
"AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
|
||||
"ConstraintDescription": "must be a valid CIDR range of the form x.x.x.x/x."
|
||||
"ConstraintDescription": "must be a valid CIDR range of the form x.x.x.x/x.",
|
||||
},
|
||||
"PortNumber": {
|
||||
"Description": "The port number on which the cluster accepts incoming connections.",
|
||||
"Type": "Number",
|
||||
"Default": "5439"
|
||||
}
|
||||
"Default": "5439",
|
||||
},
|
||||
},
|
||||
"Conditions": {
|
||||
"IsMultiNodeCluster": {
|
||||
"Fn::Equals": [{"Ref": "ClusterType"}, "multi-node"]
|
||||
}
|
||||
"IsMultiNodeCluster": {"Fn::Equals": [{"Ref": "ClusterType"}, "multi-node"]}
|
||||
},
|
||||
"Resources": {
|
||||
"RedshiftCluster": {
|
||||
|
|
@ -63,7 +61,13 @@ template = {
|
|||
"DependsOn": "AttachGateway",
|
||||
"Properties": {
|
||||
"ClusterType": {"Ref": "ClusterType"},
|
||||
"NumberOfNodes": {"Fn::If": ["IsMultiNodeCluster", {"Ref": "NumberOfNodes"}, {"Ref": "AWS::NoValue"}]},
|
||||
"NumberOfNodes": {
|
||||
"Fn::If": [
|
||||
"IsMultiNodeCluster",
|
||||
{"Ref": "NumberOfNodes"},
|
||||
{"Ref": "AWS::NoValue"},
|
||||
]
|
||||
},
|
||||
"NodeType": {"Ref": "NodeType"},
|
||||
"DBName": {"Ref": "DatabaseName"},
|
||||
"MasterUsername": {"Ref": "MasterUsername"},
|
||||
|
|
@ -72,116 +76,106 @@ template = {
|
|||
"VpcSecurityGroupIds": [{"Ref": "SecurityGroup"}],
|
||||
"ClusterSubnetGroupName": {"Ref": "RedshiftClusterSubnetGroup"},
|
||||
"PubliclyAccessible": "true",
|
||||
"Port": {"Ref": "PortNumber"}
|
||||
}
|
||||
"Port": {"Ref": "PortNumber"},
|
||||
},
|
||||
},
|
||||
"RedshiftClusterParameterGroup": {
|
||||
"Type": "AWS::Redshift::ClusterParameterGroup",
|
||||
"Properties": {
|
||||
"Description": "Cluster parameter group",
|
||||
"ParameterGroupFamily": "redshift-1.0",
|
||||
"Parameters": [{
|
||||
"ParameterName": "enable_user_activity_logging",
|
||||
"ParameterValue": "true"
|
||||
}]
|
||||
}
|
||||
"Parameters": [
|
||||
{
|
||||
"ParameterName": "enable_user_activity_logging",
|
||||
"ParameterValue": "true",
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
"RedshiftClusterSubnetGroup": {
|
||||
"Type": "AWS::Redshift::ClusterSubnetGroup",
|
||||
"Properties": {
|
||||
"Description": "Cluster subnet group",
|
||||
"SubnetIds": [{"Ref": "PublicSubnet"}]
|
||||
}
|
||||
},
|
||||
"VPC": {
|
||||
"Type": "AWS::EC2::VPC",
|
||||
"Properties": {
|
||||
"CidrBlock": "10.0.0.0/16"
|
||||
}
|
||||
"SubnetIds": [{"Ref": "PublicSubnet"}],
|
||||
},
|
||||
},
|
||||
"VPC": {"Type": "AWS::EC2::VPC", "Properties": {"CidrBlock": "10.0.0.0/16"}},
|
||||
"PublicSubnet": {
|
||||
"Type": "AWS::EC2::Subnet",
|
||||
"Properties": {
|
||||
"CidrBlock": "10.0.0.0/24",
|
||||
"VpcId": {"Ref": "VPC"}
|
||||
}
|
||||
"Properties": {"CidrBlock": "10.0.0.0/24", "VpcId": {"Ref": "VPC"}},
|
||||
},
|
||||
"SecurityGroup": {
|
||||
"Type": "AWS::EC2::SecurityGroup",
|
||||
"Properties": {
|
||||
"GroupDescription": "Security group",
|
||||
"SecurityGroupIngress": [{
|
||||
"CidrIp": {"Ref": "InboundTraffic"},
|
||||
"FromPort": {"Ref": "PortNumber"},
|
||||
"ToPort": {"Ref": "PortNumber"},
|
||||
"IpProtocol": "tcp"
|
||||
}],
|
||||
"VpcId": {"Ref": "VPC"}
|
||||
}
|
||||
},
|
||||
"myInternetGateway": {
|
||||
"Type": "AWS::EC2::InternetGateway"
|
||||
"SecurityGroupIngress": [
|
||||
{
|
||||
"CidrIp": {"Ref": "InboundTraffic"},
|
||||
"FromPort": {"Ref": "PortNumber"},
|
||||
"ToPort": {"Ref": "PortNumber"},
|
||||
"IpProtocol": "tcp",
|
||||
}
|
||||
],
|
||||
"VpcId": {"Ref": "VPC"},
|
||||
},
|
||||
},
|
||||
"myInternetGateway": {"Type": "AWS::EC2::InternetGateway"},
|
||||
"AttachGateway": {
|
||||
"Type": "AWS::EC2::VPCGatewayAttachment",
|
||||
"Properties": {
|
||||
"VpcId": {"Ref": "VPC"},
|
||||
"InternetGatewayId": {"Ref": "myInternetGateway"}
|
||||
}
|
||||
"InternetGatewayId": {"Ref": "myInternetGateway"},
|
||||
},
|
||||
},
|
||||
"PublicRouteTable": {
|
||||
"Type": "AWS::EC2::RouteTable",
|
||||
"Properties": {
|
||||
"VpcId": {
|
||||
"Ref": "VPC"
|
||||
}
|
||||
}
|
||||
"Properties": {"VpcId": {"Ref": "VPC"}},
|
||||
},
|
||||
"PublicRoute": {
|
||||
"Type": "AWS::EC2::Route",
|
||||
"DependsOn": "AttachGateway",
|
||||
"Properties": {
|
||||
"RouteTableId": {
|
||||
"Ref": "PublicRouteTable"
|
||||
},
|
||||
"RouteTableId": {"Ref": "PublicRouteTable"},
|
||||
"DestinationCidrBlock": "0.0.0.0/0",
|
||||
"GatewayId": {
|
||||
"Ref": "myInternetGateway"
|
||||
}
|
||||
}
|
||||
"GatewayId": {"Ref": "myInternetGateway"},
|
||||
},
|
||||
},
|
||||
"PublicSubnetRouteTableAssociation": {
|
||||
"Type": "AWS::EC2::SubnetRouteTableAssociation",
|
||||
"Properties": {
|
||||
"SubnetId": {
|
||||
"Ref": "PublicSubnet"
|
||||
},
|
||||
"RouteTableId": {
|
||||
"Ref": "PublicRouteTable"
|
||||
}
|
||||
}
|
||||
}
|
||||
"SubnetId": {"Ref": "PublicSubnet"},
|
||||
"RouteTableId": {"Ref": "PublicRouteTable"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"Outputs": {
|
||||
"ClusterEndpoint": {
|
||||
"Description": "Cluster endpoint",
|
||||
"Value": {"Fn::Join": [":", [{"Fn::GetAtt": ["RedshiftCluster", "Endpoint.Address"]}, {"Fn::GetAtt": ["RedshiftCluster", "Endpoint.Port"]}]]}
|
||||
"Value": {
|
||||
"Fn::Join": [
|
||||
":",
|
||||
[
|
||||
{"Fn::GetAtt": ["RedshiftCluster", "Endpoint.Address"]},
|
||||
{"Fn::GetAtt": ["RedshiftCluster", "Endpoint.Port"]},
|
||||
],
|
||||
]
|
||||
},
|
||||
},
|
||||
"ClusterName": {
|
||||
"Description": "Name of cluster",
|
||||
"Value": {"Ref": "RedshiftCluster"}
|
||||
"Value": {"Ref": "RedshiftCluster"},
|
||||
},
|
||||
"ParameterGroupName": {
|
||||
"Description": "Name of parameter group",
|
||||
"Value": {"Ref": "RedshiftClusterParameterGroup"}
|
||||
"Value": {"Ref": "RedshiftClusterParameterGroup"},
|
||||
},
|
||||
"RedshiftClusterSubnetGroupName": {
|
||||
"Description": "Name of cluster subnet group",
|
||||
"Value": {"Ref": "RedshiftClusterSubnetGroup"}
|
||||
"Value": {"Ref": "RedshiftClusterSubnetGroup"},
|
||||
},
|
||||
"RedshiftClusterSecurityGroupName": {
|
||||
"Description": "Name of cluster security group",
|
||||
"Value": {"Ref": "SecurityGroup"}
|
||||
}
|
||||
}
|
||||
"Value": {"Ref": "SecurityGroup"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,47 +1,38 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
template = {
|
||||
"Parameters": {
|
||||
"R53ZoneName": {
|
||||
"Type": "String",
|
||||
"Default": "my_zone"
|
||||
}
|
||||
},
|
||||
|
||||
"Parameters": {"R53ZoneName": {"Type": "String", "Default": "my_zone"}},
|
||||
"Resources": {
|
||||
"Ec2Instance": {
|
||||
"Type": "AWS::EC2::Instance",
|
||||
"Properties": {
|
||||
"ImageId": "ami-1234abcd",
|
||||
"PrivateIpAddress": "10.0.0.25",
|
||||
}
|
||||
"Properties": {"ImageId": "ami-1234abcd", "PrivateIpAddress": "10.0.0.25"},
|
||||
},
|
||||
|
||||
"HostedZone": {
|
||||
"Type": "AWS::Route53::HostedZone",
|
||||
"Properties": {
|
||||
"Name": {"Ref": "R53ZoneName"}
|
||||
}
|
||||
"Properties": {"Name": {"Ref": "R53ZoneName"}},
|
||||
},
|
||||
|
||||
"myDNSRecord": {
|
||||
"Type": "AWS::Route53::RecordSet",
|
||||
"Properties": {
|
||||
"HostedZoneId": {"Ref": "HostedZone"},
|
||||
"Comment": "DNS name for my instance.",
|
||||
"Name": {
|
||||
"Fn::Join": ["", [
|
||||
{"Ref": "Ec2Instance"}, ".",
|
||||
{"Ref": "AWS::Region"}, ".",
|
||||
{"Ref": "R53ZoneName"}, "."
|
||||
]]
|
||||
"Fn::Join": [
|
||||
"",
|
||||
[
|
||||
{"Ref": "Ec2Instance"},
|
||||
".",
|
||||
{"Ref": "AWS::Region"},
|
||||
".",
|
||||
{"Ref": "R53ZoneName"},
|
||||
".",
|
||||
],
|
||||
]
|
||||
},
|
||||
"Type": "A",
|
||||
"TTL": "900",
|
||||
"ResourceRecords": [
|
||||
{"Fn::GetAtt": ["Ec2Instance", "PrivateIp"]}
|
||||
]
|
||||
}
|
||||
}
|
||||
"ResourceRecords": [{"Fn::GetAtt": ["Ec2Instance", "PrivateIp"]}],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,8 @@ template = {
|
|||
"Resources": {
|
||||
"HostedZone": {
|
||||
"Type": "AWS::Route53::HostedZone",
|
||||
"Properties": {
|
||||
"Name": "my_zone"
|
||||
}
|
||||
"Properties": {"Name": "my_zone"},
|
||||
},
|
||||
|
||||
"my_health_check": {
|
||||
"Type": "AWS::Route53::HealthCheck",
|
||||
"Properties": {
|
||||
|
|
@ -20,9 +17,8 @@ template = {
|
|||
"ResourcePath": "/",
|
||||
"Type": "HTTP",
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
"myDNSRecord": {
|
||||
"Type": "AWS::Route53::RecordSet",
|
||||
"Properties": {
|
||||
|
|
@ -33,7 +29,7 @@ template = {
|
|||
"TTL": "900",
|
||||
"ResourceRecords": ["my.example.com"],
|
||||
"HealthCheckId": {"Ref": "my_health_check"},
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,53 +2,71 @@ from __future__ import unicode_literals
|
|||
|
||||
template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
|
||||
"Description": "AWS CloudFormation Sample Template Route53_RoundRobin: Sample template showing how to use weighted round robin (WRR) DNS entried via Amazon Route 53. This contrived sample uses weighted CNAME records to illustrate that the weighting influences the return records. It assumes that you already have a Hosted Zone registered with Amazon Route 53. **WARNING** This template creates one or more AWS resources. You will be billed for the AWS resources used if you create a stack from this template.",
|
||||
|
||||
"Parameters": {
|
||||
"R53ZoneName": {
|
||||
"Type": "String",
|
||||
"Default": "my_zone"
|
||||
}
|
||||
},
|
||||
|
||||
"Parameters": {"R53ZoneName": {"Type": "String", "Default": "my_zone"}},
|
||||
"Resources": {
|
||||
|
||||
"MyZone": {
|
||||
"Type": "AWS::Route53::HostedZone",
|
||||
"Properties": {
|
||||
"Name": {"Ref": "R53ZoneName"}
|
||||
}
|
||||
"Properties": {"Name": {"Ref": "R53ZoneName"}},
|
||||
},
|
||||
|
||||
"MyDNSRecord": {
|
||||
"Type": "AWS::Route53::RecordSetGroup",
|
||||
"Properties": {
|
||||
"HostedZoneId": {"Ref": "MyZone"},
|
||||
"Comment": "Contrived example to redirect to aws.amazon.com 75% of the time and www.amazon.com 25% of the time.",
|
||||
"RecordSets": [{
|
||||
"SetIdentifier": {"Fn::Join": [" ", [{"Ref": "AWS::StackName"}, "AWS"]]},
|
||||
"Name": {"Fn::Join": ["", [{"Ref": "AWS::StackName"}, ".", {"Ref": "AWS::Region"}, ".", {"Ref": "R53ZoneName"}, "."]]},
|
||||
"Type": "CNAME",
|
||||
"TTL": "900",
|
||||
"ResourceRecords": ["aws.amazon.com"],
|
||||
"Weight": "3"
|
||||
}, {
|
||||
"SetIdentifier": {"Fn::Join": [" ", [{"Ref": "AWS::StackName"}, "Amazon"]]},
|
||||
"Name": {"Fn::Join": ["", [{"Ref": "AWS::StackName"}, ".", {"Ref": "AWS::Region"}, ".", {"Ref": "R53ZoneName"}, "."]]},
|
||||
"Type": "CNAME",
|
||||
"TTL": "900",
|
||||
"ResourceRecords": ["www.amazon.com"],
|
||||
"Weight": "1"
|
||||
}]
|
||||
}
|
||||
}
|
||||
"RecordSets": [
|
||||
{
|
||||
"SetIdentifier": {
|
||||
"Fn::Join": [" ", [{"Ref": "AWS::StackName"}, "AWS"]]
|
||||
},
|
||||
"Name": {
|
||||
"Fn::Join": [
|
||||
"",
|
||||
[
|
||||
{"Ref": "AWS::StackName"},
|
||||
".",
|
||||
{"Ref": "AWS::Region"},
|
||||
".",
|
||||
{"Ref": "R53ZoneName"},
|
||||
".",
|
||||
],
|
||||
]
|
||||
},
|
||||
"Type": "CNAME",
|
||||
"TTL": "900",
|
||||
"ResourceRecords": ["aws.amazon.com"],
|
||||
"Weight": "3",
|
||||
},
|
||||
{
|
||||
"SetIdentifier": {
|
||||
"Fn::Join": [" ", [{"Ref": "AWS::StackName"}, "Amazon"]]
|
||||
},
|
||||
"Name": {
|
||||
"Fn::Join": [
|
||||
"",
|
||||
[
|
||||
{"Ref": "AWS::StackName"},
|
||||
".",
|
||||
{"Ref": "AWS::Region"},
|
||||
".",
|
||||
{"Ref": "R53ZoneName"},
|
||||
".",
|
||||
],
|
||||
]
|
||||
},
|
||||
"Type": "CNAME",
|
||||
"TTL": "900",
|
||||
"ResourceRecords": ["www.amazon.com"],
|
||||
"Weight": "1",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"Outputs": {
|
||||
"DomainName": {
|
||||
"Description": "Fully qualified domain name",
|
||||
"Value": {"Ref": "MyDNSRecord"}
|
||||
"Value": {"Ref": "MyDNSRecord"},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ template = {
|
|||
"MinLength": "9",
|
||||
"AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
|
||||
"MaxLength": "18",
|
||||
"Type": "String"
|
||||
"Type": "String",
|
||||
},
|
||||
"KeyName": {
|
||||
"Type": "String",
|
||||
|
|
@ -18,7 +18,7 @@ template = {
|
|||
"MinLength": "1",
|
||||
"AllowedPattern": "[\\x20-\\x7E]*",
|
||||
"MaxLength": "255",
|
||||
"ConstraintDescription": "can contain only ASCII characters."
|
||||
"ConstraintDescription": "can contain only ASCII characters.",
|
||||
},
|
||||
"InstanceType": {
|
||||
"Default": "m1.small",
|
||||
|
|
@ -40,8 +40,8 @@ template = {
|
|||
"c1.xlarge",
|
||||
"cc1.4xlarge",
|
||||
"cc2.8xlarge",
|
||||
"cg1.4xlarge"
|
||||
]
|
||||
"cg1.4xlarge",
|
||||
],
|
||||
},
|
||||
"VolumeSize": {
|
||||
"Description": "WebServer EC2 instance type",
|
||||
|
|
@ -49,8 +49,8 @@ template = {
|
|||
"Type": "Number",
|
||||
"MaxValue": "1024",
|
||||
"MinValue": "5",
|
||||
"ConstraintDescription": "must be between 5 and 1024 Gb."
|
||||
}
|
||||
"ConstraintDescription": "must be between 5 and 1024 Gb.",
|
||||
},
|
||||
},
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Outputs": {
|
||||
|
|
@ -59,17 +59,9 @@ template = {
|
|||
"Value": {
|
||||
"Fn::Join": [
|
||||
"",
|
||||
[
|
||||
"http://",
|
||||
{
|
||||
"Fn::GetAtt": [
|
||||
"WebServer",
|
||||
"PublicDnsName"
|
||||
]
|
||||
}
|
||||
]
|
||||
["http://", {"Fn::GetAtt": ["WebServer", "PublicDnsName"]}],
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
"Resources": {
|
||||
|
|
@ -81,19 +73,17 @@ template = {
|
|||
"ToPort": "80",
|
||||
"IpProtocol": "tcp",
|
||||
"CidrIp": "0.0.0.0/0",
|
||||
"FromPort": "80"
|
||||
"FromPort": "80",
|
||||
},
|
||||
{
|
||||
"ToPort": "22",
|
||||
"IpProtocol": "tcp",
|
||||
"CidrIp": {
|
||||
"Ref": "SSHLocation"
|
||||
},
|
||||
"FromPort": "22"
|
||||
}
|
||||
"CidrIp": {"Ref": "SSHLocation"},
|
||||
"FromPort": "22",
|
||||
},
|
||||
],
|
||||
"GroupDescription": "Enable SSH access and HTTP access on the inbound port"
|
||||
}
|
||||
"GroupDescription": "Enable SSH access and HTTP access on the inbound port",
|
||||
},
|
||||
},
|
||||
"WebServer": {
|
||||
"Type": "AWS::EC2::Instance",
|
||||
|
|
@ -108,23 +98,17 @@ template = {
|
|||
"# Helper function\n",
|
||||
"function error_exit\n",
|
||||
"{\n",
|
||||
" /opt/aws/bin/cfn-signal -e 1 -r \"$1\" '",
|
||||
{
|
||||
"Ref": "WaitHandle"
|
||||
},
|
||||
' /opt/aws/bin/cfn-signal -e 1 -r "$1" \'',
|
||||
{"Ref": "WaitHandle"},
|
||||
"'\n",
|
||||
" exit 1\n",
|
||||
"}\n",
|
||||
"# Install Rails packages\n",
|
||||
"/opt/aws/bin/cfn-init -s ",
|
||||
{
|
||||
"Ref": "AWS::StackId"
|
||||
},
|
||||
{"Ref": "AWS::StackId"},
|
||||
" -r WebServer ",
|
||||
" --region ",
|
||||
{
|
||||
"Ref": "AWS::Region"
|
||||
},
|
||||
{"Ref": "AWS::Region"},
|
||||
" || error_exit 'Failed to run cfn-init'\n",
|
||||
"# Wait for the EBS volume to show up\n",
|
||||
"while [ ! -e /dev/sdh ]; do echo Waiting for EBS volume to attach; sleep 5; done\n",
|
||||
|
|
@ -137,56 +121,38 @@ template = {
|
|||
"git init\n",
|
||||
"gollum --port 80 --host 0.0.0.0 &\n",
|
||||
"# If all is well so signal success\n",
|
||||
"/opt/aws/bin/cfn-signal -e $? -r \"Rails application setup complete\" '",
|
||||
{
|
||||
"Ref": "WaitHandle"
|
||||
},
|
||||
"'\n"
|
||||
]
|
||||
'/opt/aws/bin/cfn-signal -e $? -r "Rails application setup complete" \'',
|
||||
{"Ref": "WaitHandle"},
|
||||
"'\n",
|
||||
],
|
||||
]
|
||||
}
|
||||
},
|
||||
"KeyName": {
|
||||
"Ref": "KeyName"
|
||||
},
|
||||
"SecurityGroups": [
|
||||
{
|
||||
"Ref": "WebServerSecurityGroup"
|
||||
}
|
||||
],
|
||||
"InstanceType": {
|
||||
"Ref": "InstanceType"
|
||||
},
|
||||
"KeyName": {"Ref": "KeyName"},
|
||||
"SecurityGroups": [{"Ref": "WebServerSecurityGroup"}],
|
||||
"InstanceType": {"Ref": "InstanceType"},
|
||||
"ImageId": {
|
||||
"Fn::FindInMap": [
|
||||
"AWSRegionArch2AMI",
|
||||
{
|
||||
"Ref": "AWS::Region"
|
||||
},
|
||||
{"Ref": "AWS::Region"},
|
||||
{
|
||||
"Fn::FindInMap": [
|
||||
"AWSInstanceType2Arch",
|
||||
{
|
||||
"Ref": "InstanceType"
|
||||
},
|
||||
"Arch"
|
||||
{"Ref": "InstanceType"},
|
||||
"Arch",
|
||||
]
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
"Metadata": {
|
||||
"AWS::CloudFormation::Init": {
|
||||
"config": {
|
||||
"packages": {
|
||||
"rubygems": {
|
||||
"nokogiri": [
|
||||
"1.5.10"
|
||||
],
|
||||
"nokogiri": ["1.5.10"],
|
||||
"rdiscount": [],
|
||||
"gollum": [
|
||||
"1.1.1"
|
||||
]
|
||||
"gollum": ["1.1.1"],
|
||||
},
|
||||
"yum": {
|
||||
"libxslt-devel": [],
|
||||
|
|
@ -196,150 +162,99 @@ template = {
|
|||
"ruby-devel": [],
|
||||
"ruby-rdoc": [],
|
||||
"make": [],
|
||||
"libxml2-devel": []
|
||||
}
|
||||
"libxml2-devel": [],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"DataVolume": {
|
||||
"Type": "AWS::EC2::Volume",
|
||||
"Properties": {
|
||||
"Tags": [
|
||||
{
|
||||
"Value": "Gollum Data Volume",
|
||||
"Key": "Usage"
|
||||
}
|
||||
],
|
||||
"AvailabilityZone": {
|
||||
"Fn::GetAtt": [
|
||||
"WebServer",
|
||||
"AvailabilityZone"
|
||||
]
|
||||
},
|
||||
"Tags": [{"Value": "Gollum Data Volume", "Key": "Usage"}],
|
||||
"AvailabilityZone": {"Fn::GetAtt": ["WebServer", "AvailabilityZone"]},
|
||||
"Size": "100",
|
||||
}
|
||||
},
|
||||
},
|
||||
"MountPoint": {
|
||||
"Type": "AWS::EC2::VolumeAttachment",
|
||||
"Properties": {
|
||||
"InstanceId": {
|
||||
"Ref": "WebServer"
|
||||
},
|
||||
"InstanceId": {"Ref": "WebServer"},
|
||||
"Device": "/dev/sdh",
|
||||
"VolumeId": {
|
||||
"Ref": "DataVolume"
|
||||
}
|
||||
}
|
||||
"VolumeId": {"Ref": "DataVolume"},
|
||||
},
|
||||
},
|
||||
"WaitCondition": {
|
||||
"DependsOn": "MountPoint",
|
||||
"Type": "AWS::CloudFormation::WaitCondition",
|
||||
"Properties": {
|
||||
"Handle": {
|
||||
"Ref": "WaitHandle"
|
||||
},
|
||||
"Timeout": "300"
|
||||
},
|
||||
"Properties": {"Handle": {"Ref": "WaitHandle"}, "Timeout": "300"},
|
||||
"Metadata": {
|
||||
"Comment1": "Note that the WaitCondition is dependent on the volume mount point allowing the volume to be created and attached to the EC2 instance",
|
||||
"Comment2": "The instance bootstrap script waits for the volume to be attached to the instance prior to installing Gollum and signalling completion"
|
||||
}
|
||||
"Comment2": "The instance bootstrap script waits for the volume to be attached to the instance prior to installing Gollum and signalling completion",
|
||||
},
|
||||
},
|
||||
"WaitHandle": {
|
||||
"Type": "AWS::CloudFormation::WaitConditionHandle"
|
||||
}
|
||||
"WaitHandle": {"Type": "AWS::CloudFormation::WaitConditionHandle"},
|
||||
},
|
||||
"Mappings": {
|
||||
"AWSInstanceType2Arch": {
|
||||
"m3.2xlarge": {
|
||||
"Arch": "64"
|
||||
},
|
||||
"m2.2xlarge": {
|
||||
"Arch": "64"
|
||||
},
|
||||
"m1.small": {
|
||||
"Arch": "64"
|
||||
},
|
||||
"c1.medium": {
|
||||
"Arch": "64"
|
||||
},
|
||||
"cg1.4xlarge": {
|
||||
"Arch": "64HVM"
|
||||
},
|
||||
"m2.xlarge": {
|
||||
"Arch": "64"
|
||||
},
|
||||
"t1.micro": {
|
||||
"Arch": "64"
|
||||
},
|
||||
"cc1.4xlarge": {
|
||||
"Arch": "64HVM"
|
||||
},
|
||||
"m1.medium": {
|
||||
"Arch": "64"
|
||||
},
|
||||
"cc2.8xlarge": {
|
||||
"Arch": "64HVM"
|
||||
},
|
||||
"m1.large": {
|
||||
"Arch": "64"
|
||||
},
|
||||
"m1.xlarge": {
|
||||
"Arch": "64"
|
||||
},
|
||||
"m2.4xlarge": {
|
||||
"Arch": "64"
|
||||
},
|
||||
"c1.xlarge": {
|
||||
"Arch": "64"
|
||||
},
|
||||
"m3.xlarge": {
|
||||
"Arch": "64"
|
||||
}
|
||||
"m3.2xlarge": {"Arch": "64"},
|
||||
"m2.2xlarge": {"Arch": "64"},
|
||||
"m1.small": {"Arch": "64"},
|
||||
"c1.medium": {"Arch": "64"},
|
||||
"cg1.4xlarge": {"Arch": "64HVM"},
|
||||
"m2.xlarge": {"Arch": "64"},
|
||||
"t1.micro": {"Arch": "64"},
|
||||
"cc1.4xlarge": {"Arch": "64HVM"},
|
||||
"m1.medium": {"Arch": "64"},
|
||||
"cc2.8xlarge": {"Arch": "64HVM"},
|
||||
"m1.large": {"Arch": "64"},
|
||||
"m1.xlarge": {"Arch": "64"},
|
||||
"m2.4xlarge": {"Arch": "64"},
|
||||
"c1.xlarge": {"Arch": "64"},
|
||||
"m3.xlarge": {"Arch": "64"},
|
||||
},
|
||||
"AWSRegionArch2AMI": {
|
||||
"ap-southeast-1": {
|
||||
"64HVM": "NOT_YET_SUPPORTED",
|
||||
"32": "ami-b4b0cae6",
|
||||
"64": "ami-beb0caec"
|
||||
"64": "ami-beb0caec",
|
||||
},
|
||||
"ap-southeast-2": {
|
||||
"64HVM": "NOT_YET_SUPPORTED",
|
||||
"32": "ami-b3990e89",
|
||||
"64": "ami-bd990e87"
|
||||
"64": "ami-bd990e87",
|
||||
},
|
||||
"us-west-2": {
|
||||
"64HVM": "NOT_YET_SUPPORTED",
|
||||
"32": "ami-38fe7308",
|
||||
"64": "ami-30fe7300"
|
||||
"64": "ami-30fe7300",
|
||||
},
|
||||
"us-east-1": {
|
||||
"64HVM": "ami-0da96764",
|
||||
"32": "ami-31814f58",
|
||||
"64": "ami-1b814f72"
|
||||
"64": "ami-1b814f72",
|
||||
},
|
||||
"ap-northeast-1": {
|
||||
"64HVM": "NOT_YET_SUPPORTED",
|
||||
"32": "ami-0644f007",
|
||||
"64": "ami-0a44f00b"
|
||||
"64": "ami-0a44f00b",
|
||||
},
|
||||
"us-west-1": {
|
||||
"64HVM": "NOT_YET_SUPPORTED",
|
||||
"32": "ami-11d68a54",
|
||||
"64": "ami-1bd68a5e"
|
||||
"64": "ami-1bd68a5e",
|
||||
},
|
||||
"eu-west-1": {
|
||||
"64HVM": "NOT_YET_SUPPORTED",
|
||||
"32": "ami-973b06e3",
|
||||
"64": "ami-953b06e1"
|
||||
"64": "ami-953b06e1",
|
||||
},
|
||||
"sa-east-1": {
|
||||
"64HVM": "NOT_YET_SUPPORTED",
|
||||
"32": "ami-3e3be423",
|
||||
"64": "ami-3c3be421"
|
||||
}
|
||||
}
|
||||
}
|
||||
"64": "ami-3c3be421",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,5 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
template = {
|
||||
"Resources": {
|
||||
"VPCEIP": {
|
||||
"Type": "AWS::EC2::EIP",
|
||||
"Properties": {
|
||||
"Domain": "vpc"
|
||||
}
|
||||
}
|
||||
}
|
||||
"Resources": {"VPCEIP": {"Type": "AWS::EC2::EIP", "Properties": {"Domain": "vpc"}}}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,33 +6,26 @@ template = {
|
|||
"Resources": {
|
||||
"ENI": {
|
||||
"Type": "AWS::EC2::NetworkInterface",
|
||||
"Properties": {
|
||||
"SubnetId": {"Ref": "Subnet"}
|
||||
}
|
||||
"Properties": {"SubnetId": {"Ref": "Subnet"}},
|
||||
},
|
||||
"Subnet": {
|
||||
"Type": "AWS::EC2::Subnet",
|
||||
"Properties": {
|
||||
"AvailabilityZone": "us-east-1a",
|
||||
"VpcId": {"Ref": "VPC"},
|
||||
"CidrBlock": "10.0.0.0/24"
|
||||
}
|
||||
"CidrBlock": "10.0.0.0/24",
|
||||
},
|
||||
},
|
||||
"VPC": {
|
||||
"Type": "AWS::EC2::VPC",
|
||||
"Properties": {
|
||||
"CidrBlock": "10.0.0.0/16"
|
||||
}
|
||||
}
|
||||
"VPC": {"Type": "AWS::EC2::VPC", "Properties": {"CidrBlock": "10.0.0.0/16"}},
|
||||
},
|
||||
"Outputs": {
|
||||
"NinjaENI": {
|
||||
"Description": "Elastic IP mapping to Auto-Scaling Group",
|
||||
"Value": {"Ref": "ENI"}
|
||||
"Value": {"Ref": "ENI"},
|
||||
},
|
||||
"ENIIpAddress": {
|
||||
"Description": "ENI's Private IP address",
|
||||
"Value": {"Fn::GetAtt": ["ENI", "PrimaryPrivateIpAddress"]}
|
||||
}
|
||||
}
|
||||
"Value": {"Fn::GetAtt": ["ENI", "PrimaryPrivateIpAddress"]},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ template = {
|
|||
"MinLength": "9",
|
||||
"AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})",
|
||||
"MaxLength": "18",
|
||||
"Type": "String"
|
||||
"Type": "String",
|
||||
},
|
||||
"KeyName": {
|
||||
"Type": "String",
|
||||
|
|
@ -18,7 +18,7 @@ template = {
|
|||
"MinLength": "1",
|
||||
"AllowedPattern": "[\\x20-\\x7E]*",
|
||||
"MaxLength": "255",
|
||||
"ConstraintDescription": "can contain only ASCII characters."
|
||||
"ConstraintDescription": "can contain only ASCII characters.",
|
||||
},
|
||||
"InstanceType": {
|
||||
"Default": "m1.small",
|
||||
|
|
@ -40,9 +40,9 @@ template = {
|
|||
"c1.xlarge",
|
||||
"cc1.4xlarge",
|
||||
"cc2.8xlarge",
|
||||
"cg1.4xlarge"
|
||||
]
|
||||
}
|
||||
"cg1.4xlarge",
|
||||
],
|
||||
},
|
||||
},
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Outputs": {
|
||||
|
|
@ -51,116 +51,61 @@ template = {
|
|||
"Value": {
|
||||
"Fn::Join": [
|
||||
"",
|
||||
[
|
||||
"http://",
|
||||
{
|
||||
"Fn::GetAtt": [
|
||||
"WebServerInstance",
|
||||
"PublicIp"
|
||||
]
|
||||
}
|
||||
]
|
||||
["http://", {"Fn::GetAtt": ["WebServerInstance", "PublicIp"]}],
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
"Resources": {
|
||||
"Subnet": {
|
||||
"Type": "AWS::EC2::Subnet",
|
||||
"Properties": {
|
||||
"VpcId": {
|
||||
"Ref": "VPC"
|
||||
},
|
||||
"VpcId": {"Ref": "VPC"},
|
||||
"CidrBlock": "10.0.0.0/24",
|
||||
"Tags": [
|
||||
{
|
||||
"Value": {
|
||||
"Ref": "AWS::StackId"
|
||||
},
|
||||
"Key": "Application"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"WebServerWaitHandle": {
|
||||
"Type": "AWS::CloudFormation::WaitConditionHandle"
|
||||
"Tags": [{"Value": {"Ref": "AWS::StackId"}, "Key": "Application"}],
|
||||
},
|
||||
},
|
||||
"WebServerWaitHandle": {"Type": "AWS::CloudFormation::WaitConditionHandle"},
|
||||
"Route": {
|
||||
"Type": "AWS::EC2::Route",
|
||||
"Properties": {
|
||||
"GatewayId": {
|
||||
"Ref": "InternetGateway"
|
||||
},
|
||||
"GatewayId": {"Ref": "InternetGateway"},
|
||||
"DestinationCidrBlock": "0.0.0.0/0",
|
||||
"RouteTableId": {
|
||||
"Ref": "RouteTable"
|
||||
}
|
||||
"RouteTableId": {"Ref": "RouteTable"},
|
||||
},
|
||||
"DependsOn": "AttachGateway"
|
||||
"DependsOn": "AttachGateway",
|
||||
},
|
||||
"SubnetRouteTableAssociation": {
|
||||
"Type": "AWS::EC2::SubnetRouteTableAssociation",
|
||||
"Properties": {
|
||||
"SubnetId": {
|
||||
"Ref": "Subnet"
|
||||
},
|
||||
"RouteTableId": {
|
||||
"Ref": "RouteTable"
|
||||
}
|
||||
}
|
||||
"SubnetId": {"Ref": "Subnet"},
|
||||
"RouteTableId": {"Ref": "RouteTable"},
|
||||
},
|
||||
},
|
||||
"InternetGateway": {
|
||||
"Type": "AWS::EC2::InternetGateway",
|
||||
"Properties": {
|
||||
"Tags": [
|
||||
{
|
||||
"Value": {
|
||||
"Ref": "AWS::StackId"
|
||||
},
|
||||
"Key": "Application"
|
||||
}
|
||||
]
|
||||
}
|
||||
"Tags": [{"Value": {"Ref": "AWS::StackId"}, "Key": "Application"}]
|
||||
},
|
||||
},
|
||||
"RouteTable": {
|
||||
"Type": "AWS::EC2::RouteTable",
|
||||
"Properties": {
|
||||
"VpcId": {
|
||||
"Ref": "VPC"
|
||||
},
|
||||
"Tags": [
|
||||
{
|
||||
"Value": {
|
||||
"Ref": "AWS::StackId"
|
||||
},
|
||||
"Key": "Application"
|
||||
}
|
||||
]
|
||||
}
|
||||
"VpcId": {"Ref": "VPC"},
|
||||
"Tags": [{"Value": {"Ref": "AWS::StackId"}, "Key": "Application"}],
|
||||
},
|
||||
},
|
||||
"WebServerWaitCondition": {
|
||||
"Type": "AWS::CloudFormation::WaitCondition",
|
||||
"Properties": {
|
||||
"Handle": {
|
||||
"Ref": "WebServerWaitHandle"
|
||||
},
|
||||
"Timeout": "300"
|
||||
},
|
||||
"DependsOn": "WebServerInstance"
|
||||
"Properties": {"Handle": {"Ref": "WebServerWaitHandle"}, "Timeout": "300"},
|
||||
"DependsOn": "WebServerInstance",
|
||||
},
|
||||
"VPC": {
|
||||
"Type": "AWS::EC2::VPC",
|
||||
"Properties": {
|
||||
"CidrBlock": "10.0.0.0/16",
|
||||
"Tags": [
|
||||
{
|
||||
"Value": {
|
||||
"Ref": "AWS::StackId"
|
||||
},
|
||||
"Key": "Application"
|
||||
}
|
||||
]
|
||||
}
|
||||
"Tags": [{"Value": {"Ref": "AWS::StackId"}, "Key": "Application"}],
|
||||
},
|
||||
},
|
||||
"InstanceSecurityGroup": {
|
||||
"Type": "AWS::EC2::SecurityGroup",
|
||||
|
|
@ -169,23 +114,19 @@ template = {
|
|||
{
|
||||
"ToPort": "22",
|
||||
"IpProtocol": "tcp",
|
||||
"CidrIp": {
|
||||
"Ref": "SSHLocation"
|
||||
},
|
||||
"FromPort": "22"
|
||||
"CidrIp": {"Ref": "SSHLocation"},
|
||||
"FromPort": "22",
|
||||
},
|
||||
{
|
||||
"ToPort": "80",
|
||||
"IpProtocol": "tcp",
|
||||
"CidrIp": "0.0.0.0/0",
|
||||
"FromPort": "80"
|
||||
}
|
||||
"FromPort": "80",
|
||||
},
|
||||
],
|
||||
"VpcId": {
|
||||
"Ref": "VPC"
|
||||
},
|
||||
"GroupDescription": "Enable SSH access via port 22"
|
||||
}
|
||||
"VpcId": {"Ref": "VPC"},
|
||||
"GroupDescription": "Enable SSH access via port 22",
|
||||
},
|
||||
},
|
||||
"WebServerInstance": {
|
||||
"Type": "AWS::EC2::Instance",
|
||||
|
|
@ -200,71 +141,39 @@ template = {
|
|||
"# Helper function\n",
|
||||
"function error_exit\n",
|
||||
"{\n",
|
||||
" /opt/aws/bin/cfn-signal -e 1 -r \"$1\" '",
|
||||
{
|
||||
"Ref": "WebServerWaitHandle"
|
||||
},
|
||||
' /opt/aws/bin/cfn-signal -e 1 -r "$1" \'',
|
||||
{"Ref": "WebServerWaitHandle"},
|
||||
"'\n",
|
||||
" exit 1\n",
|
||||
"}\n",
|
||||
"# Install the simple web page\n",
|
||||
"/opt/aws/bin/cfn-init -s ",
|
||||
{
|
||||
"Ref": "AWS::StackId"
|
||||
},
|
||||
{"Ref": "AWS::StackId"},
|
||||
" -r WebServerInstance ",
|
||||
" --region ",
|
||||
{
|
||||
"Ref": "AWS::Region"
|
||||
},
|
||||
{"Ref": "AWS::Region"},
|
||||
" || error_exit 'Failed to run cfn-init'\n",
|
||||
"# Start up the cfn-hup daemon to listen for changes to the Web Server metadata\n",
|
||||
"/opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup'\n",
|
||||
"# All done so signal success\n",
|
||||
"/opt/aws/bin/cfn-signal -e 0 -r \"WebServer setup complete\" '",
|
||||
{
|
||||
"Ref": "WebServerWaitHandle"
|
||||
},
|
||||
"'\n"
|
||||
]
|
||||
'/opt/aws/bin/cfn-signal -e 0 -r "WebServer setup complete" \'',
|
||||
{"Ref": "WebServerWaitHandle"},
|
||||
"'\n",
|
||||
],
|
||||
]
|
||||
}
|
||||
},
|
||||
"Tags": [
|
||||
{
|
||||
"Value": {
|
||||
"Ref": "AWS::StackId"
|
||||
},
|
||||
"Key": "Application"
|
||||
},
|
||||
{
|
||||
"Value": "Bar",
|
||||
"Key": "Foo"
|
||||
}
|
||||
{"Value": {"Ref": "AWS::StackId"}, "Key": "Application"},
|
||||
{"Value": "Bar", "Key": "Foo"},
|
||||
],
|
||||
"SecurityGroupIds": [
|
||||
{
|
||||
"Ref": "InstanceSecurityGroup"
|
||||
}
|
||||
],
|
||||
"KeyName": {
|
||||
"Ref": "KeyName"
|
||||
},
|
||||
"SubnetId": {
|
||||
"Ref": "Subnet"
|
||||
},
|
||||
"SecurityGroupIds": [{"Ref": "InstanceSecurityGroup"}],
|
||||
"KeyName": {"Ref": "KeyName"},
|
||||
"SubnetId": {"Ref": "Subnet"},
|
||||
"ImageId": {
|
||||
"Fn::FindInMap": [
|
||||
"RegionMap",
|
||||
{
|
||||
"Ref": "AWS::Region"
|
||||
},
|
||||
"AMI"
|
||||
]
|
||||
"Fn::FindInMap": ["RegionMap", {"Ref": "AWS::Region"}, "AMI"]
|
||||
},
|
||||
"InstanceType": {
|
||||
"Ref": "InstanceType"
|
||||
}
|
||||
"InstanceType": {"Ref": "InstanceType"},
|
||||
},
|
||||
"Metadata": {
|
||||
"Comment": "Install a simple PHP application",
|
||||
|
|
@ -278,21 +187,17 @@ template = {
|
|||
[
|
||||
"[main]\n",
|
||||
"stack=",
|
||||
{
|
||||
"Ref": "AWS::StackId"
|
||||
},
|
||||
{"Ref": "AWS::StackId"},
|
||||
"\n",
|
||||
"region=",
|
||||
{
|
||||
"Ref": "AWS::Region"
|
||||
},
|
||||
"\n"
|
||||
]
|
||||
{"Ref": "AWS::Region"},
|
||||
"\n",
|
||||
],
|
||||
]
|
||||
},
|
||||
"owner": "root",
|
||||
"group": "root",
|
||||
"mode": "000400"
|
||||
"mode": "000400",
|
||||
},
|
||||
"/etc/cfn/hooks.d/cfn-auto-reloader.conf": {
|
||||
"content": {
|
||||
|
|
@ -303,17 +208,13 @@ template = {
|
|||
"triggers=post.update\n",
|
||||
"path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init\n",
|
||||
"action=/opt/aws/bin/cfn-init -s ",
|
||||
{
|
||||
"Ref": "AWS::StackId"
|
||||
},
|
||||
{"Ref": "AWS::StackId"},
|
||||
" -r WebServerInstance ",
|
||||
" --region ",
|
||||
{
|
||||
"Ref": "AWS::Region"
|
||||
},
|
||||
{"Ref": "AWS::Region"},
|
||||
"\n",
|
||||
"runas=root\n"
|
||||
]
|
||||
"runas=root\n",
|
||||
],
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
@ -324,85 +225,52 @@ template = {
|
|||
[
|
||||
"<?php\n",
|
||||
"echo '<h1>AWS CloudFormation sample PHP application</h1>';\n",
|
||||
"?>\n"
|
||||
]
|
||||
"?>\n",
|
||||
],
|
||||
]
|
||||
},
|
||||
"owner": "apache",
|
||||
"group": "apache",
|
||||
"mode": "000644"
|
||||
}
|
||||
"mode": "000644",
|
||||
},
|
||||
},
|
||||
"services": {
|
||||
"sysvinit": {
|
||||
"httpd": {
|
||||
"ensureRunning": "true",
|
||||
"enabled": "true"
|
||||
},
|
||||
"httpd": {"ensureRunning": "true", "enabled": "true"},
|
||||
"sendmail": {
|
||||
"ensureRunning": "false",
|
||||
"enabled": "false"
|
||||
}
|
||||
"enabled": "false",
|
||||
},
|
||||
}
|
||||
},
|
||||
"packages": {
|
||||
"yum": {
|
||||
"httpd": [],
|
||||
"php": []
|
||||
}
|
||||
}
|
||||
"packages": {"yum": {"httpd": [], "php": []}},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
"IPAddress": {
|
||||
"Type": "AWS::EC2::EIP",
|
||||
"Properties": {
|
||||
"InstanceId": {
|
||||
"Ref": "WebServerInstance"
|
||||
},
|
||||
"Domain": "vpc"
|
||||
},
|
||||
"DependsOn": "AttachGateway"
|
||||
"Properties": {"InstanceId": {"Ref": "WebServerInstance"}, "Domain": "vpc"},
|
||||
"DependsOn": "AttachGateway",
|
||||
},
|
||||
"AttachGateway": {
|
||||
"Type": "AWS::EC2::VPCGatewayAttachment",
|
||||
"Properties": {
|
||||
"VpcId": {
|
||||
"Ref": "VPC"
|
||||
},
|
||||
"InternetGatewayId": {
|
||||
"Ref": "InternetGateway"
|
||||
}
|
||||
}
|
||||
}
|
||||
"VpcId": {"Ref": "VPC"},
|
||||
"InternetGatewayId": {"Ref": "InternetGateway"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"Mappings": {
|
||||
"RegionMap": {
|
||||
"ap-southeast-1": {
|
||||
"AMI": "ami-74dda626"
|
||||
},
|
||||
"ap-southeast-2": {
|
||||
"AMI": "ami-b3990e89"
|
||||
},
|
||||
"us-west-2": {
|
||||
"AMI": "ami-16fd7026"
|
||||
},
|
||||
"us-east-1": {
|
||||
"AMI": "ami-7f418316"
|
||||
},
|
||||
"ap-northeast-1": {
|
||||
"AMI": "ami-dcfa4edd"
|
||||
},
|
||||
"us-west-1": {
|
||||
"AMI": "ami-951945d0"
|
||||
},
|
||||
"eu-west-1": {
|
||||
"AMI": "ami-24506250"
|
||||
},
|
||||
"sa-east-1": {
|
||||
"AMI": "ami-3e3be423"
|
||||
}
|
||||
"ap-southeast-1": {"AMI": "ami-74dda626"},
|
||||
"ap-southeast-2": {"AMI": "ami-b3990e89"},
|
||||
"us-west-2": {"AMI": "ami-16fd7026"},
|
||||
"us-east-1": {"AMI": "ami-7f418316"},
|
||||
"ap-northeast-1": {"AMI": "ami-dcfa4edd"},
|
||||
"us-west-1": {"AMI": "ami-951945d0"},
|
||||
"eu-west-1": {"AMI": "ami-24506250"},
|
||||
"sa-east-1": {"AMI": "ami-3e3be423"},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,24 @@ import os
|
|||
import json
|
||||
|
||||
import boto
|
||||
import boto.iam
|
||||
import boto.s3
|
||||
import boto.s3.key
|
||||
import boto.cloudformation
|
||||
from boto.exception import BotoServerError
|
||||
import sure # noqa
|
||||
|
||||
# Ensure 'assert_raises' context manager support for Python 2.6
|
||||
import tests.backport_assert_raises # noqa
|
||||
from nose.tools import assert_raises
|
||||
from moto.core import ACCOUNT_ID
|
||||
|
||||
from moto import mock_cloudformation_deprecated, mock_s3_deprecated, mock_route53_deprecated
|
||||
from moto import (
|
||||
mock_cloudformation_deprecated,
|
||||
mock_s3_deprecated,
|
||||
mock_route53_deprecated,
|
||||
mock_iam_deprecated,
|
||||
)
|
||||
from moto.cloudformation import cloudformation_backends
|
||||
|
||||
dummy_template = {
|
||||
|
|
@ -33,12 +41,7 @@ dummy_template3 = {
|
|||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack 3",
|
||||
"Resources": {
|
||||
"VPC": {
|
||||
"Properties": {
|
||||
"CidrBlock": "192.168.0.0/16",
|
||||
},
|
||||
"Type": "AWS::EC2::VPC"
|
||||
}
|
||||
"VPC": {"Properties": {"CidrBlock": "192.168.0.0/16"}, "Type": "AWS::EC2::VPC"}
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -50,24 +53,22 @@ dummy_template_json3 = json.dumps(dummy_template3)
|
|||
@mock_cloudformation_deprecated
|
||||
def test_create_stack():
|
||||
conn = boto.connect_cloudformation()
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
)
|
||||
conn.create_stack("test_stack", template_body=dummy_template_json)
|
||||
|
||||
stack = conn.describe_stacks()[0]
|
||||
stack.stack_name.should.equal('test_stack')
|
||||
stack.get_template().should.equal({
|
||||
'GetTemplateResponse': {
|
||||
'GetTemplateResult': {
|
||||
'TemplateBody': dummy_template_json,
|
||||
'ResponseMetadata': {
|
||||
'RequestId': '2d06e36c-ac1d-11e0-a958-f9382b6eb86bEXAMPLE'
|
||||
stack.stack_name.should.equal("test_stack")
|
||||
stack.get_template().should.equal(
|
||||
{
|
||||
"GetTemplateResponse": {
|
||||
"GetTemplateResult": {
|
||||
"TemplateBody": dummy_template_json,
|
||||
"ResponseMetadata": {
|
||||
"RequestId": "2d06e36c-ac1d-11e0-a958-f9382b6eb86bEXAMPLE"
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
|
|
@ -77,44 +78,34 @@ def test_create_stack_hosted_zone_by_id():
|
|||
dummy_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack 1",
|
||||
"Parameters": {
|
||||
},
|
||||
"Parameters": {},
|
||||
"Resources": {
|
||||
"Bar": {
|
||||
"Type" : "AWS::Route53::HostedZone",
|
||||
"Properties" : {
|
||||
"Name" : "foo.bar.baz",
|
||||
}
|
||||
},
|
||||
"Type": "AWS::Route53::HostedZone",
|
||||
"Properties": {"Name": "foo.bar.baz"},
|
||||
}
|
||||
},
|
||||
}
|
||||
dummy_template2 = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack 2",
|
||||
"Parameters": {
|
||||
"ZoneId": { "Type": "String" }
|
||||
},
|
||||
"Parameters": {"ZoneId": {"Type": "String"}},
|
||||
"Resources": {
|
||||
"Foo": {
|
||||
"Properties": {
|
||||
"HostedZoneId": {"Ref": "ZoneId"},
|
||||
"RecordSets": []
|
||||
},
|
||||
"Type": "AWS::Route53::RecordSetGroup"
|
||||
"Properties": {"HostedZoneId": {"Ref": "ZoneId"}, "RecordSets": []},
|
||||
"Type": "AWS::Route53::RecordSetGroup",
|
||||
}
|
||||
},
|
||||
}
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=json.dumps(dummy_template),
|
||||
parameters={}.items()
|
||||
"test_stack", template_body=json.dumps(dummy_template), parameters={}.items()
|
||||
)
|
||||
r53_conn = boto.connect_route53()
|
||||
zone_id = r53_conn.get_zones()[0].id
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=json.dumps(dummy_template2),
|
||||
parameters={"ZoneId": zone_id}.items()
|
||||
parameters={"ZoneId": zone_id}.items(),
|
||||
)
|
||||
|
||||
stack = conn.describe_stacks()[0]
|
||||
|
|
@ -139,62 +130,57 @@ def test_create_stack_with_notification_arn():
|
|||
conn.create_stack(
|
||||
"test_stack_with_notifications",
|
||||
template_body=dummy_template_json,
|
||||
notification_arns='arn:aws:sns:us-east-1:123456789012:fake-queue'
|
||||
notification_arns="arn:aws:sns:us-east-1:{}:fake-queue".format(ACCOUNT_ID),
|
||||
)
|
||||
|
||||
stack = conn.describe_stacks()[0]
|
||||
[n.value for n in stack.notification_arns].should.contain(
|
||||
'arn:aws:sns:us-east-1:123456789012:fake-queue')
|
||||
"arn:aws:sns:us-east-1:{}:fake-queue".format(ACCOUNT_ID)
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
@mock_s3_deprecated
|
||||
def test_create_stack_from_s3_url():
|
||||
s3_conn = boto.s3.connect_to_region('us-west-1')
|
||||
s3_conn = boto.s3.connect_to_region("us-west-1")
|
||||
bucket = s3_conn.create_bucket("foobar")
|
||||
key = boto.s3.key.Key(bucket)
|
||||
key.key = "template-key"
|
||||
key.set_contents_from_string(dummy_template_json)
|
||||
key_url = key.generate_url(expires_in=0, query_auth=False)
|
||||
|
||||
conn = boto.cloudformation.connect_to_region('us-west-1')
|
||||
conn.create_stack('new-stack', template_url=key_url)
|
||||
conn = boto.cloudformation.connect_to_region("us-west-1")
|
||||
conn.create_stack("new-stack", template_url=key_url)
|
||||
|
||||
stack = conn.describe_stacks()[0]
|
||||
stack.stack_name.should.equal('new-stack')
|
||||
stack.stack_name.should.equal("new-stack")
|
||||
stack.get_template().should.equal(
|
||||
{
|
||||
'GetTemplateResponse': {
|
||||
'GetTemplateResult': {
|
||||
'TemplateBody': dummy_template_json,
|
||||
'ResponseMetadata': {
|
||||
'RequestId': '2d06e36c-ac1d-11e0-a958-f9382b6eb86bEXAMPLE'
|
||||
}
|
||||
"GetTemplateResponse": {
|
||||
"GetTemplateResult": {
|
||||
"TemplateBody": dummy_template_json,
|
||||
"ResponseMetadata": {
|
||||
"RequestId": "2d06e36c-ac1d-11e0-a958-f9382b6eb86bEXAMPLE"
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
def test_describe_stack_by_name():
|
||||
conn = boto.connect_cloudformation()
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
)
|
||||
conn.create_stack("test_stack", template_body=dummy_template_json)
|
||||
|
||||
stack = conn.describe_stacks("test_stack")[0]
|
||||
stack.stack_name.should.equal('test_stack')
|
||||
stack.stack_name.should.equal("test_stack")
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
def test_describe_stack_by_stack_id():
|
||||
conn = boto.connect_cloudformation()
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
)
|
||||
conn.create_stack("test_stack", template_body=dummy_template_json)
|
||||
|
||||
stack = conn.describe_stacks("test_stack")[0]
|
||||
stack_by_id = conn.describe_stacks(stack.stack_id)[0]
|
||||
|
|
@ -205,10 +191,7 @@ def test_describe_stack_by_stack_id():
|
|||
@mock_cloudformation_deprecated
|
||||
def test_describe_deleted_stack():
|
||||
conn = boto.connect_cloudformation()
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
)
|
||||
conn.create_stack("test_stack", template_body=dummy_template_json)
|
||||
|
||||
stack = conn.describe_stacks("test_stack")[0]
|
||||
stack_id = stack.stack_id
|
||||
|
|
@ -222,36 +205,28 @@ def test_describe_deleted_stack():
|
|||
@mock_cloudformation_deprecated
|
||||
def test_get_template_by_name():
|
||||
conn = boto.connect_cloudformation()
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
)
|
||||
conn.create_stack("test_stack", template_body=dummy_template_json)
|
||||
|
||||
template = conn.get_template("test_stack")
|
||||
template.should.equal({
|
||||
'GetTemplateResponse': {
|
||||
'GetTemplateResult': {
|
||||
'TemplateBody': dummy_template_json,
|
||||
'ResponseMetadata': {
|
||||
'RequestId': '2d06e36c-ac1d-11e0-a958-f9382b6eb86bEXAMPLE'
|
||||
template.should.equal(
|
||||
{
|
||||
"GetTemplateResponse": {
|
||||
"GetTemplateResult": {
|
||||
"TemplateBody": dummy_template_json,
|
||||
"ResponseMetadata": {
|
||||
"RequestId": "2d06e36c-ac1d-11e0-a958-f9382b6eb86bEXAMPLE"
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
def test_list_stacks():
|
||||
conn = boto.connect_cloudformation()
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
)
|
||||
conn.create_stack(
|
||||
"test_stack2",
|
||||
template_body=dummy_template_json,
|
||||
)
|
||||
conn.create_stack("test_stack", template_body=dummy_template_json)
|
||||
conn.create_stack("test_stack2", template_body=dummy_template_json)
|
||||
|
||||
stacks = conn.list_stacks()
|
||||
stacks.should.have.length_of(2)
|
||||
|
|
@ -261,10 +236,7 @@ def test_list_stacks():
|
|||
@mock_cloudformation_deprecated
|
||||
def test_delete_stack_by_name():
|
||||
conn = boto.connect_cloudformation()
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
)
|
||||
conn.create_stack("test_stack", template_body=dummy_template_json)
|
||||
|
||||
conn.describe_stacks().should.have.length_of(1)
|
||||
conn.delete_stack("test_stack")
|
||||
|
|
@ -274,10 +246,7 @@ def test_delete_stack_by_name():
|
|||
@mock_cloudformation_deprecated
|
||||
def test_delete_stack_by_id():
|
||||
conn = boto.connect_cloudformation()
|
||||
stack_id = conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
)
|
||||
stack_id = conn.create_stack("test_stack", template_body=dummy_template_json)
|
||||
|
||||
conn.describe_stacks().should.have.length_of(1)
|
||||
conn.delete_stack(stack_id)
|
||||
|
|
@ -291,10 +260,7 @@ def test_delete_stack_by_id():
|
|||
@mock_cloudformation_deprecated
|
||||
def test_delete_stack_with_resource_missing_delete_attr():
|
||||
conn = boto.connect_cloudformation()
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json3,
|
||||
)
|
||||
conn.create_stack("test_stack", template_body=dummy_template_json3)
|
||||
|
||||
conn.describe_stacks().should.have.length_of(1)
|
||||
conn.delete_stack("test_stack")
|
||||
|
|
@ -318,19 +284,22 @@ def test_cloudformation_params():
|
|||
"APPNAME": {
|
||||
"Default": "app-name",
|
||||
"Description": "The name of the app",
|
||||
"Type": "String"
|
||||
"Type": "String",
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
dummy_template_json = json.dumps(dummy_template)
|
||||
cfn = boto.connect_cloudformation()
|
||||
cfn.create_stack('test_stack1', template_body=dummy_template_json, parameters=[
|
||||
('APPNAME', 'testing123')])
|
||||
stack = cfn.describe_stacks('test_stack1')[0]
|
||||
cfn.create_stack(
|
||||
"test_stack1",
|
||||
template_body=dummy_template_json,
|
||||
parameters=[("APPNAME", "testing123")],
|
||||
)
|
||||
stack = cfn.describe_stacks("test_stack1")[0]
|
||||
stack.parameters.should.have.length_of(1)
|
||||
param = stack.parameters[0]
|
||||
param.key.should.equal('APPNAME')
|
||||
param.value.should.equal('testing123')
|
||||
param.key.should.equal("APPNAME")
|
||||
param.value.should.equal("testing123")
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
|
|
@ -339,52 +308,34 @@ def test_cloudformation_params_conditions_and_resources_are_distinct():
|
|||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack 1",
|
||||
"Conditions": {
|
||||
"FooEnabled": {
|
||||
"Fn::Equals": [
|
||||
{
|
||||
"Ref": "FooEnabled"
|
||||
},
|
||||
"true"
|
||||
]
|
||||
},
|
||||
"FooEnabled": {"Fn::Equals": [{"Ref": "FooEnabled"}, "true"]},
|
||||
"FooDisabled": {
|
||||
"Fn::Not": [
|
||||
{
|
||||
"Fn::Equals": [
|
||||
{
|
||||
"Ref": "FooEnabled"
|
||||
},
|
||||
"true"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"Fn::Not": [{"Fn::Equals": [{"Ref": "FooEnabled"}, "true"]}]
|
||||
},
|
||||
},
|
||||
"Parameters": {
|
||||
"FooEnabled": {
|
||||
"Type": "String",
|
||||
"AllowedValues": [
|
||||
"true",
|
||||
"false"
|
||||
]
|
||||
}
|
||||
"FooEnabled": {"Type": "String", "AllowedValues": ["true", "false"]}
|
||||
},
|
||||
"Resources": {
|
||||
"Bar": {
|
||||
"Properties": {
|
||||
"CidrBlock": "192.168.0.0/16",
|
||||
},
|
||||
"Properties": {"CidrBlock": "192.168.0.0/16"},
|
||||
"Condition": "FooDisabled",
|
||||
"Type": "AWS::EC2::VPC"
|
||||
"Type": "AWS::EC2::VPC",
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
dummy_template_json = json.dumps(dummy_template)
|
||||
cfn = boto.connect_cloudformation()
|
||||
cfn.create_stack('test_stack1', template_body=dummy_template_json, parameters=[('FooEnabled', 'true')])
|
||||
stack = cfn.describe_stacks('test_stack1')[0]
|
||||
cfn.create_stack(
|
||||
"test_stack1",
|
||||
template_body=dummy_template_json,
|
||||
parameters=[("FooEnabled", "true")],
|
||||
)
|
||||
stack = cfn.describe_stacks("test_stack1")[0]
|
||||
resources = stack.list_resources()
|
||||
assert not [resource for resource in resources if resource.logical_resource_id == 'Bar']
|
||||
assert not [
|
||||
resource for resource in resources if resource.logical_resource_id == "Bar"
|
||||
]
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
|
|
@ -403,48 +354,46 @@ def test_stack_tags():
|
|||
@mock_cloudformation_deprecated
|
||||
def test_update_stack():
|
||||
conn = boto.connect_cloudformation()
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
)
|
||||
conn.create_stack("test_stack", template_body=dummy_template_json)
|
||||
|
||||
conn.update_stack("test_stack", dummy_template_json2)
|
||||
|
||||
stack = conn.describe_stacks()[0]
|
||||
stack.stack_status.should.equal("UPDATE_COMPLETE")
|
||||
stack.get_template().should.equal({
|
||||
'GetTemplateResponse': {
|
||||
'GetTemplateResult': {
|
||||
'TemplateBody': dummy_template_json2,
|
||||
'ResponseMetadata': {
|
||||
'RequestId': '2d06e36c-ac1d-11e0-a958-f9382b6eb86bEXAMPLE'
|
||||
stack.get_template().should.equal(
|
||||
{
|
||||
"GetTemplateResponse": {
|
||||
"GetTemplateResult": {
|
||||
"TemplateBody": dummy_template_json2,
|
||||
"ResponseMetadata": {
|
||||
"RequestId": "2d06e36c-ac1d-11e0-a958-f9382b6eb86bEXAMPLE"
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
def test_update_stack_with_previous_template():
|
||||
conn = boto.connect_cloudformation()
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
)
|
||||
conn.create_stack("test_stack", template_body=dummy_template_json)
|
||||
conn.update_stack("test_stack", use_previous_template=True)
|
||||
|
||||
stack = conn.describe_stacks()[0]
|
||||
stack.stack_status.should.equal("UPDATE_COMPLETE")
|
||||
stack.get_template().should.equal({
|
||||
'GetTemplateResponse': {
|
||||
'GetTemplateResult': {
|
||||
'TemplateBody': dummy_template_json,
|
||||
'ResponseMetadata': {
|
||||
'RequestId': '2d06e36c-ac1d-11e0-a958-f9382b6eb86bEXAMPLE'
|
||||
stack.get_template().should.equal(
|
||||
{
|
||||
"GetTemplateResponse": {
|
||||
"GetTemplateResult": {
|
||||
"TemplateBody": dummy_template_json,
|
||||
"ResponseMetadata": {
|
||||
"RequestId": "2d06e36c-ac1d-11e0-a958-f9382b6eb86bEXAMPLE"
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
|
|
@ -454,29 +403,23 @@ def test_update_stack_with_parameters():
|
|||
"Description": "Stack",
|
||||
"Resources": {
|
||||
"VPC": {
|
||||
"Properties": {
|
||||
"CidrBlock": {"Ref": "Bar"}
|
||||
},
|
||||
"Type": "AWS::EC2::VPC"
|
||||
"Properties": {"CidrBlock": {"Ref": "Bar"}},
|
||||
"Type": "AWS::EC2::VPC",
|
||||
}
|
||||
},
|
||||
"Parameters": {
|
||||
"Bar": {
|
||||
"Type": "String"
|
||||
}
|
||||
}
|
||||
"Parameters": {"Bar": {"Type": "String"}},
|
||||
}
|
||||
dummy_template_json = json.dumps(dummy_template)
|
||||
conn = boto.connect_cloudformation()
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
parameters=[("Bar", "192.168.0.0/16")]
|
||||
parameters=[("Bar", "192.168.0.0/16")],
|
||||
)
|
||||
conn.update_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
parameters=[("Bar", "192.168.0.1/16")]
|
||||
parameters=[("Bar", "192.168.0.1/16")],
|
||||
)
|
||||
|
||||
stack = conn.describe_stacks()[0]
|
||||
|
|
@ -487,14 +430,10 @@ def test_update_stack_with_parameters():
|
|||
def test_update_stack_replace_tags():
|
||||
conn = boto.connect_cloudformation()
|
||||
conn.create_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
tags={"foo": "bar"},
|
||||
"test_stack", template_body=dummy_template_json, tags={"foo": "bar"}
|
||||
)
|
||||
conn.update_stack(
|
||||
"test_stack",
|
||||
template_body=dummy_template_json,
|
||||
tags={"foo": "baz"},
|
||||
"test_stack", template_body=dummy_template_json, tags={"foo": "baz"}
|
||||
)
|
||||
|
||||
stack = conn.describe_stacks()[0]
|
||||
|
|
@ -506,28 +445,26 @@ def test_update_stack_replace_tags():
|
|||
@mock_cloudformation_deprecated
|
||||
def test_update_stack_when_rolled_back():
|
||||
conn = boto.connect_cloudformation()
|
||||
stack_id = conn.create_stack(
|
||||
"test_stack", template_body=dummy_template_json)
|
||||
stack_id = conn.create_stack("test_stack", template_body=dummy_template_json)
|
||||
|
||||
cloudformation_backends[conn.region.name].stacks[
|
||||
stack_id].status = 'ROLLBACK_COMPLETE'
|
||||
stack_id
|
||||
].status = "ROLLBACK_COMPLETE"
|
||||
|
||||
with assert_raises(BotoServerError) as err:
|
||||
conn.update_stack("test_stack", dummy_template_json)
|
||||
|
||||
ex = err.exception
|
||||
ex.body.should.match(
|
||||
r'is in ROLLBACK_COMPLETE state and can not be updated')
|
||||
ex.error_code.should.equal('ValidationError')
|
||||
ex.reason.should.equal('Bad Request')
|
||||
ex.body.should.match(r"is in ROLLBACK_COMPLETE state and can not be updated")
|
||||
ex.error_code.should.equal("ValidationError")
|
||||
ex.reason.should.equal("Bad Request")
|
||||
ex.status.should.equal(400)
|
||||
|
||||
|
||||
@mock_cloudformation_deprecated
|
||||
def test_describe_stack_events_shows_create_update_and_delete():
|
||||
conn = boto.connect_cloudformation()
|
||||
stack_id = conn.create_stack(
|
||||
"test_stack", template_body=dummy_template_json)
|
||||
stack_id = conn.create_stack("test_stack", template_body=dummy_template_json)
|
||||
conn.update_stack(stack_id, template_body=dummy_template_json2)
|
||||
conn.delete_stack(stack_id)
|
||||
|
||||
|
|
@ -538,14 +475,16 @@ def test_describe_stack_events_shows_create_update_and_delete():
|
|||
|
||||
# testing ordering of stack events without assuming resource events will not exist
|
||||
# the AWS API returns events in reverse chronological order
|
||||
stack_events_to_look_for = iter([
|
||||
("DELETE_COMPLETE", None),
|
||||
("DELETE_IN_PROGRESS", "User Initiated"),
|
||||
("UPDATE_COMPLETE", None),
|
||||
("UPDATE_IN_PROGRESS", "User Initiated"),
|
||||
("CREATE_COMPLETE", None),
|
||||
("CREATE_IN_PROGRESS", "User Initiated"),
|
||||
])
|
||||
stack_events_to_look_for = iter(
|
||||
[
|
||||
("DELETE_COMPLETE", None),
|
||||
("DELETE_IN_PROGRESS", "User Initiated"),
|
||||
("UPDATE_COMPLETE", None),
|
||||
("UPDATE_IN_PROGRESS", "User Initiated"),
|
||||
("CREATE_COMPLETE", None),
|
||||
("CREATE_IN_PROGRESS", "User Initiated"),
|
||||
]
|
||||
)
|
||||
try:
|
||||
for event in events:
|
||||
event.stack_id.should.equal(stack_id)
|
||||
|
|
@ -556,12 +495,10 @@ def test_describe_stack_events_shows_create_update_and_delete():
|
|||
event.logical_resource_id.should.equal("test_stack")
|
||||
event.physical_resource_id.should.equal(stack_id)
|
||||
|
||||
status_to_look_for, reason_to_look_for = next(
|
||||
stack_events_to_look_for)
|
||||
status_to_look_for, reason_to_look_for = next(stack_events_to_look_for)
|
||||
event.resource_status.should.equal(status_to_look_for)
|
||||
if reason_to_look_for is not None:
|
||||
event.resource_status_reason.should.equal(
|
||||
reason_to_look_for)
|
||||
event.resource_status_reason.should.equal(reason_to_look_for)
|
||||
except StopIteration:
|
||||
assert False, "Too many stack events"
|
||||
|
||||
|
|
@ -574,74 +511,60 @@ def test_create_stack_lambda_and_dynamodb():
|
|||
dummy_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack Lambda Test 1",
|
||||
"Parameters": {
|
||||
},
|
||||
"Parameters": {},
|
||||
"Resources": {
|
||||
"func1": {
|
||||
"Type" : "AWS::Lambda::Function",
|
||||
"Properties" : {
|
||||
"Code": {
|
||||
"S3Bucket": "bucket_123",
|
||||
"S3Key": "key_123"
|
||||
},
|
||||
"Type": "AWS::Lambda::Function",
|
||||
"Properties": {
|
||||
"Code": {"S3Bucket": "bucket_123", "S3Key": "key_123"},
|
||||
"FunctionName": "func1",
|
||||
"Handler": "handler.handler",
|
||||
"Role": "role1",
|
||||
"Role": get_role_name(),
|
||||
"Runtime": "python2.7",
|
||||
"Description": "descr",
|
||||
"MemorySize": 12345,
|
||||
}
|
||||
},
|
||||
},
|
||||
"func1version": {
|
||||
"Type": "AWS::Lambda::Version",
|
||||
"Properties": {
|
||||
"FunctionName": {
|
||||
"Ref": "func1"
|
||||
}
|
||||
}
|
||||
"Properties": {"FunctionName": {"Ref": "func1"}},
|
||||
},
|
||||
"tab1": {
|
||||
"Type" : "AWS::DynamoDB::Table",
|
||||
"Properties" : {
|
||||
"Type": "AWS::DynamoDB::Table",
|
||||
"Properties": {
|
||||
"TableName": "tab1",
|
||||
"KeySchema": [{
|
||||
"AttributeName": "attr1",
|
||||
"KeyType": "HASH"
|
||||
}],
|
||||
"AttributeDefinitions": [{
|
||||
"AttributeName": "attr1",
|
||||
"AttributeType": "string"
|
||||
}],
|
||||
"KeySchema": [{"AttributeName": "attr1", "KeyType": "HASH"}],
|
||||
"AttributeDefinitions": [
|
||||
{"AttributeName": "attr1", "AttributeType": "string"}
|
||||
],
|
||||
"ProvisionedThroughput": {
|
||||
"ReadCapacityUnits": 10,
|
||||
"WriteCapacityUnits": 10
|
||||
}
|
||||
}
|
||||
"WriteCapacityUnits": 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
"func1mapping": {
|
||||
"Type": "AWS::Lambda::EventSourceMapping",
|
||||
"Properties": {
|
||||
"FunctionName": {
|
||||
"Ref": "func1"
|
||||
},
|
||||
"FunctionName": {"Ref": "func1"},
|
||||
"EventSourceArn": "arn:aws:dynamodb:region:XXXXXX:table/tab1/stream/2000T00:00:00.000",
|
||||
"StartingPosition": "0",
|
||||
"BatchSize": 100,
|
||||
"Enabled": True
|
||||
}
|
||||
}
|
||||
"Enabled": True,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
validate_s3_before = os.environ.get('VALIDATE_LAMBDA_S3', '')
|
||||
validate_s3_before = os.environ.get("VALIDATE_LAMBDA_S3", "")
|
||||
try:
|
||||
os.environ['VALIDATE_LAMBDA_S3'] = 'false'
|
||||
os.environ["VALIDATE_LAMBDA_S3"] = "false"
|
||||
conn.create_stack(
|
||||
"test_stack_lambda_1",
|
||||
template_body=json.dumps(dummy_template),
|
||||
parameters={}.items()
|
||||
parameters={}.items(),
|
||||
)
|
||||
finally:
|
||||
os.environ['VALIDATE_LAMBDA_S3'] = validate_s3_before
|
||||
os.environ["VALIDATE_LAMBDA_S3"] = validate_s3_before
|
||||
|
||||
stack = conn.describe_stacks()[0]
|
||||
resources = stack.list_resources()
|
||||
|
|
@ -657,20 +580,26 @@ def test_create_stack_kinesis():
|
|||
"Parameters": {},
|
||||
"Resources": {
|
||||
"stream1": {
|
||||
"Type" : "AWS::Kinesis::Stream",
|
||||
"Properties" : {
|
||||
"Name": "stream1",
|
||||
"ShardCount": 2
|
||||
}
|
||||
"Type": "AWS::Kinesis::Stream",
|
||||
"Properties": {"Name": "stream1", "ShardCount": 2},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
conn.create_stack(
|
||||
"test_stack_kinesis_1",
|
||||
template_body=json.dumps(dummy_template),
|
||||
parameters={}.items()
|
||||
parameters={}.items(),
|
||||
)
|
||||
|
||||
stack = conn.describe_stacks()[0]
|
||||
resources = stack.list_resources()
|
||||
assert len(resources) == 1
|
||||
|
||||
|
||||
def get_role_name():
|
||||
with mock_iam_deprecated():
|
||||
iam = boto.connect_iam()
|
||||
role = iam.create_role("my-role")["create_role_response"]["create_role_result"][
|
||||
"role"
|
||||
]["arn"]
|
||||
return role
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,87 +1,89 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
# Standard library modules
|
||||
import unittest
|
||||
|
||||
# Third-party modules
|
||||
import boto3
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
# Package modules
|
||||
from moto import mock_cloudformation
|
||||
|
||||
AWS_REGION = 'us-west-1'
|
||||
|
||||
SG_STACK_NAME = 'simple-sg-stack'
|
||||
SG_TEMPLATE = """
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: Simple test CF template for moto_cloudformation
|
||||
|
||||
|
||||
Resources:
|
||||
SimpleSecurityGroup:
|
||||
Type: AWS::EC2::SecurityGroup
|
||||
Description: "A simple security group"
|
||||
Properties:
|
||||
GroupName: simple-security-group
|
||||
GroupDescription: "A simple security group"
|
||||
SecurityGroupEgress:
|
||||
-
|
||||
Description: "Egress to remote HTTPS servers"
|
||||
CidrIp: 0.0.0.0/0
|
||||
IpProtocol: tcp
|
||||
FromPort: 443
|
||||
ToPort: 443
|
||||
|
||||
Outputs:
|
||||
SimpleSecurityGroupName:
|
||||
Value: !GetAtt SimpleSecurityGroup.GroupId
|
||||
Export:
|
||||
Name: "SimpleSecurityGroup"
|
||||
|
||||
"""
|
||||
|
||||
EC2_STACK_NAME = 'simple-ec2-stack'
|
||||
EC2_TEMPLATE = """
|
||||
---
|
||||
# The latest template format version is "2010-09-09" and as of 2018-04-09
|
||||
# is currently the only valid value.
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: Simple test CF template for moto_cloudformation
|
||||
|
||||
|
||||
Resources:
|
||||
SimpleInstance:
|
||||
Type: AWS::EC2::Instance
|
||||
Properties:
|
||||
ImageId: ami-03cf127a
|
||||
InstanceType: t2.micro
|
||||
SecurityGroups: !Split [',', !ImportValue SimpleSecurityGroup]
|
||||
"""
|
||||
|
||||
|
||||
class TestSimpleInstance(unittest.TestCase):
|
||||
def test_simple_instance(self):
|
||||
"""Test that we can create a simple CloudFormation stack that imports values from an existing CloudFormation stack"""
|
||||
with mock_cloudformation():
|
||||
client = boto3.client('cloudformation', region_name=AWS_REGION)
|
||||
client.create_stack(StackName=SG_STACK_NAME, TemplateBody=SG_TEMPLATE)
|
||||
response = client.create_stack(StackName=EC2_STACK_NAME, TemplateBody=EC2_TEMPLATE)
|
||||
self.assertIn('StackId', response)
|
||||
response = client.describe_stacks(StackName=response['StackId'])
|
||||
self.assertIn('Stacks', response)
|
||||
stack_info = response['Stacks']
|
||||
self.assertEqual(1, len(stack_info))
|
||||
self.assertIn('StackName', stack_info[0])
|
||||
self.assertEqual(EC2_STACK_NAME, stack_info[0]['StackName'])
|
||||
|
||||
def test_simple_instance_missing_export(self):
|
||||
"""Test that we get an exception if a CloudFormation stack tries to imports a non-existent export value"""
|
||||
with mock_cloudformation():
|
||||
client = boto3.client('cloudformation', region_name=AWS_REGION)
|
||||
with self.assertRaises(ClientError) as e:
|
||||
client.create_stack(StackName=EC2_STACK_NAME, TemplateBody=EC2_TEMPLATE)
|
||||
self.assertIn('Error', e.exception.response)
|
||||
self.assertIn('Code', e.exception.response['Error'])
|
||||
self.assertEqual('ExportNotFound', e.exception.response['Error']['Code'])
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
# Standard library modules
|
||||
import unittest
|
||||
|
||||
# Third-party modules
|
||||
import boto3
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
# Package modules
|
||||
from moto import mock_cloudformation
|
||||
|
||||
AWS_REGION = "us-west-1"
|
||||
|
||||
SG_STACK_NAME = "simple-sg-stack"
|
||||
SG_TEMPLATE = """
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: Simple test CF template for moto_cloudformation
|
||||
|
||||
|
||||
Resources:
|
||||
SimpleSecurityGroup:
|
||||
Type: AWS::EC2::SecurityGroup
|
||||
Description: "A simple security group"
|
||||
Properties:
|
||||
GroupName: simple-security-group
|
||||
GroupDescription: "A simple security group"
|
||||
SecurityGroupEgress:
|
||||
-
|
||||
Description: "Egress to remote HTTPS servers"
|
||||
CidrIp: 0.0.0.0/0
|
||||
IpProtocol: tcp
|
||||
FromPort: 443
|
||||
ToPort: 443
|
||||
|
||||
Outputs:
|
||||
SimpleSecurityGroupName:
|
||||
Value: !GetAtt SimpleSecurityGroup.GroupId
|
||||
Export:
|
||||
Name: "SimpleSecurityGroup"
|
||||
|
||||
"""
|
||||
|
||||
EC2_STACK_NAME = "simple-ec2-stack"
|
||||
EC2_TEMPLATE = """
|
||||
---
|
||||
# The latest template format version is "2010-09-09" and as of 2018-04-09
|
||||
# is currently the only valid value.
|
||||
AWSTemplateFormatVersion: 2010-09-09
|
||||
Description: Simple test CF template for moto_cloudformation
|
||||
|
||||
|
||||
Resources:
|
||||
SimpleInstance:
|
||||
Type: AWS::EC2::Instance
|
||||
Properties:
|
||||
ImageId: ami-03cf127a
|
||||
InstanceType: t2.micro
|
||||
SecurityGroups: !Split [',', !ImportValue SimpleSecurityGroup]
|
||||
"""
|
||||
|
||||
|
||||
class TestSimpleInstance(unittest.TestCase):
|
||||
def test_simple_instance(self):
|
||||
"""Test that we can create a simple CloudFormation stack that imports values from an existing CloudFormation stack"""
|
||||
with mock_cloudformation():
|
||||
client = boto3.client("cloudformation", region_name=AWS_REGION)
|
||||
client.create_stack(StackName=SG_STACK_NAME, TemplateBody=SG_TEMPLATE)
|
||||
response = client.create_stack(
|
||||
StackName=EC2_STACK_NAME, TemplateBody=EC2_TEMPLATE
|
||||
)
|
||||
self.assertIn("StackId", response)
|
||||
response = client.describe_stacks(StackName=response["StackId"])
|
||||
self.assertIn("Stacks", response)
|
||||
stack_info = response["Stacks"]
|
||||
self.assertEqual(1, len(stack_info))
|
||||
self.assertIn("StackName", stack_info[0])
|
||||
self.assertEqual(EC2_STACK_NAME, stack_info[0]["StackName"])
|
||||
|
||||
def test_simple_instance_missing_export(self):
|
||||
"""Test that we get an exception if a CloudFormation stack tries to imports a non-existent export value"""
|
||||
with mock_cloudformation():
|
||||
client = boto3.client("cloudformation", region_name=AWS_REGION)
|
||||
with self.assertRaises(ClientError) as e:
|
||||
client.create_stack(StackName=EC2_STACK_NAME, TemplateBody=EC2_TEMPLATE)
|
||||
self.assertIn("Error", e.exception.response)
|
||||
self.assertIn("Code", e.exception.response["Error"])
|
||||
self.assertEqual("ExportNotFound", e.exception.response["Error"]["Code"])
|
||||
|
|
|
|||
|
|
@ -1,33 +1,36 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
from six.moves.urllib.parse import urlencode
|
||||
import re
|
||||
import sure # noqa
|
||||
|
||||
import moto.server as server
|
||||
|
||||
'''
|
||||
Test the different server responses
|
||||
'''
|
||||
|
||||
|
||||
def test_cloudformation_server_get():
|
||||
backend = server.create_backend_app("cloudformation")
|
||||
stack_name = 'test stack'
|
||||
test_client = backend.test_client()
|
||||
template_body = {
|
||||
"Resources": {},
|
||||
}
|
||||
create_stack_resp = test_client.action_data("CreateStack", StackName=stack_name,
|
||||
TemplateBody=json.dumps(template_body))
|
||||
create_stack_resp.should.match(
|
||||
r"<CreateStackResponse>.*<CreateStackResult>.*<StackId>.*</StackId>.*</CreateStackResult>.*</CreateStackResponse>", re.DOTALL)
|
||||
stack_id_from_create_response = re.search(
|
||||
"<StackId>(.*)</StackId>", create_stack_resp).groups()[0]
|
||||
|
||||
list_stacks_resp = test_client.action_data("ListStacks")
|
||||
stack_id_from_list_response = re.search(
|
||||
"<StackId>(.*)</StackId>", list_stacks_resp).groups()[0]
|
||||
|
||||
stack_id_from_create_response.should.equal(stack_id_from_list_response)
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
from six.moves.urllib.parse import urlencode
|
||||
import re
|
||||
import sure # noqa
|
||||
|
||||
import moto.server as server
|
||||
|
||||
"""
|
||||
Test the different server responses
|
||||
"""
|
||||
|
||||
|
||||
def test_cloudformation_server_get():
|
||||
backend = server.create_backend_app("cloudformation")
|
||||
stack_name = "test stack"
|
||||
test_client = backend.test_client()
|
||||
template_body = {"Resources": {}}
|
||||
create_stack_resp = test_client.action_data(
|
||||
"CreateStack", StackName=stack_name, TemplateBody=json.dumps(template_body)
|
||||
)
|
||||
create_stack_resp.should.match(
|
||||
r"<CreateStackResponse>.*<CreateStackResult>.*<StackId>.*</StackId>.*</CreateStackResult>.*</CreateStackResponse>",
|
||||
re.DOTALL,
|
||||
)
|
||||
stack_id_from_create_response = re.search(
|
||||
"<StackId>(.*)</StackId>", create_stack_resp
|
||||
).groups()[0]
|
||||
|
||||
list_stacks_resp = test_client.action_data("ListStacks")
|
||||
stack_id_from_list_response = re.search(
|
||||
"<StackId>(.*)</StackId>", list_stacks_resp
|
||||
).groups()[0]
|
||||
|
||||
stack_id_from_create_response.should.equal(stack_id_from_list_response)
|
||||
|
|
|
|||
|
|
@ -7,91 +7,57 @@ import sure # noqa
|
|||
|
||||
from moto.cloudformation.exceptions import ValidationError
|
||||
from moto.cloudformation.models import FakeStack
|
||||
from moto.cloudformation.parsing import resource_class_from_type, parse_condition, Export
|
||||
from moto.cloudformation.parsing import (
|
||||
resource_class_from_type,
|
||||
parse_condition,
|
||||
Export,
|
||||
)
|
||||
from moto.sqs.models import Queue
|
||||
from moto.s3.models import FakeBucket
|
||||
from moto.cloudformation.utils import yaml_tag_constructor
|
||||
from boto.cloudformation.stack import Output
|
||||
|
||||
|
||||
|
||||
dummy_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
|
||||
"Description": "Create a multi-az, load balanced, Auto Scaled sample web site. The Auto Scaling trigger is based on the CPU utilization of the web servers. The AMI is chosen based on the region in which the stack is run. This example creates a web service running across all availability zones in a region. The instances are load balanced with a simple health check. The web site is available on port 80, however, the instances can be configured to listen on any port (8888 by default). **WARNING** This template creates one or more Amazon EC2 instances. You will be billed for the AWS resources used if you create a stack from this template.",
|
||||
|
||||
"Resources": {
|
||||
"Queue": {
|
||||
"Type": "AWS::SQS::Queue",
|
||||
"Properties": {
|
||||
"QueueName": "my-queue",
|
||||
"VisibilityTimeout": 60,
|
||||
}
|
||||
},
|
||||
"S3Bucket": {
|
||||
"Type": "AWS::S3::Bucket",
|
||||
"DeletionPolicy": "Retain"
|
||||
"Properties": {"QueueName": "my-queue", "VisibilityTimeout": 60},
|
||||
},
|
||||
"S3Bucket": {"Type": "AWS::S3::Bucket", "DeletionPolicy": "Retain"},
|
||||
},
|
||||
}
|
||||
|
||||
name_type_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
|
||||
"Description": "Create a multi-az, load balanced, Auto Scaled sample web site. The Auto Scaling trigger is based on the CPU utilization of the web servers. The AMI is chosen based on the region in which the stack is run. This example creates a web service running across all availability zones in a region. The instances are load balanced with a simple health check. The web site is available on port 80, however, the instances can be configured to listen on any port (8888 by default). **WARNING** This template creates one or more Amazon EC2 instances. You will be billed for the AWS resources used if you create a stack from this template.",
|
||||
|
||||
"Resources": {
|
||||
"Queue": {
|
||||
"Type": "AWS::SQS::Queue",
|
||||
"Properties": {
|
||||
"VisibilityTimeout": 60,
|
||||
}
|
||||
},
|
||||
"Queue": {"Type": "AWS::SQS::Queue", "Properties": {"VisibilityTimeout": 60}}
|
||||
},
|
||||
}
|
||||
|
||||
output_dict = {
|
||||
"Outputs": {
|
||||
"Output1": {
|
||||
"Value": {"Ref": "Queue"},
|
||||
"Description": "This is a description."
|
||||
}
|
||||
"Output1": {"Value": {"Ref": "Queue"}, "Description": "This is a description."}
|
||||
}
|
||||
}
|
||||
|
||||
bad_output = {
|
||||
"Outputs": {
|
||||
"Output1": {
|
||||
"Value": {"Fn::GetAtt": ["Queue", "InvalidAttribute"]}
|
||||
}
|
||||
}
|
||||
"Outputs": {"Output1": {"Value": {"Fn::GetAtt": ["Queue", "InvalidAttribute"]}}}
|
||||
}
|
||||
|
||||
get_attribute_output = {
|
||||
"Outputs": {
|
||||
"Output1": {
|
||||
"Value": {"Fn::GetAtt": ["Queue", "QueueName"]}
|
||||
}
|
||||
}
|
||||
"Outputs": {"Output1": {"Value": {"Fn::GetAtt": ["Queue", "QueueName"]}}}
|
||||
}
|
||||
|
||||
get_availability_zones_output = {
|
||||
"Outputs": {
|
||||
"Output1": {
|
||||
"Value": {"Fn::GetAZs": ""}
|
||||
}
|
||||
}
|
||||
}
|
||||
get_availability_zones_output = {"Outputs": {"Output1": {"Value": {"Fn::GetAZs": ""}}}}
|
||||
|
||||
parameters = {
|
||||
"Parameters": {
|
||||
"Param": {
|
||||
"Type": "String",
|
||||
},
|
||||
"NoEchoParam": {
|
||||
"Type": "String",
|
||||
"NoEcho": True
|
||||
}
|
||||
"Param": {"Type": "String"},
|
||||
"NoEchoParam": {"Type": "String", "NoEcho": True},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,11 +67,11 @@ split_select_template = {
|
|||
"Queue": {
|
||||
"Type": "AWS::SQS::Queue",
|
||||
"Properties": {
|
||||
"QueueName": {"Fn::Select": [ "1", {"Fn::Split": [ "-", "123-myqueue" ] } ] },
|
||||
"QueueName": {"Fn::Select": ["1", {"Fn::Split": ["-", "123-myqueue"]}]},
|
||||
"VisibilityTimeout": 60,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
sub_template = {
|
||||
|
|
@ -114,18 +80,18 @@ sub_template = {
|
|||
"Queue1": {
|
||||
"Type": "AWS::SQS::Queue",
|
||||
"Properties": {
|
||||
"QueueName": {"Fn::Sub": '${AWS::StackName}-queue-${!Literal}'},
|
||||
"QueueName": {"Fn::Sub": "${AWS::StackName}-queue-${!Literal}"},
|
||||
"VisibilityTimeout": 60,
|
||||
}
|
||||
},
|
||||
},
|
||||
"Queue2": {
|
||||
"Type": "AWS::SQS::Queue",
|
||||
"Properties": {
|
||||
"QueueName": {"Fn::Sub": '${Queue1.QueueName}'},
|
||||
"QueueName": {"Fn::Sub": "${Queue1.QueueName}"},
|
||||
"VisibilityTimeout": 60,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export_value_template = {
|
||||
|
|
@ -134,17 +100,12 @@ export_value_template = {
|
|||
"Queue": {
|
||||
"Type": "AWS::SQS::Queue",
|
||||
"Properties": {
|
||||
"QueueName": {"Fn::Sub": '${AWS::StackName}-queue'},
|
||||
"QueueName": {"Fn::Sub": "${AWS::StackName}-queue"},
|
||||
"VisibilityTimeout": 60,
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
"Outputs": {
|
||||
"Output1": {
|
||||
"Value": "value",
|
||||
"Export": {"Name": 'queue-us-west-1'}
|
||||
}
|
||||
}
|
||||
"Outputs": {"Output1": {"Value": "value", "Export": {"Name": "queue-us-west-1"}}},
|
||||
}
|
||||
|
||||
import_value_template = {
|
||||
|
|
@ -153,33 +114,30 @@ import_value_template = {
|
|||
"Queue": {
|
||||
"Type": "AWS::SQS::Queue",
|
||||
"Properties": {
|
||||
"QueueName": {"Fn::ImportValue": 'queue-us-west-1'},
|
||||
"QueueName": {"Fn::ImportValue": "queue-us-west-1"},
|
||||
"VisibilityTimeout": 60,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
outputs_template = dict(list(dummy_template.items()) +
|
||||
list(output_dict.items()))
|
||||
bad_outputs_template = dict(
|
||||
list(dummy_template.items()) + list(bad_output.items()))
|
||||
outputs_template = dict(list(dummy_template.items()) + list(output_dict.items()))
|
||||
bad_outputs_template = dict(list(dummy_template.items()) + list(bad_output.items()))
|
||||
get_attribute_outputs_template = dict(
|
||||
list(dummy_template.items()) + list(get_attribute_output.items()))
|
||||
list(dummy_template.items()) + list(get_attribute_output.items())
|
||||
)
|
||||
get_availability_zones_template = dict(
|
||||
list(dummy_template.items()) + list(get_availability_zones_output.items()))
|
||||
list(dummy_template.items()) + list(get_availability_zones_output.items())
|
||||
)
|
||||
|
||||
parameters_template = dict(
|
||||
list(dummy_template.items()) + list(parameters.items()))
|
||||
parameters_template = dict(list(dummy_template.items()) + list(parameters.items()))
|
||||
|
||||
dummy_template_json = json.dumps(dummy_template)
|
||||
name_type_template_json = json.dumps(name_type_template)
|
||||
output_type_template_json = json.dumps(outputs_template)
|
||||
bad_output_template_json = json.dumps(bad_outputs_template)
|
||||
get_attribute_outputs_template_json = json.dumps(
|
||||
get_attribute_outputs_template)
|
||||
get_availability_zones_template_json = json.dumps(
|
||||
get_availability_zones_template)
|
||||
get_attribute_outputs_template_json = json.dumps(get_attribute_outputs_template)
|
||||
get_availability_zones_template_json = json.dumps(get_availability_zones_template)
|
||||
parameters_template_json = json.dumps(parameters_template)
|
||||
split_select_template_json = json.dumps(split_select_template)
|
||||
sub_template_json = json.dumps(sub_template)
|
||||
|
|
@ -193,15 +151,16 @@ def test_parse_stack_resources():
|
|||
name="test_stack",
|
||||
template=dummy_template_json,
|
||||
parameters={},
|
||||
region_name='us-west-1')
|
||||
region_name="us-west-1",
|
||||
)
|
||||
|
||||
stack.resource_map.should.have.length_of(2)
|
||||
|
||||
queue = stack.resource_map['Queue']
|
||||
queue = stack.resource_map["Queue"]
|
||||
queue.should.be.a(Queue)
|
||||
queue.name.should.equal("my-queue")
|
||||
|
||||
bucket = stack.resource_map['S3Bucket']
|
||||
bucket = stack.resource_map["S3Bucket"]
|
||||
bucket.should.be.a(FakeBucket)
|
||||
bucket.physical_resource_id.should.equal(bucket.name)
|
||||
|
||||
|
|
@ -209,8 +168,7 @@ def test_parse_stack_resources():
|
|||
@patch("moto.cloudformation.parsing.logger")
|
||||
def test_missing_resource_logs(logger):
|
||||
resource_class_from_type("foobar")
|
||||
logger.warning.assert_called_with(
|
||||
'No Moto CloudFormation support for %s', 'foobar')
|
||||
logger.warning.assert_called_with("No Moto CloudFormation support for %s", "foobar")
|
||||
|
||||
|
||||
def test_parse_stack_with_name_type_resource():
|
||||
|
|
@ -219,10 +177,11 @@ def test_parse_stack_with_name_type_resource():
|
|||
name="test_stack",
|
||||
template=name_type_template_json,
|
||||
parameters={},
|
||||
region_name='us-west-1')
|
||||
region_name="us-west-1",
|
||||
)
|
||||
|
||||
stack.resource_map.should.have.length_of(1)
|
||||
list(stack.resource_map.keys())[0].should.equal('Queue')
|
||||
list(stack.resource_map.keys())[0].should.equal("Queue")
|
||||
queue = list(stack.resource_map.values())[0]
|
||||
queue.should.be.a(Queue)
|
||||
|
||||
|
|
@ -233,10 +192,11 @@ def test_parse_stack_with_yaml_template():
|
|||
name="test_stack",
|
||||
template=yaml.dump(name_type_template),
|
||||
parameters={},
|
||||
region_name='us-west-1')
|
||||
region_name="us-west-1",
|
||||
)
|
||||
|
||||
stack.resource_map.should.have.length_of(1)
|
||||
list(stack.resource_map.keys())[0].should.equal('Queue')
|
||||
list(stack.resource_map.keys())[0].should.equal("Queue")
|
||||
queue = list(stack.resource_map.values())[0]
|
||||
queue.should.be.a(Queue)
|
||||
|
||||
|
|
@ -247,10 +207,11 @@ def test_parse_stack_with_outputs():
|
|||
name="test_stack",
|
||||
template=output_type_template_json,
|
||||
parameters={},
|
||||
region_name='us-west-1')
|
||||
region_name="us-west-1",
|
||||
)
|
||||
|
||||
stack.output_map.should.have.length_of(1)
|
||||
list(stack.output_map.keys())[0].should.equal('Output1')
|
||||
list(stack.output_map.keys())[0].should.equal("Output1")
|
||||
output = list(stack.output_map.values())[0]
|
||||
output.should.be.a(Output)
|
||||
output.description.should.equal("This is a description.")
|
||||
|
|
@ -262,14 +223,16 @@ def test_parse_stack_with_get_attribute_outputs():
|
|||
name="test_stack",
|
||||
template=get_attribute_outputs_template_json,
|
||||
parameters={},
|
||||
region_name='us-west-1')
|
||||
region_name="us-west-1",
|
||||
)
|
||||
|
||||
stack.output_map.should.have.length_of(1)
|
||||
list(stack.output_map.keys())[0].should.equal('Output1')
|
||||
list(stack.output_map.keys())[0].should.equal("Output1")
|
||||
output = list(stack.output_map.values())[0]
|
||||
output.should.be.a(Output)
|
||||
output.value.should.equal("my-queue")
|
||||
|
||||
|
||||
def test_parse_stack_with_get_attribute_kms():
|
||||
from .fixtures.kms_key import template
|
||||
|
||||
|
|
@ -279,31 +242,35 @@ def test_parse_stack_with_get_attribute_kms():
|
|||
name="test_stack",
|
||||
template=template_json,
|
||||
parameters={},
|
||||
region_name='us-west-1')
|
||||
region_name="us-west-1",
|
||||
)
|
||||
|
||||
stack.output_map.should.have.length_of(1)
|
||||
list(stack.output_map.keys())[0].should.equal('KeyArn')
|
||||
list(stack.output_map.keys())[0].should.equal("KeyArn")
|
||||
output = list(stack.output_map.values())[0]
|
||||
output.should.be.a(Output)
|
||||
|
||||
|
||||
def test_parse_stack_with_get_availability_zones():
|
||||
stack = FakeStack(
|
||||
stack_id="test_id",
|
||||
name="test_stack",
|
||||
template=get_availability_zones_template_json,
|
||||
parameters={},
|
||||
region_name='us-east-1')
|
||||
region_name="us-east-1",
|
||||
)
|
||||
|
||||
stack.output_map.should.have.length_of(1)
|
||||
list(stack.output_map.keys())[0].should.equal('Output1')
|
||||
list(stack.output_map.keys())[0].should.equal("Output1")
|
||||
output = list(stack.output_map.values())[0]
|
||||
output.should.be.a(Output)
|
||||
output.value.should.equal([ "us-east-1a", "us-east-1b", "us-east-1c", "us-east-1d" ])
|
||||
output.value.should.equal(["us-east-1a", "us-east-1b", "us-east-1c", "us-east-1d"])
|
||||
|
||||
|
||||
def test_parse_stack_with_bad_get_attribute_outputs():
|
||||
FakeStack.when.called_with(
|
||||
"test_id", "test_stack", bad_output_template_json, {}, "us-west-1").should.throw(ValidationError)
|
||||
"test_id", "test_stack", bad_output_template_json, {}, "us-west-1"
|
||||
).should.throw(ValidationError)
|
||||
|
||||
|
||||
def test_parse_stack_with_parameters():
|
||||
|
|
@ -312,7 +279,8 @@ def test_parse_stack_with_parameters():
|
|||
name="test_stack",
|
||||
template=parameters_template_json,
|
||||
parameters={"Param": "visible value", "NoEchoParam": "hidden value"},
|
||||
region_name='us-west-1')
|
||||
region_name="us-west-1",
|
||||
)
|
||||
|
||||
stack.resource_map.no_echo_parameter_keys.should.have("NoEchoParam")
|
||||
stack.resource_map.no_echo_parameter_keys.should_not.have("Param")
|
||||
|
|
@ -334,21 +302,13 @@ def test_parse_equals_condition():
|
|||
|
||||
def test_parse_not_condition():
|
||||
parse_condition(
|
||||
condition={
|
||||
"Fn::Not": [{
|
||||
"Fn::Equals": [{"Ref": "EnvType"}, "prod"]
|
||||
}]
|
||||
},
|
||||
condition={"Fn::Not": [{"Fn::Equals": [{"Ref": "EnvType"}, "prod"]}]},
|
||||
resources_map={"EnvType": "prod"},
|
||||
condition_map={},
|
||||
).should.equal(False)
|
||||
|
||||
parse_condition(
|
||||
condition={
|
||||
"Fn::Not": [{
|
||||
"Fn::Equals": [{"Ref": "EnvType"}, "prod"]
|
||||
}]
|
||||
},
|
||||
condition={"Fn::Not": [{"Fn::Equals": [{"Ref": "EnvType"}, "prod"]}]},
|
||||
resources_map={"EnvType": "staging"},
|
||||
condition_map={},
|
||||
).should.equal(True)
|
||||
|
|
@ -416,10 +376,11 @@ def test_parse_split_and_select():
|
|||
name="test_stack",
|
||||
template=split_select_template_json,
|
||||
parameters={},
|
||||
region_name='us-west-1')
|
||||
region_name="us-west-1",
|
||||
)
|
||||
|
||||
stack.resource_map.should.have.length_of(1)
|
||||
queue = stack.resource_map['Queue']
|
||||
queue = stack.resource_map["Queue"]
|
||||
queue.name.should.equal("myqueue")
|
||||
|
||||
|
||||
|
|
@ -429,10 +390,11 @@ def test_sub():
|
|||
name="test_stack",
|
||||
template=sub_template_json,
|
||||
parameters={},
|
||||
region_name='us-west-1')
|
||||
region_name="us-west-1",
|
||||
)
|
||||
|
||||
queue1 = stack.resource_map['Queue1']
|
||||
queue2 = stack.resource_map['Queue2']
|
||||
queue1 = stack.resource_map["Queue1"]
|
||||
queue2 = stack.resource_map["Queue2"]
|
||||
queue2.name.should.equal(queue1.name)
|
||||
|
||||
|
||||
|
|
@ -442,20 +404,21 @@ def test_import():
|
|||
name="test_stack",
|
||||
template=export_value_template_json,
|
||||
parameters={},
|
||||
region_name='us-west-1')
|
||||
region_name="us-west-1",
|
||||
)
|
||||
import_stack = FakeStack(
|
||||
stack_id="test_id",
|
||||
name="test_stack",
|
||||
template=import_value_template_json,
|
||||
parameters={},
|
||||
region_name='us-west-1',
|
||||
cross_stack_resources={export_stack.exports[0].value: export_stack.exports[0]})
|
||||
region_name="us-west-1",
|
||||
cross_stack_resources={export_stack.exports[0].value: export_stack.exports[0]},
|
||||
)
|
||||
|
||||
queue = import_stack.resource_map['Queue']
|
||||
queue = import_stack.resource_map["Queue"]
|
||||
queue.name.should.equal("value")
|
||||
|
||||
|
||||
|
||||
def test_short_form_func_in_yaml_teamplate():
|
||||
template = """---
|
||||
KeyB64: !Base64 valueToEncode
|
||||
|
|
@ -476,24 +439,24 @@ def test_short_form_func_in_yaml_teamplate():
|
|||
KeySplit: !Split [A, B]
|
||||
KeySub: !Sub A
|
||||
"""
|
||||
yaml.add_multi_constructor('', yaml_tag_constructor, Loader=yaml.Loader)
|
||||
yaml.add_multi_constructor("", yaml_tag_constructor, Loader=yaml.Loader)
|
||||
template_dict = yaml.load(template, Loader=yaml.Loader)
|
||||
key_and_expects = [
|
||||
['KeyRef', {'Ref': 'foo'}],
|
||||
['KeyB64', {'Fn::Base64': 'valueToEncode'}],
|
||||
['KeyAnd', {'Fn::And': ['A', 'B']}],
|
||||
['KeyEquals', {'Fn::Equals': ['A', 'B']}],
|
||||
['KeyIf', {'Fn::If': ['A', 'B', 'C']}],
|
||||
['KeyNot', {'Fn::Not': ['A']}],
|
||||
['KeyOr', {'Fn::Or': ['A', 'B']}],
|
||||
['KeyFindInMap', {'Fn::FindInMap': ['A', 'B', 'C']}],
|
||||
['KeyGetAtt', {'Fn::GetAtt': ['A', 'B']}],
|
||||
['KeyGetAZs', {'Fn::GetAZs': 'A'}],
|
||||
['KeyImportValue', {'Fn::ImportValue': 'A'}],
|
||||
['KeyJoin', {'Fn::Join': [ ":", [ 'A', 'B', 'C' ] ]}],
|
||||
['KeySelect', {'Fn::Select': ['A', 'B']}],
|
||||
['KeySplit', {'Fn::Split': ['A', 'B']}],
|
||||
['KeySub', {'Fn::Sub': 'A'}],
|
||||
["KeyRef", {"Ref": "foo"}],
|
||||
["KeyB64", {"Fn::Base64": "valueToEncode"}],
|
||||
["KeyAnd", {"Fn::And": ["A", "B"]}],
|
||||
["KeyEquals", {"Fn::Equals": ["A", "B"]}],
|
||||
["KeyIf", {"Fn::If": ["A", "B", "C"]}],
|
||||
["KeyNot", {"Fn::Not": ["A"]}],
|
||||
["KeyOr", {"Fn::Or": ["A", "B"]}],
|
||||
["KeyFindInMap", {"Fn::FindInMap": ["A", "B", "C"]}],
|
||||
["KeyGetAtt", {"Fn::GetAtt": ["A", "B"]}],
|
||||
["KeyGetAZs", {"Fn::GetAZs": "A"}],
|
||||
["KeyImportValue", {"Fn::ImportValue": "A"}],
|
||||
["KeyJoin", {"Fn::Join": [":", ["A", "B", "C"]]}],
|
||||
["KeySelect", {"Fn::Select": ["A", "B"]}],
|
||||
["KeySplit", {"Fn::Split": ["A", "B"]}],
|
||||
["KeySub", {"Fn::Sub": "A"}],
|
||||
]
|
||||
for k, v in key_and_expects:
|
||||
template_dict.should.have.key(k).which.should.be.equal(v)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,11 @@ import botocore
|
|||
|
||||
from moto.cloudformation.exceptions import ValidationError
|
||||
from moto.cloudformation.models import FakeStack
|
||||
from moto.cloudformation.parsing import resource_class_from_type, parse_condition, Export
|
||||
from moto.cloudformation.parsing import (
|
||||
resource_class_from_type,
|
||||
parse_condition,
|
||||
Export,
|
||||
)
|
||||
from moto.sqs.models import Queue
|
||||
from moto.s3.models import FakeBucket
|
||||
from moto.cloudformation.utils import yaml_tag_constructor
|
||||
|
|
@ -27,25 +31,16 @@ json_template = {
|
|||
"KeyName": "dummy",
|
||||
"InstanceType": "t2.micro",
|
||||
"Tags": [
|
||||
{
|
||||
"Key": "Description",
|
||||
"Value": "Test tag"
|
||||
},
|
||||
{
|
||||
"Key": "Name",
|
||||
"Value": "Name tag for tests"
|
||||
}
|
||||
]
|
||||
}
|
||||
{"Key": "Description", "Value": "Test tag"},
|
||||
{"Key": "Name", "Value": "Name tag for tests"},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
# One resource is required
|
||||
json_bad_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack 1"
|
||||
}
|
||||
json_bad_template = {"AWSTemplateFormatVersion": "2010-09-09", "Description": "Stack 1"}
|
||||
|
||||
dummy_template_json = json.dumps(json_template)
|
||||
dummy_bad_template_json = json.dumps(json_bad_template)
|
||||
|
|
@ -53,25 +48,25 @@ dummy_bad_template_json = json.dumps(json_bad_template)
|
|||
|
||||
@mock_cloudformation
|
||||
def test_boto3_json_validate_successful():
|
||||
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||
response = cf_conn.validate_template(
|
||||
TemplateBody=dummy_template_json,
|
||||
)
|
||||
assert response['Description'] == "Stack 1"
|
||||
assert response['Parameters'] == []
|
||||
assert response['ResponseMetadata']['HTTPStatusCode'] == 200
|
||||
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||
response = cf_conn.validate_template(TemplateBody=dummy_template_json)
|
||||
assert response["Description"] == "Stack 1"
|
||||
assert response["Parameters"] == []
|
||||
assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
def test_boto3_json_invalid_missing_resource():
|
||||
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||
try:
|
||||
cf_conn.validate_template(
|
||||
TemplateBody=dummy_bad_template_json,
|
||||
)
|
||||
cf_conn.validate_template(TemplateBody=dummy_bad_template_json)
|
||||
assert False
|
||||
except botocore.exceptions.ClientError as e:
|
||||
assert str(e) == 'An error occurred (ValidationError) when calling the ValidateTemplate operation: Stack' \
|
||||
' with id Missing top level item Resources to file module does not exist'
|
||||
assert (
|
||||
str(e)
|
||||
== "An error occurred (ValidationError) when calling the ValidateTemplate operation: Stack"
|
||||
" with id Missing top level item Resources to file module does not exist"
|
||||
)
|
||||
assert True
|
||||
|
||||
|
||||
|
|
@ -91,25 +86,26 @@ yaml_bad_template = """
|
|||
Description: Simple CloudFormation Test Template
|
||||
"""
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
def test_boto3_yaml_validate_successful():
|
||||
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||
response = cf_conn.validate_template(
|
||||
TemplateBody=yaml_template,
|
||||
)
|
||||
assert response['Description'] == "Simple CloudFormation Test Template"
|
||||
assert response['Parameters'] == []
|
||||
assert response['ResponseMetadata']['HTTPStatusCode'] == 200
|
||||
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||
response = cf_conn.validate_template(TemplateBody=yaml_template)
|
||||
assert response["Description"] == "Simple CloudFormation Test Template"
|
||||
assert response["Parameters"] == []
|
||||
assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
def test_boto3_yaml_invalid_missing_resource():
|
||||
cf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||
try:
|
||||
cf_conn.validate_template(
|
||||
TemplateBody=yaml_bad_template,
|
||||
)
|
||||
cf_conn.validate_template(TemplateBody=yaml_bad_template)
|
||||
assert False
|
||||
except botocore.exceptions.ClientError as e:
|
||||
assert str(e) == 'An error occurred (ValidationError) when calling the ValidateTemplate operation: Stack' \
|
||||
' with id Missing top level item Resources to file module does not exist'
|
||||
assert (
|
||||
str(e)
|
||||
== "An error occurred (ValidationError) when calling the ValidateTemplate operation: Stack"
|
||||
" with id Missing top level item Resources to file module does not exist"
|
||||
)
|
||||
assert True
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue