| 
									
										
										
										
											2014-03-27 19:12:53 -04:00
										 |  |  | import json | 
					
						
							| 
									
										
										
										
											2021-01-17 17:28:49 +02:00
										 |  |  | import io | 
					
						
							|  |  |  | import zipfile | 
					
						
							| 
									
										
										
										
											2014-03-27 19:12:53 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-25 18:16:33 +09:00
										 |  |  | from decimal import Decimal | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-05 05:04:04 -04:00
										 |  |  | from botocore.exceptions import ClientError | 
					
						
							| 
									
										
										
										
											2016-02-12 15:38:39 -05:00
										 |  |  | import boto3 | 
					
						
							| 
									
										
										
										
											2021-10-18 19:44:29 +00:00
										 |  |  | import sure  # noqa # pylint: disable=unused-import | 
					
						
							| 
									
										
										
										
											2021-10-04 13:47:40 +00:00
										 |  |  | import pytest | 
					
						
							| 
									
										
										
										
											2020-06-03 02:54:01 -03:00
										 |  |  | from string import Template | 
					
						
							| 
									
										
										
										
											2014-03-27 19:12:53 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | from moto import ( | 
					
						
							| 
									
										
										
										
											2020-05-24 07:21:29 -04:00
										 |  |  |     mock_autoscaling, | 
					
						
							| 
									
										
										
										
											2014-03-27 19:12:53 -04:00
										 |  |  |     mock_cloudformation, | 
					
						
							| 
									
										
										
										
											2022-03-11 21:29:16 -01:00
										 |  |  |     mock_dynamodb, | 
					
						
							| 
									
										
										
										
											2014-03-27 19:12:53 -04:00
										 |  |  |     mock_ec2, | 
					
						
							| 
									
										
										
										
											2020-03-22 18:03:42 -03:00
										 |  |  |     mock_events, | 
					
						
							| 
									
										
										
										
											2016-05-13 21:36:24 +00:00
										 |  |  |     mock_kms, | 
					
						
							| 
									
										
										
										
											2016-02-12 15:38:39 -05:00
										 |  |  |     mock_lambda, | 
					
						
							| 
									
										
										
										
											2020-03-18 13:02:07 +00:00
										 |  |  |     mock_logs, | 
					
						
							|  |  |  |     mock_s3, | 
					
						
							| 
									
										
										
										
											2021-10-04 13:47:40 +00:00
										 |  |  |     mock_sqs, | 
					
						
							| 
									
										
										
										
											2017-10-27 11:54:43 -04:00
										 |  |  |     mock_elbv2, | 
					
						
							| 
									
										
										
										
											2022-11-05 18:06:12 +07:00
										 |  |  |     mock_ssm, | 
					
						
							| 
									
										
										
										
											2017-10-27 11:54:43 -04:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2022-08-13 09:49:43 +00:00
										 |  |  | from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID | 
					
						
							| 
									
										
										
										
											2014-03-27 19:12:53 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-13 09:02:11 +00:00
										 |  |  | from tests import EXAMPLE_AMI_ID, EXAMPLE_AMI_ID2 | 
					
						
							| 
									
										
										
										
											2023-03-12 17:54:50 +01:00
										 |  |  | from tests.markers import requires_docker | 
					
						
							| 
									
										
										
										
											2020-05-18 04:47:18 -04:00
										 |  |  | from tests.test_cloudformation.fixtures import fn_join, single_instance_with_ebs_volume | 
					
						
							| 
									
										
										
										
											2014-03-27 19:12:53 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-04 13:47:40 +00:00
										 |  |  | @mock_cloudformation | 
					
						
							|  |  |  | def test_create_template_without_required_param_boto3(): | 
					
						
							|  |  |  |     template_json = json.dumps(single_instance_with_ebs_volume.template) | 
					
						
							|  |  |  |     cf = boto3.client("cloudformation", region_name="us-west-1") | 
					
						
							|  |  |  |     with pytest.raises(ClientError) as ex: | 
					
						
							|  |  |  |         cf.create_stack(StackName="test_stack", TemplateBody=template_json) | 
					
						
							|  |  |  |     err = ex.value.response["Error"] | 
					
						
							|  |  |  |     err.should.have.key("Code").equal("Missing Parameter") | 
					
						
							|  |  |  |     err.should.have.key("Message").equal("Missing parameter KeyName") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_ec2 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | def test_fn_join_boto3(): | 
					
						
							|  |  |  |     template_json = json.dumps(fn_join.template) | 
					
						
							|  |  |  |     cf = boto3.client("cloudformation", region_name="us-west-1") | 
					
						
							|  |  |  |     cf.create_stack(StackName="test_stack", TemplateBody=template_json) | 
					
						
							|  |  |  |     ec2 = boto3.client("ec2", region_name="us-west-1") | 
					
						
							|  |  |  |     eip = ec2.describe_addresses()["Addresses"][0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     stack = cf.describe_stacks()["Stacks"][0] | 
					
						
							|  |  |  |     fn_join_output = stack["Outputs"][0] | 
					
						
							| 
									
										
										
										
											2022-11-17 21:41:08 -01:00
										 |  |  |     fn_join_output["OutputValue"].should.equal(f"test eip:{eip['PublicIp']}") | 
					
						
							| 
									
										
										
										
											2021-10-04 13:47:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_sqs | 
					
						
							|  |  |  | def test_conditional_resources_boto3(): | 
					
						
							|  |  |  |     sqs_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Parameters": { | 
					
						
							|  |  |  |             "EnvType": {"Description": "Environment type.", "Type": "String"} | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "Conditions": {"CreateQueue": {"Fn::Equals": [{"Ref": "EnvType"}, "prod"]}}, | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "QueueGroup": { | 
					
						
							|  |  |  |                 "Condition": "CreateQueue", | 
					
						
							|  |  |  |                 "Type": "AWS::SQS::Queue", | 
					
						
							|  |  |  |                 "Properties": {"QueueName": "my-queue", "VisibilityTimeout": 60}, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     sqs_template_json = json.dumps(sqs_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf = boto3.client("cloudformation", region_name="us-west-1") | 
					
						
							|  |  |  |     cf.create_stack( | 
					
						
							|  |  |  |         StackName="test_stack_without_queue", | 
					
						
							|  |  |  |         TemplateBody=sqs_template_json, | 
					
						
							|  |  |  |         Parameters=[{"ParameterKey": "EnvType", "ParameterValue": "staging"}], | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     sqs = boto3.client("sqs", region_name="us-west-1") | 
					
						
							|  |  |  |     sqs.list_queues().shouldnt.have.key("QueueUrls") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf.create_stack( | 
					
						
							|  |  |  |         StackName="test_stack_with_queue", | 
					
						
							|  |  |  |         TemplateBody=sqs_template_json, | 
					
						
							|  |  |  |         Parameters=[{"ParameterKey": "EnvType", "ParameterValue": "prod"}], | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     sqs.list_queues()["QueueUrls"].should.have.length_of(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_ec2 | 
					
						
							|  |  |  | def test_conditional_if_handling_boto3(): | 
					
						
							|  |  |  |     dummy_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Conditions": {"EnvEqualsPrd": {"Fn::Equals": [{"Ref": "ENV"}, "prd"]}}, | 
					
						
							|  |  |  |         "Parameters": { | 
					
						
							|  |  |  |             "ENV": { | 
					
						
							|  |  |  |                 "Default": "dev", | 
					
						
							|  |  |  |                 "Description": "Deployment environment for the stack (dev/prd)", | 
					
						
							|  |  |  |                 "Type": "String", | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "Description": "Stack 1", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "App1": { | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "ImageId": { | 
					
						
							|  |  |  |                         "Fn::If": ["EnvEqualsPrd", EXAMPLE_AMI_ID, EXAMPLE_AMI_ID2] | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::Instance", | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     dummy_template_json = json.dumps(dummy_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf = boto3.client("cloudformation", region_name="us-west-1") | 
					
						
							|  |  |  |     cf.create_stack(StackName="test_stack", TemplateBody=dummy_template_json) | 
					
						
							|  |  |  |     ec2 = boto3.client("ec2", region_name="us-west-1") | 
					
						
							|  |  |  |     ec2_instance = ec2.describe_instances()["Reservations"][0]["Instances"][0] | 
					
						
							|  |  |  |     ec2_instance["ImageId"].should.equal(EXAMPLE_AMI_ID2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf = boto3.client("cloudformation", region_name="us-west-2") | 
					
						
							|  |  |  |     cf.create_stack( | 
					
						
							|  |  |  |         StackName="test_stack", | 
					
						
							|  |  |  |         TemplateBody=dummy_template_json, | 
					
						
							|  |  |  |         Parameters=[{"ParameterKey": "ENV", "ParameterValue": "prd"}], | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     ec2 = boto3.client("ec2", region_name="us-west-2") | 
					
						
							|  |  |  |     ec2_instance = ec2.describe_instances()["Reservations"][0]["Instances"][0] | 
					
						
							|  |  |  |     ec2_instance["ImageId"].should.equal(EXAMPLE_AMI_ID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_ec2 | 
					
						
							|  |  |  | def test_cloudformation_mapping_boto3(): | 
					
						
							|  |  |  |     dummy_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Mappings": { | 
					
						
							|  |  |  |             "RegionMap": { | 
					
						
							|  |  |  |                 "us-east-1": {"32": EXAMPLE_AMI_ID, "64": "n/a"}, | 
					
						
							|  |  |  |                 "us-west-1": {"32": EXAMPLE_AMI_ID2, "64": "n/a"}, | 
					
						
							|  |  |  |                 "eu-west-1": {"32": "n/a", "64": "n/a"}, | 
					
						
							|  |  |  |                 "ap-southeast-1": {"32": "n/a", "64": "n/a"}, | 
					
						
							|  |  |  |                 "ap-northeast-1": {"32": "n/a", "64": "n/a"}, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "WebServer": { | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::Instance", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "ImageId": { | 
					
						
							|  |  |  |                         "Fn::FindInMap": ["RegionMap", {"Ref": "AWS::Region"}, "32"] | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     "InstanceType": "m1.small", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dummy_template_json = json.dumps(dummy_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf = boto3.client("cloudformation", region_name="us-east-1") | 
					
						
							|  |  |  |     cf.create_stack(StackName="test_stack1", TemplateBody=dummy_template_json) | 
					
						
							|  |  |  |     ec2 = boto3.client("ec2", region_name="us-east-1") | 
					
						
							|  |  |  |     ec2_instance = ec2.describe_instances()["Reservations"][0]["Instances"][0] | 
					
						
							|  |  |  |     ec2_instance["ImageId"].should.equal(EXAMPLE_AMI_ID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf = boto3.client("cloudformation", region_name="us-west-1") | 
					
						
							|  |  |  |     cf.create_stack(StackName="test_stack1", TemplateBody=dummy_template_json) | 
					
						
							|  |  |  |     ec2 = boto3.client("ec2", region_name="us-west-1") | 
					
						
							|  |  |  |     ec2_instance = ec2.describe_instances()["Reservations"][0]["Instances"][0] | 
					
						
							|  |  |  |     ec2_instance["ImageId"].should.equal(EXAMPLE_AMI_ID2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-23 19:43:48 -05:00
										 |  |  | @mock_cloudformation | 
					
						
							| 
									
										
										
										
											2016-02-12 15:38:39 -05:00
										 |  |  | @mock_lambda | 
					
						
							| 
									
										
										
										
											2023-03-12 17:54:50 +01:00
										 |  |  | @requires_docker | 
					
						
							| 
									
										
										
										
											2016-02-12 15:38:39 -05:00
										 |  |  | def test_lambda_function(): | 
					
						
							| 
									
										
										
										
											2016-10-06 19:52:23 +10:00
										 |  |  |     # switch this to python as backend lambda only supports python execution. | 
					
						
							| 
									
										
										
										
											2017-05-17 18:16:40 -04:00
										 |  |  |     lambda_code = """
 | 
					
						
							|  |  |  | def lambda_handler(event, context): | 
					
						
							| 
									
										
										
										
											2021-11-03 20:00:42 -01:00
										 |  |  |     return {"event": event} | 
					
						
							| 
									
										
										
										
											2017-05-17 18:16:40 -04:00
										 |  |  | """
 | 
					
						
							| 
									
										
										
										
											2016-02-12 15:38:39 -05:00
										 |  |  |     template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "lambdaTest": { | 
					
						
							|  |  |  |                 "Type": "AWS::Lambda::Function", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Code": { | 
					
						
							| 
									
										
										
										
											2017-05-17 18:16:40 -04:00
										 |  |  |                         # CloudFormation expects a string as ZipFile, not a ZIP file base64-encoded | 
					
						
							|  |  |  |                         "ZipFile": {"Fn::Join": ["\n", lambda_code.splitlines()]} | 
					
						
							| 
									
										
										
										
											2016-02-12 15:38:39 -05:00
										 |  |  |                     }, | 
					
						
							| 
									
										
										
										
											2021-11-03 20:00:42 -01:00
										 |  |  |                     "Handler": "index.lambda_handler", | 
					
						
							| 
									
										
										
										
											2016-02-12 15:38:39 -05:00
										 |  |  |                     "Description": "Test function", | 
					
						
							|  |  |  |                     "MemorySize": 128, | 
					
						
							| 
									
										
										
										
											2019-11-07 11:18:03 -08:00
										 |  |  |                     "Role": {"Fn::GetAtt": ["MyRole", "Arn"]}, | 
					
						
							| 
									
										
										
										
											2018-12-28 22:16:07 -05:00
										 |  |  |                     "Runtime": "python2.7", | 
					
						
							|  |  |  |                     "Environment": {"Variables": {"TEST_ENV_KEY": "test-env-val"}}, | 
					
						
							| 
									
										
										
										
											2020-08-26 07:06:53 -03:00
										 |  |  |                     "ReservedConcurrentExecutions": 10, | 
					
						
							| 
									
										
										
										
											2018-12-28 22:16:07 -05:00
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2019-11-07 11:18:03 -08:00
										 |  |  |             }, | 
					
						
							|  |  |  |             "MyRole": { | 
					
						
							|  |  |  |                 "Type": "AWS::IAM::Role", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "AssumeRolePolicyDocument": { | 
					
						
							|  |  |  |                         "Statement": [ | 
					
						
							|  |  |  |                             { | 
					
						
							|  |  |  |                                 "Action": ["sts:AssumeRole"], | 
					
						
							|  |  |  |                                 "Effect": "Allow", | 
					
						
							|  |  |  |                                 "Principal": {"Service": ["ec2.amazonaws.com"]}, | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         ] | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2016-02-12 15:38:39 -05:00
										 |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template_json = json.dumps(template) | 
					
						
							| 
									
										
										
										
											2017-02-23 19:43:48 -05:00
										 |  |  |     cf_conn = boto3.client("cloudformation", "us-east-1") | 
					
						
							|  |  |  |     cf_conn.create_stack(StackName="test_stack", TemplateBody=template_json) | 
					
						
							| 
									
										
										
										
											2016-02-12 15:38:39 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-15 22:35:45 -05:00
										 |  |  |     conn = boto3.client("lambda", "us-east-1") | 
					
						
							| 
									
										
										
										
											2016-02-12 15:38:39 -05:00
										 |  |  |     result = conn.list_functions() | 
					
						
							|  |  |  |     result["Functions"].should.have.length_of(1) | 
					
						
							|  |  |  |     result["Functions"][0]["Description"].should.equal("Test function") | 
					
						
							| 
									
										
										
										
											2021-11-03 20:00:42 -01:00
										 |  |  |     result["Functions"][0]["Handler"].should.equal("index.lambda_handler") | 
					
						
							| 
									
										
										
										
											2016-02-12 15:38:39 -05:00
										 |  |  |     result["Functions"][0]["MemorySize"].should.equal(128) | 
					
						
							| 
									
										
										
										
											2016-10-06 19:52:23 +10:00
										 |  |  |     result["Functions"][0]["Runtime"].should.equal("python2.7") | 
					
						
							| 
									
										
										
										
											2018-12-28 22:16:07 -05:00
										 |  |  |     result["Functions"][0]["Environment"].should.equal( | 
					
						
							|  |  |  |         {"Variables": {"TEST_ENV_KEY": "test-env-val"}} | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2016-03-01 11:57:46 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-26 07:06:53 -03:00
										 |  |  |     function_name = result["Functions"][0]["FunctionName"] | 
					
						
							|  |  |  |     result = conn.get_function(FunctionName=function_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     result["Concurrency"]["ReservedConcurrentExecutions"].should.equal(10) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-03 20:00:42 -01:00
										 |  |  |     response = conn.invoke(FunctionName=function_name) | 
					
						
							|  |  |  |     result = json.loads(response["Payload"].read()) | 
					
						
							|  |  |  |     result.should.equal({"event": "{}"}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-01 11:57:46 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-17 17:28:49 +02:00
										 |  |  | def _make_zipfile(func_str): | 
					
						
							|  |  |  |     zip_output = io.BytesIO() | 
					
						
							|  |  |  |     zip_file = zipfile.ZipFile(zip_output, "w", zipfile.ZIP_DEFLATED) | 
					
						
							|  |  |  |     zip_file.writestr("lambda_function.py", func_str) | 
					
						
							|  |  |  |     zip_file.close() | 
					
						
							|  |  |  |     zip_output.seek(0) | 
					
						
							|  |  |  |     return zip_output.read() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_s3 | 
					
						
							|  |  |  | @mock_lambda | 
					
						
							|  |  |  | def test_lambda_layer(): | 
					
						
							|  |  |  |     # switch this to python as backend lambda only supports python execution. | 
					
						
							|  |  |  |     layer_code = """
 | 
					
						
							|  |  |  | def lambda_handler(event, context): | 
					
						
							|  |  |  |     return (event, context) | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  |     region = "us-east-1" | 
					
						
							|  |  |  |     bucket_name = "test_bucket" | 
					
						
							|  |  |  |     s3_conn = boto3.client("s3", region) | 
					
						
							|  |  |  |     s3_conn.create_bucket(Bucket=bucket_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     zip_content = _make_zipfile(layer_code) | 
					
						
							|  |  |  |     s3_conn.put_object(Bucket=bucket_name, Key="test.zip", Body=zip_content) | 
					
						
							|  |  |  |     template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "lambdaTest": { | 
					
						
							|  |  |  |                 "Type": "AWS::Lambda::LayerVersion", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Content": {"S3Bucket": bucket_name, "S3Key": "test.zip"}, | 
					
						
							|  |  |  |                     "LayerName": "testLayer", | 
					
						
							|  |  |  |                     "Description": "Test Layer", | 
					
						
							|  |  |  |                     "CompatibleRuntimes": ["python2.7", "python3.6"], | 
					
						
							|  |  |  |                     "LicenseInfo": "MIT", | 
					
						
							| 
									
										
										
										
											2022-05-19 11:08:02 +00:00
										 |  |  |                     "CompatibleArchitectures": [], | 
					
						
							| 
									
										
										
										
											2021-01-17 17:28:49 +02:00
										 |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template_json = json.dumps(template) | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", region) | 
					
						
							|  |  |  |     cf_conn.create_stack(StackName="test_stack", TemplateBody=template_json) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     lambda_conn = boto3.client("lambda", region) | 
					
						
							|  |  |  |     result = lambda_conn.list_layers() | 
					
						
							|  |  |  |     layer_name = result["Layers"][0]["LayerName"] | 
					
						
							|  |  |  |     result = lambda_conn.list_layer_versions(LayerName=layer_name) | 
					
						
							|  |  |  |     result["LayerVersions"][0].pop("CreatedDate") | 
					
						
							|  |  |  |     result["LayerVersions"].should.equal( | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "Version": 1, | 
					
						
							| 
									
										
										
										
											2022-11-17 21:41:08 -01:00
										 |  |  |                 "LayerVersionArn": f"arn:aws:lambda:{region}:{ACCOUNT_ID}:layer:{layer_name}:1", | 
					
						
							| 
									
										
										
										
											2021-01-17 17:28:49 +02:00
										 |  |  |                 "CompatibleRuntimes": ["python2.7", "python3.6"], | 
					
						
							|  |  |  |                 "Description": "Test Layer", | 
					
						
							|  |  |  |                 "LicenseInfo": "MIT", | 
					
						
							| 
									
										
										
										
											2022-05-19 11:08:02 +00:00
										 |  |  |                 "CompatibleArchitectures": [], | 
					
						
							| 
									
										
										
										
											2021-01-17 17:28:49 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-01 11:57:46 -05:00
										 |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_ec2 | 
					
						
							|  |  |  | def test_nat_gateway(): | 
					
						
							|  |  |  |     ec2_conn = boto3.client("ec2", "us-east-1") | 
					
						
							|  |  |  |     vpc_id = ec2_conn.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"]["VpcId"] | 
					
						
							| 
									
										
										
										
											2017-02-23 21:37:43 -05:00
										 |  |  |     subnet_id = ec2_conn.create_subnet(CidrBlock="10.0.1.0/24", VpcId=vpc_id)["Subnet"][ | 
					
						
							|  |  |  |         "SubnetId" | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  |     route_table_id = ec2_conn.create_route_table(VpcId=vpc_id)["RouteTable"][ | 
					
						
							|  |  |  |         "RouteTableId" | 
					
						
							|  |  |  |     ] | 
					
						
							| 
									
										
										
										
											2016-03-01 11:57:46 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							| 
									
										
										
										
											2017-02-23 21:37:43 -05:00
										 |  |  |             "NAT": { | 
					
						
							|  |  |  |                 "DependsOn": "vpcgatewayattachment", | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::NatGateway", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "AllocationId": {"Fn::GetAtt": ["EIP", "AllocationId"]}, | 
					
						
							|  |  |  |                     "SubnetId": subnet_id, | 
					
						
							| 
									
										
										
										
											2016-03-01 11:57:46 -05:00
										 |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2015-02-17 14:37:34 -05:00
										 |  |  |             "EIP": {"Type": "AWS::EC2::EIP", "Properties": {"Domain": "vpc"}}, | 
					
						
							| 
									
										
										
										
											2017-02-23 21:37:43 -05:00
										 |  |  |             "Route": { | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::Route", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "RouteTableId": route_table_id, | 
					
						
							|  |  |  |                     "DestinationCidrBlock": "0.0.0.0/0", | 
					
						
							|  |  |  |                     "NatGatewayId": {"Ref": "NAT"}, | 
					
						
							| 
									
										
										
										
											2016-03-01 11:57:46 -05:00
										 |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "internetgateway": {"Type": "AWS::EC2::InternetGateway"}, | 
					
						
							|  |  |  |             "vpcgatewayattachment": { | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::VPCGatewayAttachment", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "InternetGatewayId": {"Ref": "internetgateway"}, | 
					
						
							|  |  |  |                     "VpcId": vpc_id, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-east-1") | 
					
						
							|  |  |  |     cf_conn.create_stack(StackName="test_stack", TemplateBody=json.dumps(template)) | 
					
						
							| 
									
										
										
										
											2021-03-20 09:57:53 +01:00
										 |  |  |     stack_resources = cf_conn.list_stack_resources(StackName="test_stack") | 
					
						
							|  |  |  |     nat_gateway_resource = stack_resources.get("StackResourceSummaries")[0] | 
					
						
							|  |  |  |     for resource in stack_resources["StackResourceSummaries"]: | 
					
						
							|  |  |  |         if resource["ResourceType"] == "AWS::EC2::NatGateway": | 
					
						
							|  |  |  |             nat_gateway_resource = resource | 
					
						
							|  |  |  |         elif resource["ResourceType"] == "AWS::EC2::Route": | 
					
						
							|  |  |  |             route_resource = resource | 
					
						
							| 
									
										
										
										
											2016-03-01 11:57:46 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     result = ec2_conn.describe_nat_gateways() | 
					
						
							|  |  |  |     result["NatGateways"].should.have.length_of(1) | 
					
						
							|  |  |  |     result["NatGateways"][0]["VpcId"].should.equal(vpc_id) | 
					
						
							|  |  |  |     result["NatGateways"][0]["SubnetId"].should.equal(subnet_id) | 
					
						
							|  |  |  |     result["NatGateways"][0]["State"].should.equal("available") | 
					
						
							| 
									
										
										
										
											2021-03-20 09:57:53 +01:00
										 |  |  |     result["NatGateways"][0]["NatGatewayId"].should.equal( | 
					
						
							|  |  |  |         nat_gateway_resource.get("PhysicalResourceId") | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     route_resource.get("PhysicalResourceId").should.contain("rtb-") | 
					
						
							| 
									
										
										
										
											2016-05-13 21:36:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-23 21:37:43 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-13 21:36:24 +00:00
										 |  |  | @mock_cloudformation() | 
					
						
							|  |  |  | @mock_kms() | 
					
						
							|  |  |  | def test_stack_kms(): | 
					
						
							|  |  |  |     kms_key_template = { | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "kmskey": { | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Description": "A kms key", | 
					
						
							|  |  |  |                     "EnableKeyRotation": True, | 
					
						
							|  |  |  |                     "Enabled": True, | 
					
						
							|  |  |  |                     "KeyPolicy": "a policy", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "Type": "AWS::KMS::Key", | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     kms_key_template_json = json.dumps(kms_key_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-east-1") | 
					
						
							|  |  |  |     cf_conn.create_stack(StackName="test_stack", TemplateBody=kms_key_template_json) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     kms_conn = boto3.client("kms", "us-east-1") | 
					
						
							|  |  |  |     keys = kms_conn.list_keys()["Keys"] | 
					
						
							|  |  |  |     len(keys).should.equal(1) | 
					
						
							|  |  |  |     result = kms_conn.describe_key(KeyId=keys[0]["KeyId"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     result["KeyMetadata"]["Enabled"].should.equal(True) | 
					
						
							|  |  |  |     result["KeyMetadata"]["KeyUsage"].should.equal("ENCRYPT_DECRYPT") | 
					
						
							| 
									
										
										
										
											2016-11-07 09:53:44 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation() | 
					
						
							|  |  |  | @mock_ec2() | 
					
						
							|  |  |  | def test_stack_spot_fleet(): | 
					
						
							| 
									
										
										
										
											2016-11-07 23:08:30 -05:00
										 |  |  |     conn = boto3.client("ec2", "us-east-1") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-25 19:35:07 +02:00
										 |  |  |     vpc = conn.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"] | 
					
						
							| 
									
										
										
										
											2017-02-23 21:37:43 -05:00
										 |  |  |     subnet = conn.create_subnet( | 
					
						
							|  |  |  |         VpcId=vpc["VpcId"], CidrBlock="10.0.0.0/16", AvailabilityZone="us-east-1a" | 
					
						
							|  |  |  |     )["Subnet"] | 
					
						
							| 
									
										
										
										
											2016-11-07 23:08:30 -05:00
										 |  |  |     subnet_id = subnet["SubnetId"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-07 09:53:44 -05:00
										 |  |  |     spot_fleet_template = { | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "SpotFleet": { | 
					
						
							| 
									
										
										
										
											2017-02-23 21:37:43 -05:00
										 |  |  |                 "Type": "AWS::EC2::SpotFleet", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "SpotFleetRequestConfigData": { | 
					
						
							| 
									
										
										
										
											2022-11-17 21:41:08 -01:00
										 |  |  |                         "IamFleetRole": f"arn:aws:iam::{ACCOUNT_ID}:role/fleet", | 
					
						
							| 
									
										
										
										
											2017-02-23 21:37:43 -05:00
										 |  |  |                         "SpotPrice": "0.12", | 
					
						
							|  |  |  |                         "TargetCapacity": 6, | 
					
						
							|  |  |  |                         "AllocationStrategy": "diversified", | 
					
						
							|  |  |  |                         "LaunchSpecifications": [ | 
					
						
							|  |  |  |                             { | 
					
						
							| 
									
										
										
										
											2017-06-21 12:58:01 -04:00
										 |  |  |                                 "EbsOptimized": "false", | 
					
						
							|  |  |  |                                 "InstanceType": "t2.small", | 
					
						
							| 
									
										
										
										
											2021-01-13 09:02:11 +00:00
										 |  |  |                                 "ImageId": EXAMPLE_AMI_ID, | 
					
						
							| 
									
										
										
										
											2017-06-21 12:58:01 -04:00
										 |  |  |                                 "SubnetId": subnet_id, | 
					
						
							|  |  |  |                                 "WeightedCapacity": "2", | 
					
						
							|  |  |  |                                 "SpotPrice": "0.13", | 
					
						
							|  |  |  |                             }, | 
					
						
							|  |  |  |                             { | 
					
						
							|  |  |  |                                 "EbsOptimized": "true", | 
					
						
							|  |  |  |                                 "InstanceType": "t2.large", | 
					
						
							| 
									
										
										
										
											2021-01-13 09:02:11 +00:00
										 |  |  |                                 "ImageId": EXAMPLE_AMI_ID, | 
					
						
							| 
									
										
										
										
											2017-06-21 12:58:01 -04:00
										 |  |  |                                 "Monitoring": {"Enabled": "true"}, | 
					
						
							|  |  |  |                                 "SecurityGroups": [{"GroupId": "sg-123"}], | 
					
						
							|  |  |  |                                 "SubnetId": subnet_id, | 
					
						
							|  |  |  |                                 "IamInstanceProfile": { | 
					
						
							| 
									
										
										
										
											2022-11-17 21:41:08 -01:00
										 |  |  |                                     "Arn": f"arn:aws:iam::{ACCOUNT_ID}:role/fleet" | 
					
						
							| 
									
										
										
										
											2017-06-21 12:58:01 -04:00
										 |  |  |                                 }, | 
					
						
							|  |  |  |                                 "WeightedCapacity": "4", | 
					
						
							|  |  |  |                                 "SpotPrice": "10.00", | 
					
						
							|  |  |  |                             }, | 
					
						
							| 
									
										
										
										
											2017-02-23 21:37:43 -05:00
										 |  |  |                         ], | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2016-11-07 09:53:44 -05:00
										 |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     spot_fleet_template_json = json.dumps(spot_fleet_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-east-1") | 
					
						
							|  |  |  |     stack_id = cf_conn.create_stack( | 
					
						
							|  |  |  |         StackName="test_stack", TemplateBody=spot_fleet_template_json | 
					
						
							|  |  |  |     )["StackId"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     stack_resources = cf_conn.list_stack_resources(StackName=stack_id) | 
					
						
							|  |  |  |     stack_resources["StackResourceSummaries"].should.have.length_of(1) | 
					
						
							| 
									
										
										
										
											2017-02-23 21:37:43 -05:00
										 |  |  |     spot_fleet_id = stack_resources["StackResourceSummaries"][0]["PhysicalResourceId"] | 
					
						
							| 
									
										
										
										
											2016-11-07 09:53:44 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-23 21:37:43 -05:00
										 |  |  |     spot_fleet_requests = conn.describe_spot_fleet_requests( | 
					
						
							|  |  |  |         SpotFleetRequestIds=[spot_fleet_id] | 
					
						
							|  |  |  |     )["SpotFleetRequestConfigs"] | 
					
						
							| 
									
										
										
										
											2016-11-07 09:53:44 -05:00
										 |  |  |     len(spot_fleet_requests).should.equal(1) | 
					
						
							|  |  |  |     spot_fleet_request = spot_fleet_requests[0] | 
					
						
							|  |  |  |     spot_fleet_request["SpotFleetRequestState"].should.equal("active") | 
					
						
							|  |  |  |     spot_fleet_config = spot_fleet_request["SpotFleetRequestConfig"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     spot_fleet_config["SpotPrice"].should.equal("0.12") | 
					
						
							|  |  |  |     spot_fleet_config["TargetCapacity"].should.equal(6) | 
					
						
							| 
									
										
										
										
											2017-02-23 21:37:43 -05:00
										 |  |  |     spot_fleet_config["IamFleetRole"].should.equal( | 
					
						
							| 
									
										
										
										
											2022-11-17 21:41:08 -01:00
										 |  |  |         f"arn:aws:iam::{ACCOUNT_ID}:role/fleet" | 
					
						
							| 
									
										
										
										
											2017-02-23 21:37:43 -05:00
										 |  |  |     ) | 
					
						
							| 
									
										
										
										
											2016-11-07 09:53:44 -05:00
										 |  |  |     spot_fleet_config["AllocationStrategy"].should.equal("diversified") | 
					
						
							|  |  |  |     spot_fleet_config["FulfilledCapacity"].should.equal(6.0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     len(spot_fleet_config["LaunchSpecifications"]).should.equal(2) | 
					
						
							|  |  |  |     launch_spec = spot_fleet_config["LaunchSpecifications"][0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     launch_spec["EbsOptimized"].should.equal(False) | 
					
						
							| 
									
										
										
										
											2021-01-13 09:02:11 +00:00
										 |  |  |     launch_spec["ImageId"].should.equal(EXAMPLE_AMI_ID) | 
					
						
							| 
									
										
										
										
											2016-11-07 09:53:44 -05:00
										 |  |  |     launch_spec["InstanceType"].should.equal("t2.small") | 
					
						
							| 
									
										
										
										
											2016-11-07 23:08:30 -05:00
										 |  |  |     launch_spec["SubnetId"].should.equal(subnet_id) | 
					
						
							| 
									
										
										
										
											2016-11-07 09:53:44 -05:00
										 |  |  |     launch_spec["SpotPrice"].should.equal("0.13") | 
					
						
							|  |  |  |     launch_spec["WeightedCapacity"].should.equal(2.0) | 
					
						
							| 
									
										
										
										
											2017-10-27 11:54:43 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-01 17:09:10 -05:00
										 |  |  | @mock_cloudformation() | 
					
						
							|  |  |  | @mock_ec2() | 
					
						
							|  |  |  | def test_stack_spot_fleet_should_figure_out_default_price(): | 
					
						
							|  |  |  |     conn = boto3.client("ec2", "us-east-1") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-25 19:35:07 +02:00
										 |  |  |     vpc = conn.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"] | 
					
						
							| 
									
										
										
										
											2018-02-01 17:09:10 -05:00
										 |  |  |     subnet = conn.create_subnet( | 
					
						
							|  |  |  |         VpcId=vpc["VpcId"], CidrBlock="10.0.0.0/16", AvailabilityZone="us-east-1a" | 
					
						
							|  |  |  |     )["Subnet"] | 
					
						
							|  |  |  |     subnet_id = subnet["SubnetId"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     spot_fleet_template = { | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "SpotFleet1": { | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::SpotFleet", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "SpotFleetRequestConfigData": { | 
					
						
							| 
									
										
										
										
											2022-11-17 21:41:08 -01:00
										 |  |  |                         "IamFleetRole": f"arn:aws:iam::{ACCOUNT_ID}:role/fleet", | 
					
						
							| 
									
										
										
										
											2018-02-01 17:09:10 -05:00
										 |  |  |                         "TargetCapacity": 6, | 
					
						
							|  |  |  |                         "AllocationStrategy": "diversified", | 
					
						
							|  |  |  |                         "LaunchSpecifications": [ | 
					
						
							|  |  |  |                             { | 
					
						
							|  |  |  |                                 "EbsOptimized": "false", | 
					
						
							|  |  |  |                                 "InstanceType": "t2.small", | 
					
						
							| 
									
										
										
										
											2021-01-13 09:02:11 +00:00
										 |  |  |                                 "ImageId": EXAMPLE_AMI_ID, | 
					
						
							| 
									
										
										
										
											2018-02-01 17:09:10 -05:00
										 |  |  |                                 "SubnetId": subnet_id, | 
					
						
							|  |  |  |                                 "WeightedCapacity": "2", | 
					
						
							|  |  |  |                             }, | 
					
						
							|  |  |  |                             { | 
					
						
							|  |  |  |                                 "EbsOptimized": "true", | 
					
						
							|  |  |  |                                 "InstanceType": "t2.large", | 
					
						
							| 
									
										
										
										
											2021-01-13 09:02:11 +00:00
										 |  |  |                                 "ImageId": EXAMPLE_AMI_ID, | 
					
						
							| 
									
										
										
										
											2018-02-01 17:09:10 -05:00
										 |  |  |                                 "Monitoring": {"Enabled": "true"}, | 
					
						
							|  |  |  |                                 "SecurityGroups": [{"GroupId": "sg-123"}], | 
					
						
							|  |  |  |                                 "SubnetId": subnet_id, | 
					
						
							|  |  |  |                                 "IamInstanceProfile": { | 
					
						
							| 
									
										
										
										
											2022-11-17 21:41:08 -01:00
										 |  |  |                                     "Arn": f"arn:aws:iam::{ACCOUNT_ID}:role/fleet" | 
					
						
							| 
									
										
										
										
											2018-02-01 17:09:10 -05:00
										 |  |  |                                 }, | 
					
						
							|  |  |  |                                 "WeightedCapacity": "4", | 
					
						
							|  |  |  |                             }, | 
					
						
							|  |  |  |                         ], | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     spot_fleet_template_json = json.dumps(spot_fleet_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-east-1") | 
					
						
							|  |  |  |     stack_id = cf_conn.create_stack( | 
					
						
							|  |  |  |         StackName="test_stack", TemplateBody=spot_fleet_template_json | 
					
						
							|  |  |  |     )["StackId"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     stack_resources = cf_conn.list_stack_resources(StackName=stack_id) | 
					
						
							|  |  |  |     stack_resources["StackResourceSummaries"].should.have.length_of(1) | 
					
						
							|  |  |  |     spot_fleet_id = stack_resources["StackResourceSummaries"][0]["PhysicalResourceId"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     spot_fleet_requests = conn.describe_spot_fleet_requests( | 
					
						
							|  |  |  |         SpotFleetRequestIds=[spot_fleet_id] | 
					
						
							|  |  |  |     )["SpotFleetRequestConfigs"] | 
					
						
							|  |  |  |     len(spot_fleet_requests).should.equal(1) | 
					
						
							|  |  |  |     spot_fleet_request = spot_fleet_requests[0] | 
					
						
							|  |  |  |     spot_fleet_request["SpotFleetRequestState"].should.equal("active") | 
					
						
							|  |  |  |     spot_fleet_config = spot_fleet_request["SpotFleetRequestConfig"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     assert "SpotPrice" not in spot_fleet_config | 
					
						
							|  |  |  |     len(spot_fleet_config["LaunchSpecifications"]).should.equal(2) | 
					
						
							|  |  |  |     launch_spec1 = spot_fleet_config["LaunchSpecifications"][0] | 
					
						
							|  |  |  |     launch_spec2 = spot_fleet_config["LaunchSpecifications"][1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     assert "SpotPrice" not in launch_spec1 | 
					
						
							|  |  |  |     assert "SpotPrice" not in launch_spec2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-05 05:04:04 -04:00
										 |  |  | @mock_ec2 | 
					
						
							|  |  |  | @mock_elbv2 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | def test_invalid_action_type_listener_rule(): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     invalid_listener_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "alb": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "myelbv2", | 
					
						
							|  |  |  |                     "Scheme": "internet-facing", | 
					
						
							|  |  |  |                     "Subnets": [{"Ref": "mysubnet"}], | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "mytargetgroup1": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", | 
					
						
							|  |  |  |                 "Properties": {"Name": "mytargetgroup1"}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "mytargetgroup2": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", | 
					
						
							|  |  |  |                 "Properties": {"Name": "mytargetgroup2"}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "listener": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::Listener", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "DefaultActions": [ | 
					
						
							|  |  |  |                         {"Type": "forward", "TargetGroupArn": {"Ref": "mytargetgroup1"}} | 
					
						
							|  |  |  |                     ], | 
					
						
							|  |  |  |                     "LoadBalancerArn": {"Ref": "alb"}, | 
					
						
							|  |  |  |                     "Port": "80", | 
					
						
							|  |  |  |                     "Protocol": "HTTP", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "rule": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::ListenerRule", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Actions": [ | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             "Type": "forward2", | 
					
						
							|  |  |  |                             "TargetGroupArn": {"Ref": "mytargetgroup2"}, | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     ], | 
					
						
							|  |  |  |                     "Conditions": [{"field": "path-pattern", "values": ["/*"]}], | 
					
						
							|  |  |  |                     "ListenerArn": {"Ref": "listener"}, | 
					
						
							|  |  |  |                     "Priority": 2, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "myvpc": { | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::VPC", | 
					
						
							|  |  |  |                 "Properties": {"CidrBlock": "10.0.0.0/16"}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "mysubnet": { | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::Subnet", | 
					
						
							|  |  |  |                 "Properties": {"CidrBlock": "10.0.0.0/27", "VpcId": {"Ref": "myvpc"}}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     listener_template_json = json.dumps(invalid_listener_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cfn_conn = boto3.client("cloudformation", "us-west-1") | 
					
						
							|  |  |  |     cfn_conn.create_stack.when.called_with( | 
					
						
							|  |  |  |         StackName="listener_stack", TemplateBody=listener_template_json | 
					
						
							|  |  |  |     ).should.throw(ClientError) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-11 16:56:28 -04:00
										 |  |  | @mock_ec2 | 
					
						
							|  |  |  | @mock_elbv2 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_events | 
					
						
							|  |  |  | def test_update_stack_listener_and_rule(): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     initial_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "alb": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "myelbv2", | 
					
						
							|  |  |  |                     "Scheme": "internet-facing", | 
					
						
							|  |  |  |                     "Subnets": [{"Ref": "mysubnet"}], | 
					
						
							|  |  |  |                     "SecurityGroups": [{"Ref": "mysg"}], | 
					
						
							|  |  |  |                     "Type": "application", | 
					
						
							|  |  |  |                     "IpAddressType": "ipv4", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "mytargetgroup1": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", | 
					
						
							|  |  |  |                 "Properties": {"Name": "mytargetgroup1"}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "mytargetgroup2": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", | 
					
						
							|  |  |  |                 "Properties": {"Name": "mytargetgroup2"}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "listener": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::Listener", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "DefaultActions": [ | 
					
						
							|  |  |  |                         {"Type": "forward", "TargetGroupArn": {"Ref": "mytargetgroup1"}} | 
					
						
							|  |  |  |                     ], | 
					
						
							|  |  |  |                     "LoadBalancerArn": {"Ref": "alb"}, | 
					
						
							|  |  |  |                     "Port": "80", | 
					
						
							|  |  |  |                     "Protocol": "HTTP", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "rule": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::ListenerRule", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Actions": [ | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             "Type": "forward", | 
					
						
							|  |  |  |                             "TargetGroupArn": {"Ref": "mytargetgroup2"}, | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     ], | 
					
						
							|  |  |  |                     "Conditions": [{"Field": "path-pattern", "Values": ["/*"]}], | 
					
						
							|  |  |  |                     "ListenerArn": {"Ref": "listener"}, | 
					
						
							|  |  |  |                     "Priority": 2, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "myvpc": { | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::VPC", | 
					
						
							|  |  |  |                 "Properties": {"CidrBlock": "10.0.0.0/16"}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "mysubnet": { | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::Subnet", | 
					
						
							|  |  |  |                 "Properties": {"CidrBlock": "10.0.0.0/27", "VpcId": {"Ref": "myvpc"}}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "mysg": { | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::SecurityGroup", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "GroupName": "mysg", | 
					
						
							|  |  |  |                     "GroupDescription": "test security group", | 
					
						
							|  |  |  |                     "VpcId": {"Ref": "myvpc"}, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     initial_template_json = json.dumps(initial_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cfn_conn = boto3.client("cloudformation", "us-west-1") | 
					
						
							|  |  |  |     cfn_conn.create_stack(StackName="initial_stack", TemplateBody=initial_template_json) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     elbv2_conn = boto3.client("elbv2", "us-west-1") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     initial_template["Resources"]["rule"]["Properties"]["Conditions"][0][ | 
					
						
							|  |  |  |         "Field" | 
					
						
							|  |  |  |     ] = "host-header" | 
					
						
							|  |  |  |     initial_template["Resources"]["rule"]["Properties"]["Conditions"][0]["Values"] = "*" | 
					
						
							|  |  |  |     initial_template["Resources"]["listener"]["Properties"]["Port"] = 90 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     initial_template_json = json.dumps(initial_template) | 
					
						
							|  |  |  |     cfn_conn.update_stack(StackName="initial_stack", TemplateBody=initial_template_json) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     load_balancers = elbv2_conn.describe_load_balancers()["LoadBalancers"] | 
					
						
							|  |  |  |     listeners = elbv2_conn.describe_listeners( | 
					
						
							|  |  |  |         LoadBalancerArn=load_balancers[0]["LoadBalancerArn"] | 
					
						
							|  |  |  |     )["Listeners"] | 
					
						
							|  |  |  |     listeners[0]["Port"].should.equal(90) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     listener_rule = elbv2_conn.describe_rules(ListenerArn=listeners[0]["ListenerArn"])[ | 
					
						
							|  |  |  |         "Rules" | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     listener_rule[0]["Conditions"].should.equal( | 
					
						
							|  |  |  |         [{"Field": "host-header", "Values": ["*"]}] | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-27 11:54:43 -04:00
										 |  |  | @mock_ec2 | 
					
						
							|  |  |  | @mock_elbv2 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | def test_stack_elbv2_resources_integration(): | 
					
						
							|  |  |  |     alb_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							| 
									
										
										
										
											2017-10-27 15:32:16 -04:00
										 |  |  |         "Outputs": { | 
					
						
							|  |  |  |             "albdns": { | 
					
						
							|  |  |  |                 "Description": "Load balanacer DNS", | 
					
						
							|  |  |  |                 "Value": {"Fn::GetAtt": ["alb", "DNSName"]}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "albname": { | 
					
						
							|  |  |  |                 "Description": "Load balancer name", | 
					
						
							|  |  |  |                 "Value": {"Fn::GetAtt": ["alb", "LoadBalancerName"]}, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2017-11-15 10:11:11 -05:00
										 |  |  |             "canonicalhostedzoneid": { | 
					
						
							|  |  |  |                 "Description": "Load balancer canonical hosted zone ID", | 
					
						
							|  |  |  |                 "Value": {"Fn::GetAtt": ["alb", "CanonicalHostedZoneID"]}, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2017-10-27 15:32:16 -04:00
										 |  |  |         }, | 
					
						
							| 
									
										
										
										
											2017-10-27 11:54:43 -04:00
										 |  |  |         "Resources": { | 
					
						
							|  |  |  |             "alb": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::LoadBalancer", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "myelbv2", | 
					
						
							|  |  |  |                     "Scheme": "internet-facing", | 
					
						
							|  |  |  |                     "Subnets": [{"Ref": "mysubnet"}], | 
					
						
							|  |  |  |                     "SecurityGroups": [{"Ref": "mysg"}], | 
					
						
							|  |  |  |                     "Type": "application", | 
					
						
							|  |  |  |                     "IpAddressType": "ipv4", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2017-11-15 14:36:53 -05:00
										 |  |  |             "mytargetgroup1": { | 
					
						
							| 
									
										
										
										
											2017-10-27 11:54:43 -04:00
										 |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "HealthCheckIntervalSeconds": 30, | 
					
						
							|  |  |  |                     "HealthCheckPath": "/status", | 
					
						
							|  |  |  |                     "HealthCheckPort": 80, | 
					
						
							|  |  |  |                     "HealthCheckProtocol": "HTTP", | 
					
						
							|  |  |  |                     "HealthCheckTimeoutSeconds": 5, | 
					
						
							|  |  |  |                     "HealthyThresholdCount": 30, | 
					
						
							|  |  |  |                     "UnhealthyThresholdCount": 5, | 
					
						
							|  |  |  |                     "Matcher": {"HttpCode": "200,201"}, | 
					
						
							| 
									
										
										
										
											2017-11-15 14:36:53 -05:00
										 |  |  |                     "Name": "mytargetgroup1", | 
					
						
							| 
									
										
										
										
											2017-10-27 11:54:43 -04:00
										 |  |  |                     "Port": 80, | 
					
						
							|  |  |  |                     "Protocol": "HTTP", | 
					
						
							|  |  |  |                     "TargetType": "instance", | 
					
						
							|  |  |  |                     "Targets": [{"Id": {"Ref": "ec2instance", "Port": 80}}], | 
					
						
							|  |  |  |                     "VpcId": {"Ref": "myvpc"}, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2017-11-15 14:36:53 -05:00
										 |  |  |             "mytargetgroup2": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::TargetGroup", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "HealthCheckIntervalSeconds": 30, | 
					
						
							|  |  |  |                     "HealthCheckPath": "/status", | 
					
						
							|  |  |  |                     "HealthCheckPort": 8080, | 
					
						
							|  |  |  |                     "HealthCheckProtocol": "HTTP", | 
					
						
							|  |  |  |                     "HealthCheckTimeoutSeconds": 5, | 
					
						
							|  |  |  |                     "HealthyThresholdCount": 30, | 
					
						
							|  |  |  |                     "UnhealthyThresholdCount": 5, | 
					
						
							|  |  |  |                     "Name": "mytargetgroup2", | 
					
						
							|  |  |  |                     "Port": 8080, | 
					
						
							|  |  |  |                     "Protocol": "HTTP", | 
					
						
							|  |  |  |                     "TargetType": "instance", | 
					
						
							|  |  |  |                     "Targets": [{"Id": {"Ref": "ec2instance", "Port": 8080}}], | 
					
						
							|  |  |  |                     "VpcId": {"Ref": "myvpc"}, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2017-10-27 11:54:43 -04:00
										 |  |  |             "listener": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::Listener", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "DefaultActions": [ | 
					
						
							| 
									
										
										
										
											2017-11-15 14:36:53 -05:00
										 |  |  |                         {"Type": "forward", "TargetGroupArn": {"Ref": "mytargetgroup1"}} | 
					
						
							| 
									
										
										
										
											2017-10-27 11:54:43 -04:00
										 |  |  |                     ], | 
					
						
							|  |  |  |                     "LoadBalancerArn": {"Ref": "alb"}, | 
					
						
							|  |  |  |                     "Port": "80", | 
					
						
							|  |  |  |                     "Protocol": "HTTP", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2021-06-05 05:04:04 -04:00
										 |  |  |             "rule": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::ListenerRule", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Actions": [ | 
					
						
							| 
									
										
										
										
											2021-06-09 13:41:18 -04:00
										 |  |  |                         { | 
					
						
							|  |  |  |                             "Type": "forward", | 
					
						
							|  |  |  |                             "ForwardConfig": { | 
					
						
							|  |  |  |                                 "TargetGroups": [ | 
					
						
							|  |  |  |                                     { | 
					
						
							|  |  |  |                                         "TargetGroupArn": {"Ref": "mytargetgroup2"}, | 
					
						
							|  |  |  |                                         "Weight": 1, | 
					
						
							|  |  |  |                                     }, | 
					
						
							|  |  |  |                                     { | 
					
						
							|  |  |  |                                         "TargetGroupArn": {"Ref": "mytargetgroup1"}, | 
					
						
							|  |  |  |                                         "Weight": 2, | 
					
						
							|  |  |  |                                     }, | 
					
						
							|  |  |  |                                 ] | 
					
						
							|  |  |  |                             }, | 
					
						
							|  |  |  |                         } | 
					
						
							| 
									
										
										
										
											2021-06-05 05:04:04 -04:00
										 |  |  |                     ], | 
					
						
							| 
									
										
										
										
											2021-06-11 16:56:28 -04:00
										 |  |  |                     "Conditions": [{"Field": "path-pattern", "Values": ["/*"]}], | 
					
						
							| 
									
										
										
										
											2021-06-05 05:04:04 -04:00
										 |  |  |                     "ListenerArn": {"Ref": "listener"}, | 
					
						
							|  |  |  |                     "Priority": 2, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2021-06-09 13:41:18 -04:00
										 |  |  |             "rule2": { | 
					
						
							|  |  |  |                 "Type": "AWS::ElasticLoadBalancingV2::ListenerRule", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Actions": [ | 
					
						
							|  |  |  |                         {"Type": "forward", "TargetGroupArn": {"Ref": "mytargetgroup2"}} | 
					
						
							|  |  |  |                     ], | 
					
						
							| 
									
										
										
										
											2021-06-11 16:56:28 -04:00
										 |  |  |                     "Conditions": [{"Field": "host-header", "Values": ["example.com"]}], | 
					
						
							| 
									
										
										
										
											2021-06-09 13:41:18 -04:00
										 |  |  |                     "ListenerArn": {"Ref": "listener"}, | 
					
						
							|  |  |  |                     "Priority": 30, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2017-10-27 11:54:43 -04:00
										 |  |  |             "myvpc": { | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::VPC", | 
					
						
							|  |  |  |                 "Properties": {"CidrBlock": "10.0.0.0/16"}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "mysubnet": { | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::Subnet", | 
					
						
							|  |  |  |                 "Properties": {"CidrBlock": "10.0.0.0/27", "VpcId": {"Ref": "myvpc"}}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "mysg": { | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::SecurityGroup", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "GroupName": "mysg", | 
					
						
							|  |  |  |                     "GroupDescription": "test security group", | 
					
						
							|  |  |  |                     "VpcId": {"Ref": "myvpc"}, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "ec2instance": { | 
					
						
							|  |  |  |                 "Type": "AWS::EC2::Instance", | 
					
						
							| 
									
										
										
										
											2021-01-13 09:02:11 +00:00
										 |  |  |                 "Properties": {"ImageId": EXAMPLE_AMI_ID, "UserData": "some user data"}, | 
					
						
							| 
									
										
										
										
											2017-10-27 11:54:43 -04:00
										 |  |  |             }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     alb_template_json = json.dumps(alb_template) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-27 15:32:16 -04:00
										 |  |  |     cfn_conn = boto3.client("cloudformation", "us-west-1") | 
					
						
							| 
									
										
										
										
											2017-10-27 11:54:43 -04:00
										 |  |  |     cfn_conn.create_stack(StackName="elb_stack", TemplateBody=alb_template_json) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     elbv2_conn = boto3.client("elbv2", "us-west-1") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     load_balancers = elbv2_conn.describe_load_balancers()["LoadBalancers"] | 
					
						
							| 
									
										
										
										
											2017-10-27 13:25:22 -04:00
										 |  |  |     len(load_balancers).should.equal(1) | 
					
						
							|  |  |  |     load_balancers[0]["LoadBalancerName"].should.equal("myelbv2") | 
					
						
							|  |  |  |     load_balancers[0]["Scheme"].should.equal("internet-facing") | 
					
						
							|  |  |  |     load_balancers[0]["Type"].should.equal("application") | 
					
						
							|  |  |  |     load_balancers[0]["IpAddressType"].should.equal("ipv4") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-15 14:36:53 -05:00
										 |  |  |     target_groups = sorted( | 
					
						
							|  |  |  |         elbv2_conn.describe_target_groups()["TargetGroups"], | 
					
						
							|  |  |  |         key=lambda tg: tg["TargetGroupName"], | 
					
						
							|  |  |  |     )  # sort to do comparison with indexes | 
					
						
							|  |  |  |     len(target_groups).should.equal(2) | 
					
						
							| 
									
										
										
										
											2017-10-27 13:25:22 -04:00
										 |  |  |     target_groups[0]["HealthCheckIntervalSeconds"].should.equal(30) | 
					
						
							|  |  |  |     target_groups[0]["HealthCheckPath"].should.equal("/status") | 
					
						
							|  |  |  |     target_groups[0]["HealthCheckPort"].should.equal("80") | 
					
						
							|  |  |  |     target_groups[0]["HealthCheckProtocol"].should.equal("HTTP") | 
					
						
							|  |  |  |     target_groups[0]["HealthCheckTimeoutSeconds"].should.equal(5) | 
					
						
							|  |  |  |     target_groups[0]["HealthyThresholdCount"].should.equal(30) | 
					
						
							|  |  |  |     target_groups[0]["UnhealthyThresholdCount"].should.equal(5) | 
					
						
							|  |  |  |     target_groups[0]["Matcher"].should.equal({"HttpCode": "200,201"}) | 
					
						
							| 
									
										
										
										
											2017-11-15 14:36:53 -05:00
										 |  |  |     target_groups[0]["TargetGroupName"].should.equal("mytargetgroup1") | 
					
						
							| 
									
										
										
										
											2017-10-27 13:25:22 -04:00
										 |  |  |     target_groups[0]["Port"].should.equal(80) | 
					
						
							|  |  |  |     target_groups[0]["Protocol"].should.equal("HTTP") | 
					
						
							|  |  |  |     target_groups[0]["TargetType"].should.equal("instance") | 
					
						
							| 
									
										
										
										
											2019-10-31 08:44:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-15 14:36:53 -05:00
										 |  |  |     target_groups[1]["HealthCheckIntervalSeconds"].should.equal(30) | 
					
						
							|  |  |  |     target_groups[1]["HealthCheckPath"].should.equal("/status") | 
					
						
							|  |  |  |     target_groups[1]["HealthCheckPort"].should.equal("8080") | 
					
						
							|  |  |  |     target_groups[1]["HealthCheckProtocol"].should.equal("HTTP") | 
					
						
							|  |  |  |     target_groups[1]["HealthCheckTimeoutSeconds"].should.equal(5) | 
					
						
							|  |  |  |     target_groups[1]["HealthyThresholdCount"].should.equal(30) | 
					
						
							|  |  |  |     target_groups[1]["UnhealthyThresholdCount"].should.equal(5) | 
					
						
							|  |  |  |     target_groups[1]["Matcher"].should.equal({"HttpCode": "200"}) | 
					
						
							|  |  |  |     target_groups[1]["TargetGroupName"].should.equal("mytargetgroup2") | 
					
						
							|  |  |  |     target_groups[1]["Port"].should.equal(8080) | 
					
						
							|  |  |  |     target_groups[1]["Protocol"].should.equal("HTTP") | 
					
						
							|  |  |  |     target_groups[1]["TargetType"].should.equal("instance") | 
					
						
							| 
									
										
										
										
											2019-10-31 08:44:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-27 14:24:45 -04:00
										 |  |  |     listeners = elbv2_conn.describe_listeners( | 
					
						
							|  |  |  |         LoadBalancerArn=load_balancers[0]["LoadBalancerArn"] | 
					
						
							|  |  |  |     )["Listeners"] | 
					
						
							|  |  |  |     len(listeners).should.equal(1) | 
					
						
							|  |  |  |     listeners[0]["LoadBalancerArn"].should.equal(load_balancers[0]["LoadBalancerArn"]) | 
					
						
							|  |  |  |     listeners[0]["Port"].should.equal(80) | 
					
						
							|  |  |  |     listeners[0]["Protocol"].should.equal("HTTP") | 
					
						
							|  |  |  |     listeners[0]["DefaultActions"].should.equal( | 
					
						
							|  |  |  |         [{"Type": "forward", "TargetGroupArn": target_groups[0]["TargetGroupArn"]}] | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2017-10-27 15:32:16 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-05 05:04:04 -04:00
										 |  |  |     listener_rule = elbv2_conn.describe_rules(ListenerArn=listeners[0]["ListenerArn"])[ | 
					
						
							|  |  |  |         "Rules" | 
					
						
							|  |  |  |     ] | 
					
						
							| 
									
										
										
										
											2021-06-09 13:41:18 -04:00
										 |  |  |     len(listener_rule).should.equal(3) | 
					
						
							| 
									
										
										
										
											2021-06-05 05:04:04 -04:00
										 |  |  |     listener_rule[0]["Priority"].should.equal("2") | 
					
						
							|  |  |  |     listener_rule[0]["Actions"].should.equal( | 
					
						
							| 
									
										
										
										
											2021-06-09 13:41:18 -04:00
										 |  |  |         [ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "Type": "forward", | 
					
						
							|  |  |  |                 "ForwardConfig": { | 
					
						
							|  |  |  |                     "TargetGroups": [ | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             "TargetGroupArn": target_groups[1]["TargetGroupArn"], | 
					
						
							|  |  |  |                             "Weight": 1, | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             "TargetGroupArn": target_groups[0]["TargetGroupArn"], | 
					
						
							|  |  |  |                             "Weight": 2, | 
					
						
							|  |  |  |                         }, | 
					
						
							| 
									
										
										
										
											2022-03-21 19:55:19 -01:00
										 |  |  |                     ], | 
					
						
							|  |  |  |                     "TargetGroupStickinessConfig": {"Enabled": False}, | 
					
						
							| 
									
										
										
										
											2021-06-09 13:41:18 -04:00
										 |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-07-26 16:21:17 +02:00
										 |  |  |         ], | 
					
						
							|  |  |  |         [{"Type": "forward", "TargetGroupArn": target_groups[1]["TargetGroupArn"]}], | 
					
						
							| 
									
										
										
										
											2021-06-05 05:04:04 -04:00
										 |  |  |     ) | 
					
						
							|  |  |  |     listener_rule[0]["Conditions"].should.equal( | 
					
						
							|  |  |  |         [{"Field": "path-pattern", "Values": ["/*"]}] | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-09 13:41:18 -04:00
										 |  |  |     listener_rule[1]["Priority"].should.equal("30") | 
					
						
							|  |  |  |     listener_rule[1]["Actions"].should.equal( | 
					
						
							|  |  |  |         [{"Type": "forward", "TargetGroupArn": target_groups[1]["TargetGroupArn"]}] | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     listener_rule[1]["Conditions"].should.equal( | 
					
						
							|  |  |  |         [{"Field": "host-header", "Values": ["example.com"]}] | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-27 15:32:16 -04:00
										 |  |  |     # test outputs | 
					
						
							|  |  |  |     stacks = cfn_conn.describe_stacks(StackName="elb_stack")["Stacks"] | 
					
						
							|  |  |  |     len(stacks).should.equal(1) | 
					
						
							| 
									
										
										
										
											2017-11-12 11:18:25 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     dns = list( | 
					
						
							|  |  |  |         filter(lambda item: item["OutputKey"] == "albdns", stacks[0]["Outputs"]) | 
					
						
							|  |  |  |     )[0] | 
					
						
							|  |  |  |     name = list( | 
					
						
							|  |  |  |         filter(lambda item: item["OutputKey"] == "albname", stacks[0]["Outputs"]) | 
					
						
							|  |  |  |     )[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dns["OutputValue"].should.equal(load_balancers[0]["DNSName"]) | 
					
						
							|  |  |  |     name["OutputValue"].should.equal(load_balancers[0]["LoadBalancerName"]) | 
					
						
							| 
									
										
										
										
											2019-05-25 18:16:33 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-11 21:29:16 -01:00
										 |  |  | @mock_dynamodb | 
					
						
							| 
									
										
										
										
											2019-05-25 18:16:33 +09:00
										 |  |  | @mock_cloudformation | 
					
						
							|  |  |  | def test_stack_dynamodb_resources_integration(): | 
					
						
							|  |  |  |     dynamodb_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "myDynamoDBTable": { | 
					
						
							|  |  |  |                 "Type": "AWS::DynamoDB::Table", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "AttributeDefinitions": [ | 
					
						
							|  |  |  |                         {"AttributeName": "Album", "AttributeType": "S"}, | 
					
						
							|  |  |  |                         {"AttributeName": "Artist", "AttributeType": "S"}, | 
					
						
							|  |  |  |                         {"AttributeName": "Sales", "AttributeType": "N"}, | 
					
						
							|  |  |  |                         {"AttributeName": "NumberOfSongs", "AttributeType": "N"}, | 
					
						
							|  |  |  |                     ], | 
					
						
							|  |  |  |                     "KeySchema": [ | 
					
						
							|  |  |  |                         {"AttributeName": "Album", "KeyType": "HASH"}, | 
					
						
							|  |  |  |                         {"AttributeName": "Artist", "KeyType": "RANGE"}, | 
					
						
							| 
									
										
										
										
											2019-10-31 08:44:26 -07:00
										 |  |  |                     ], | 
					
						
							| 
									
										
										
										
											2019-05-25 18:16:33 +09:00
										 |  |  |                     "ProvisionedThroughput": { | 
					
						
							|  |  |  |                         "ReadCapacityUnits": "5", | 
					
						
							|  |  |  |                         "WriteCapacityUnits": "5", | 
					
						
							| 
									
										
										
										
											2019-10-31 08:44:26 -07:00
										 |  |  |                     }, | 
					
						
							| 
									
										
										
										
											2019-05-25 18:16:33 +09:00
										 |  |  |                     "TableName": "myTableName", | 
					
						
							|  |  |  |                     "GlobalSecondaryIndexes": [ | 
					
						
							| 
									
										
										
										
											2019-10-31 08:44:26 -07:00
										 |  |  |                         { | 
					
						
							| 
									
										
										
										
											2019-05-25 18:16:33 +09:00
										 |  |  |                             "IndexName": "myGSI", | 
					
						
							|  |  |  |                             "KeySchema": [ | 
					
						
							|  |  |  |                                 {"AttributeName": "Sales", "KeyType": "HASH"}, | 
					
						
							|  |  |  |                                 {"AttributeName": "Artist", "KeyType": "RANGE"}, | 
					
						
							| 
									
										
										
										
											2019-10-31 08:44:26 -07:00
										 |  |  |                             ], | 
					
						
							| 
									
										
										
										
											2019-05-25 18:16:33 +09:00
										 |  |  |                             "Projection": { | 
					
						
							|  |  |  |                                 "NonKeyAttributes": ["Album", "NumberOfSongs"], | 
					
						
							|  |  |  |                                 "ProjectionType": "INCLUDE", | 
					
						
							|  |  |  |                             }, | 
					
						
							|  |  |  |                             "ProvisionedThroughput": { | 
					
						
							|  |  |  |                                 "ReadCapacityUnits": "5", | 
					
						
							|  |  |  |                                 "WriteCapacityUnits": "5", | 
					
						
							|  |  |  |                             }, | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             "IndexName": "myGSI2", | 
					
						
							|  |  |  |                             "KeySchema": [ | 
					
						
							|  |  |  |                                 {"AttributeName": "NumberOfSongs", "KeyType": "HASH"}, | 
					
						
							|  |  |  |                                 {"AttributeName": "Sales", "KeyType": "RANGE"}, | 
					
						
							|  |  |  |                             ], | 
					
						
							|  |  |  |                             "Projection": { | 
					
						
							|  |  |  |                                 "NonKeyAttributes": ["Album", "Artist"], | 
					
						
							|  |  |  |                                 "ProjectionType": "INCLUDE", | 
					
						
							|  |  |  |                             }, | 
					
						
							|  |  |  |                             "ProvisionedThroughput": { | 
					
						
							|  |  |  |                                 "ReadCapacityUnits": "5", | 
					
						
							|  |  |  |                                 "WriteCapacityUnits": "5", | 
					
						
							|  |  |  |                             }, | 
					
						
							|  |  |  |                         }, | 
					
						
							| 
									
										
										
										
											2019-10-31 08:44:26 -07:00
										 |  |  |                     ], | 
					
						
							| 
									
										
										
										
											2019-05-25 18:16:33 +09:00
										 |  |  |                     "LocalSecondaryIndexes": [ | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             "IndexName": "myLSI", | 
					
						
							|  |  |  |                             "KeySchema": [ | 
					
						
							|  |  |  |                                 {"AttributeName": "Album", "KeyType": "HASH"}, | 
					
						
							|  |  |  |                                 {"AttributeName": "Sales", "KeyType": "RANGE"}, | 
					
						
							|  |  |  |                             ], | 
					
						
							|  |  |  |                             "Projection": { | 
					
						
							|  |  |  |                                 "NonKeyAttributes": ["Artist", "NumberOfSongs"], | 
					
						
							|  |  |  |                                 "ProjectionType": "INCLUDE", | 
					
						
							|  |  |  |                             }, | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     ], | 
					
						
							| 
									
										
										
										
											2020-06-04 07:45:00 +01:00
										 |  |  |                     "StreamSpecification": {"StreamViewType": "KEYS_ONLY"}, | 
					
						
							| 
									
										
										
										
											2019-05-25 18:16:33 +09:00
										 |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dynamodb_template_json = json.dumps(dynamodb_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cfn_conn = boto3.client("cloudformation", "us-east-1") | 
					
						
							|  |  |  |     cfn_conn.create_stack( | 
					
						
							|  |  |  |         StackName="dynamodb_stack", TemplateBody=dynamodb_template_json | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 07:45:00 +01:00
										 |  |  |     dynamodb_client = boto3.client("dynamodb", region_name="us-east-1") | 
					
						
							|  |  |  |     table_desc = dynamodb_client.describe_table(TableName="myTableName")["Table"] | 
					
						
							|  |  |  |     table_desc["StreamSpecification"].should.equal( | 
					
						
							|  |  |  |         {"StreamEnabled": True, "StreamViewType": "KEYS_ONLY"} | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-25 18:16:33 +09:00
										 |  |  |     dynamodb_conn = boto3.resource("dynamodb", region_name="us-east-1") | 
					
						
							|  |  |  |     table = dynamodb_conn.Table("myTableName") | 
					
						
							|  |  |  |     table.name.should.equal("myTableName") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     table.put_item( | 
					
						
							|  |  |  |         Item={"Album": "myAlbum", "Artist": "myArtist", "Sales": 10, "NumberOfSongs": 5} | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     response = table.get_item(Key={"Album": "myAlbum", "Artist": "myArtist"}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     response["Item"]["Album"].should.equal("myAlbum") | 
					
						
							|  |  |  |     response["Item"]["Sales"].should.equal(Decimal("10")) | 
					
						
							|  |  |  |     response["Item"]["NumberOfSongs"].should.equal(Decimal("5")) | 
					
						
							|  |  |  |     response["Item"]["Album"].should.equal("myAlbum") | 
					
						
							| 
									
										
										
										
											2020-03-18 13:02:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_logs | 
					
						
							|  |  |  | @mock_s3 | 
					
						
							|  |  |  | def test_create_log_group_using_fntransform(): | 
					
						
							|  |  |  |     s3_resource = boto3.resource("s3") | 
					
						
							|  |  |  |     s3_resource.create_bucket( | 
					
						
							|  |  |  |         Bucket="owi-common-cf", | 
					
						
							|  |  |  |         CreateBucketConfiguration={"LocationConstraint": "us-west-2"}, | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     s3_resource.Object("owi-common-cf", "snippets/test.json").put( | 
					
						
							|  |  |  |         Body=json.dumps({"lgname": {"name": "some-log-group"}}) | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Mappings": { | 
					
						
							|  |  |  |             "EnvironmentMapping": { | 
					
						
							|  |  |  |                 "Fn::Transform": { | 
					
						
							|  |  |  |                     "Name": "AWS::Include", | 
					
						
							|  |  |  |                     "Parameters": {"Location": "s3://owi-common-cf/snippets/test.json"}, | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "LogGroup": { | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "LogGroupName": { | 
					
						
							|  |  |  |                         "Fn::FindInMap": ["EnvironmentMapping", "lgname", "name"] | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     "RetentionInDays": 90, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "Type": "AWS::Logs::LogGroup", | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-18 19:44:29 +00:00
										 |  |  |     cf_conn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  |     cf_conn.create_stack(StackName="test_stack", TemplateBody=json.dumps(template)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     logs_conn = boto3.client("logs", region_name="us-west-2") | 
					
						
							|  |  |  |     log_group = logs_conn.describe_log_groups()["logGroups"][0] | 
					
						
							|  |  |  |     log_group["logGroupName"].should.equal("some-log-group") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-18 13:02:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-18 14:47:31 +05:30
										 |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_logs | 
					
						
							|  |  |  | def test_create_cloudwatch_logs_resource_policy(): | 
					
						
							|  |  |  |     policy_document = json.dumps( | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             "Statement": [ | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     "Action": ["logs:CreateLogStream", "logs:PutLogEvents"], | 
					
						
							|  |  |  |                     "Effect": "Allow", | 
					
						
							|  |  |  |                     "Principal": {"Service": "es.amazonaws.com"}, | 
					
						
							|  |  |  |                     "Resource": "*", | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     template1 = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "LogGroupPolicy1": { | 
					
						
							|  |  |  |                 "Type": "AWS::Logs::ResourcePolicy", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "PolicyDocument": policy_document, | 
					
						
							|  |  |  |                     "PolicyName": "TestPolicyA", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     template2 = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "LogGroupPolicy1": { | 
					
						
							|  |  |  |                 "Type": "AWS::Logs::ResourcePolicy", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "PolicyDocument": policy_document, | 
					
						
							|  |  |  |                     "PolicyName": "TestPolicyB", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "LogGroupPolicy2": { | 
					
						
							|  |  |  |                 "Type": "AWS::Logs::ResourcePolicy", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "PolicyDocument": policy_document, | 
					
						
							|  |  |  |                     "PolicyName": "TestPolicyC", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-east-1") | 
					
						
							|  |  |  |     cf_conn.create_stack(StackName="test_stack", TemplateBody=json.dumps(template1)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     logs_conn = boto3.client("logs", region_name="us-east-1") | 
					
						
							|  |  |  |     policies = logs_conn.describe_resource_policies()["resourcePolicies"] | 
					
						
							|  |  |  |     policies.should.have.length_of(1) | 
					
						
							|  |  |  |     policies.should.be.containing_item_with_attributes( | 
					
						
							|  |  |  |         policyName="TestPolicyA", policyDocument=policy_document | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn.update_stack(StackName="test_stack", TemplateBody=json.dumps(template2)) | 
					
						
							|  |  |  |     policies = logs_conn.describe_resource_policies()["resourcePolicies"] | 
					
						
							|  |  |  |     policies.should.have.length_of(2) | 
					
						
							|  |  |  |     policies.should.be.containing_item_with_attributes( | 
					
						
							|  |  |  |         policyName="TestPolicyB", policyDocument=policy_document | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     policies.should.be.containing_item_with_attributes( | 
					
						
							|  |  |  |         policyName="TestPolicyC", policyDocument=policy_document | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn.update_stack(StackName="test_stack", TemplateBody=json.dumps(template1)) | 
					
						
							|  |  |  |     policies = logs_conn.describe_resource_policies()["resourcePolicies"] | 
					
						
							|  |  |  |     policies.should.have.length_of(1) | 
					
						
							|  |  |  |     policies.should.be.containing_item_with_attributes( | 
					
						
							|  |  |  |         policyName="TestPolicyA", policyDocument=policy_document | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_logs | 
					
						
							|  |  |  | def test_delete_stack_containing_cloudwatch_logs_resource_policy(): | 
					
						
							|  |  |  |     template1 = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "LogGroupPolicy1": { | 
					
						
							|  |  |  |                 "Type": "AWS::Logs::ResourcePolicy", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "PolicyDocument": '{"Statement":[{"Action":"logs:*","Effect":"Allow","Principal":"*","Resource":"*"}]}', | 
					
						
							|  |  |  |                     "PolicyName": "TestPolicyA", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-east-1") | 
					
						
							|  |  |  |     cf_conn.create_stack(StackName="test_stack", TemplateBody=json.dumps(template1)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     logs_conn = boto3.client("logs", region_name="us-east-1") | 
					
						
							|  |  |  |     policies = logs_conn.describe_resource_policies()["resourcePolicies"] | 
					
						
							|  |  |  |     policies.should.have.length_of(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn.delete_stack(StackName="test_stack") | 
					
						
							|  |  |  |     policies = logs_conn.describe_resource_policies()["resourcePolicies"] | 
					
						
							|  |  |  |     policies.should.have.length_of(0) | 
					
						
							| 
									
										
										
										
											2020-03-22 18:03:42 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-24 06:39:02 -05:00
										 |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_sqs | 
					
						
							|  |  |  | def test_delete_stack_with_deletion_policy_boto3(): | 
					
						
							|  |  |  |     sqs_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "QueueGroup": { | 
					
						
							|  |  |  |                 "DeletionPolicy": "Retain", | 
					
						
							|  |  |  |                 "Type": "AWS::SQS::Queue", | 
					
						
							|  |  |  |                 "Properties": {"QueueName": "my-queue", "VisibilityTimeout": 60}, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sqs_template_json = json.dumps(sqs_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf = boto3.client("cloudformation", region_name="us-west-1") | 
					
						
							|  |  |  |     cf.create_stack( | 
					
						
							|  |  |  |         StackName="test_stack", | 
					
						
							|  |  |  |         TemplateBody=sqs_template_json, | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     sqs = boto3.client("sqs", region_name="us-west-1") | 
					
						
							|  |  |  |     sqs.list_queues()["QueueUrls"].should.have.length_of(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf.delete_stack( | 
					
						
							|  |  |  |         StackName="test_stack", | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     sqs.list_queues()["QueueUrls"].should.have.length_of(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-22 18:03:42 -03:00
										 |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_events | 
					
						
							| 
									
										
										
										
											2020-03-23 22:17:02 -03:00
										 |  |  | def test_stack_events_create_rule_integration(): | 
					
						
							| 
									
										
										
										
											2020-03-22 18:03:42 -03:00
										 |  |  |     events_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							| 
									
										
										
										
											2020-03-23 22:17:02 -03:00
										 |  |  |             "Event": { | 
					
						
							| 
									
										
										
										
											2020-03-22 18:03:42 -03:00
										 |  |  |                 "Type": "AWS::Events::Rule", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "quick-fox", | 
					
						
							|  |  |  |                     "State": "ENABLED", | 
					
						
							|  |  |  |                     "ScheduleExpression": "rate(5 minutes)", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  |     cf_conn.create_stack( | 
					
						
							| 
									
										
										
										
											2020-04-01 22:48:40 -03:00
										 |  |  |         StackName="test_stack", TemplateBody=json.dumps(events_template) | 
					
						
							| 
									
										
										
										
											2020-03-22 18:03:42 -03:00
										 |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-23 22:17:02 -03:00
										 |  |  |     rules = boto3.client("events", "us-west-2").list_rules() | 
					
						
							|  |  |  |     rules["Rules"].should.have.length_of(1) | 
					
						
							|  |  |  |     rules["Rules"][0]["Name"].should.equal("quick-fox") | 
					
						
							|  |  |  |     rules["Rules"][0]["State"].should.equal("ENABLED") | 
					
						
							|  |  |  |     rules["Rules"][0]["ScheduleExpression"].should.equal("rate(5 minutes)") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_events | 
					
						
							|  |  |  | def test_stack_events_delete_rule_integration(): | 
					
						
							|  |  |  |     events_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "Event": { | 
					
						
							|  |  |  |                 "Type": "AWS::Events::Rule", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "quick-fox", | 
					
						
							|  |  |  |                     "State": "ENABLED", | 
					
						
							|  |  |  |                     "ScheduleExpression": "rate(5 minutes)", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  |     cf_conn.create_stack( | 
					
						
							| 
									
										
										
										
											2020-04-01 22:48:40 -03:00
										 |  |  |         StackName="test_stack", TemplateBody=json.dumps(events_template) | 
					
						
							| 
									
										
										
										
											2020-03-23 22:17:02 -03:00
										 |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rules = boto3.client("events", "us-west-2").list_rules() | 
					
						
							|  |  |  |     rules["Rules"].should.have.length_of(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn.delete_stack(StackName="test_stack") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rules = boto3.client("events", "us-west-2").list_rules() | 
					
						
							|  |  |  |     rules["Rules"].should.have.length_of(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_events | 
					
						
							|  |  |  | def test_stack_events_create_rule_without_name_integration(): | 
					
						
							|  |  |  |     events_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "Event": { | 
					
						
							|  |  |  |                 "Type": "AWS::Events::Rule", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "State": "ENABLED", | 
					
						
							|  |  |  |                     "ScheduleExpression": "rate(5 minutes)", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  |     cf_conn.create_stack( | 
					
						
							| 
									
										
										
										
											2020-04-01 22:48:40 -03:00
										 |  |  |         StackName="test_stack", TemplateBody=json.dumps(events_template) | 
					
						
							| 
									
										
										
										
											2020-03-23 22:17:02 -03:00
										 |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rules = boto3.client("events", "us-west-2").list_rules() | 
					
						
							|  |  |  |     rules["Rules"][0]["Name"].should.contain("test_stack-Event-") | 
					
						
							| 
									
										
										
										
											2020-04-01 22:00:20 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_events | 
					
						
							|  |  |  | @mock_logs | 
					
						
							|  |  |  | def test_stack_events_create_rule_as_target(): | 
					
						
							|  |  |  |     events_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "SecurityGroup": { | 
					
						
							|  |  |  |                 "Type": "AWS::Logs::LogGroup", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "LogGroupName": {"Fn::GetAtt": ["Event", "Arn"]}, | 
					
						
							|  |  |  |                     "RetentionInDays": 3, | 
					
						
							| 
									
										
										
										
											2020-04-01 22:48:40 -03:00
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2020-04-01 22:00:20 -03:00
										 |  |  |             }, | 
					
						
							|  |  |  |             "Event": { | 
					
						
							|  |  |  |                 "Type": "AWS::Events::Rule", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "State": "ENABLED", | 
					
						
							|  |  |  |                     "ScheduleExpression": "rate(5 minutes)", | 
					
						
							|  |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2020-04-01 22:48:40 -03:00
										 |  |  |             }, | 
					
						
							| 
									
										
										
										
											2020-04-01 22:00:20 -03:00
										 |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  |     cf_conn.create_stack( | 
					
						
							| 
									
										
										
										
											2020-04-01 22:48:40 -03:00
										 |  |  |         StackName="test_stack", TemplateBody=json.dumps(events_template) | 
					
						
							| 
									
										
										
										
											2020-04-01 22:00:20 -03:00
										 |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rules = boto3.client("events", "us-west-2").list_rules() | 
					
						
							|  |  |  |     log_groups = boto3.client("logs", "us-west-2").describe_log_groups() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rules["Rules"][0]["Name"].should.contain("test_stack-Event-") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     log_groups["logGroups"][0]["logGroupName"].should.equal(rules["Rules"][0]["Arn"]) | 
					
						
							|  |  |  |     log_groups["logGroups"][0]["retentionInDays"].should.equal(3) | 
					
						
							| 
									
										
										
										
											2020-05-24 07:21:29 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 02:54:01 -03:00
										 |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_events | 
					
						
							|  |  |  | def test_stack_events_update_rule_integration(): | 
					
						
							|  |  |  |     events_template = Template( | 
					
						
							|  |  |  |         """{
 | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "Event": { | 
					
						
							|  |  |  |                 "Type": "AWS::Events::Rule", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "$Name", | 
					
						
							|  |  |  |                     "State": "$State", | 
					
						
							|  |  |  |                     "ScheduleExpression": "rate(5 minutes)", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } """
 | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     original_template = events_template.substitute(Name="Foo", State="ENABLED") | 
					
						
							|  |  |  |     cf_conn.create_stack(StackName="test_stack", TemplateBody=original_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rules = boto3.client("events", "us-west-2").list_rules() | 
					
						
							|  |  |  |     rules["Rules"].should.have.length_of(1) | 
					
						
							|  |  |  |     rules["Rules"][0]["Name"].should.equal("Foo") | 
					
						
							|  |  |  |     rules["Rules"][0]["State"].should.equal("ENABLED") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     update_template = events_template.substitute(Name="Bar", State="DISABLED") | 
					
						
							|  |  |  |     cf_conn.update_stack(StackName="test_stack", TemplateBody=update_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rules = boto3.client("events", "us-west-2").list_rules() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rules["Rules"].should.have.length_of(1) | 
					
						
							|  |  |  |     rules["Rules"][0]["Name"].should.equal("Bar") | 
					
						
							|  |  |  |     rules["Rules"][0]["State"].should.equal("DISABLED") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 07:21:29 -04:00
										 |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_autoscaling | 
					
						
							|  |  |  | def test_autoscaling_propagate_tags(): | 
					
						
							|  |  |  |     autoscaling_group_with_tags = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "AutoScalingGroup": { | 
					
						
							|  |  |  |                 "Type": "AWS::AutoScaling::AutoScalingGroup", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "AutoScalingGroupName": "test-scaling-group", | 
					
						
							|  |  |  |                     "DesiredCapacity": 1, | 
					
						
							|  |  |  |                     "MinSize": 1, | 
					
						
							|  |  |  |                     "MaxSize": 50, | 
					
						
							|  |  |  |                     "LaunchConfigurationName": "test-launch-config", | 
					
						
							|  |  |  |                     "AvailabilityZones": ["us-east-1a"], | 
					
						
							|  |  |  |                     "Tags": [ | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             "Key": "test-key-propagate", | 
					
						
							|  |  |  |                             "Value": "test", | 
					
						
							|  |  |  |                             "PropagateAtLaunch": True, | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             "Key": "test-key-no-propagate", | 
					
						
							|  |  |  |                             "Value": "test", | 
					
						
							|  |  |  |                             "PropagateAtLaunch": False, | 
					
						
							|  |  |  |                         }, | 
					
						
							|  |  |  |                     ], | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 "DependsOn": "LaunchConfig", | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "LaunchConfig": { | 
					
						
							|  |  |  |                 "Type": "AWS::AutoScaling::LaunchConfiguration", | 
					
						
							| 
									
										
										
										
											2021-01-27 11:49:33 -08:00
										 |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "LaunchConfigurationName": "test-launch-config", | 
					
						
							|  |  |  |                     "ImageId": EXAMPLE_AMI_ID, | 
					
						
							|  |  |  |                     "InstanceType": "t2.medium", | 
					
						
							|  |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2020-05-24 07:21:29 -04:00
										 |  |  |             }, | 
					
						
							| 
									
										
										
										
											2022-07-26 04:07:22 +05:30
										 |  |  |             "ScheduledAction": { | 
					
						
							|  |  |  |                 "Type": "AWS::AutoScaling::ScheduledAction", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "AutoScalingGroupName": "test-scaling-group", | 
					
						
							|  |  |  |                     "DesiredCapacity": 10, | 
					
						
							|  |  |  |                     "EndTime": "2022-08-01T00:00:00Z", | 
					
						
							|  |  |  |                     "MaxSize": 15, | 
					
						
							|  |  |  |                     "MinSize": 5, | 
					
						
							|  |  |  |                     "Recurrence": "* * * * *", | 
					
						
							|  |  |  |                     "StartTime": "2022-07-01T00:00:00Z", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2020-05-24 07:21:29 -04:00
										 |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     boto3.client("cloudformation", "us-east-1").create_stack( | 
					
						
							|  |  |  |         StackName="propagate_tags_test", | 
					
						
							|  |  |  |         TemplateBody=json.dumps(autoscaling_group_with_tags), | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     autoscaling = boto3.client("autoscaling", "us-east-1") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     autoscaling_group_tags = autoscaling.describe_auto_scaling_groups()[ | 
					
						
							|  |  |  |         "AutoScalingGroups" | 
					
						
							|  |  |  |     ][0]["Tags"] | 
					
						
							|  |  |  |     propagation_dict = { | 
					
						
							|  |  |  |         tag["Key"]: tag["PropagateAtLaunch"] for tag in autoscaling_group_tags | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     assert propagation_dict["test-key-propagate"] | 
					
						
							|  |  |  |     assert not propagation_dict["test-key-no-propagate"] | 
					
						
							| 
									
										
										
										
											2020-06-06 07:31:14 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_events | 
					
						
							|  |  |  | def test_stack_eventbus_create_from_cfn_integration(): | 
					
						
							|  |  |  |     eventbus_template = """{
 | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "EventBus": { | 
					
						
							|  |  |  |                 "Type": "AWS::Events::EventBus", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "MyCustomEventBus" | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     }"""
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  |     cf_conn.create_stack(StackName="test_stack", TemplateBody=eventbus_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     event_buses = boto3.client("events", "us-west-2").list_event_buses( | 
					
						
							|  |  |  |         NamePrefix="MyCustom" | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     event_buses["EventBuses"].should.have.length_of(1) | 
					
						
							|  |  |  |     event_buses["EventBuses"][0]["Name"].should.equal("MyCustomEventBus") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_events | 
					
						
							|  |  |  | def test_stack_events_delete_eventbus_integration(): | 
					
						
							|  |  |  |     eventbus_template = """{
 | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "EventBus": { | 
					
						
							|  |  |  |                 "Type": "AWS::Events::EventBus", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "MyCustomEventBus" | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     }"""
 | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  |     cf_conn.create_stack(StackName="test_stack", TemplateBody=eventbus_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     event_buses = boto3.client("events", "us-west-2").list_event_buses( | 
					
						
							|  |  |  |         NamePrefix="MyCustom" | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     event_buses["EventBuses"].should.have.length_of(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn.delete_stack(StackName="test_stack") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     event_buses = boto3.client("events", "us-west-2").list_event_buses( | 
					
						
							|  |  |  |         NamePrefix="MyCustom" | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     event_buses["EventBuses"].should.have.length_of(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_events | 
					
						
							|  |  |  | def test_stack_events_delete_from_cfn_integration(): | 
					
						
							|  |  |  |     eventbus_template = Template( | 
					
						
							|  |  |  |         """{
 | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "$resource_name": { | 
					
						
							|  |  |  |                 "Type": "AWS::Events::EventBus", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "$name" | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     }"""
 | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     original_template = eventbus_template.substitute( | 
					
						
							|  |  |  |         {"resource_name": "original", "name": "MyCustomEventBus"} | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     cf_conn.create_stack(StackName="test_stack", TemplateBody=original_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     original_event_buses = boto3.client("events", "us-west-2").list_event_buses( | 
					
						
							|  |  |  |         NamePrefix="MyCustom" | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     original_event_buses["EventBuses"].should.have.length_of(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     original_eventbus = original_event_buses["EventBuses"][0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     updated_template = eventbus_template.substitute( | 
					
						
							|  |  |  |         {"resource_name": "updated", "name": "AnotherEventBus"} | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     cf_conn.update_stack(StackName="test_stack", TemplateBody=updated_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     update_event_buses = boto3.client("events", "us-west-2").list_event_buses( | 
					
						
							|  |  |  |         NamePrefix="AnotherEventBus" | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     update_event_buses["EventBuses"].should.have.length_of(1) | 
					
						
							|  |  |  |     update_event_buses["EventBuses"][0]["Arn"].shouldnt.equal(original_eventbus["Arn"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_events | 
					
						
							|  |  |  | def test_stack_events_update_from_cfn_integration(): | 
					
						
							|  |  |  |     eventbus_template = Template( | 
					
						
							|  |  |  |         """{
 | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "EventBus": { | 
					
						
							|  |  |  |                 "Type": "AWS::Events::EventBus", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "$name" | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     }"""
 | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf_conn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     original_template = eventbus_template.substitute({"name": "MyCustomEventBus"}) | 
					
						
							|  |  |  |     cf_conn.create_stack(StackName="test_stack", TemplateBody=original_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     original_event_buses = boto3.client("events", "us-west-2").list_event_buses( | 
					
						
							|  |  |  |         NamePrefix="MyCustom" | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     original_event_buses["EventBuses"].should.have.length_of(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     original_eventbus = original_event_buses["EventBuses"][0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     updated_template = eventbus_template.substitute({"name": "NewEventBus"}) | 
					
						
							|  |  |  |     cf_conn.update_stack(StackName="test_stack", TemplateBody=updated_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     update_event_buses = boto3.client("events", "us-west-2").list_event_buses( | 
					
						
							|  |  |  |         NamePrefix="NewEventBus" | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     update_event_buses["EventBuses"].should.have.length_of(1) | 
					
						
							|  |  |  |     update_event_buses["EventBuses"][0]["Name"].should.equal("NewEventBus") | 
					
						
							|  |  |  |     update_event_buses["EventBuses"][0]["Arn"].shouldnt.equal(original_eventbus["Arn"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_events | 
					
						
							|  |  |  | def test_stack_events_get_attribute_integration(): | 
					
						
							|  |  |  |     eventbus_template = """{
 | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "EventBus": { | 
					
						
							|  |  |  |                 "Type": "AWS::Events::EventBus", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "MyEventBus" | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "Outputs": { | 
					
						
							|  |  |  |             "bus_arn": {"Value": {"Fn::GetAtt": ["EventBus", "Arn"]}}, | 
					
						
							|  |  |  |             "bus_name": {"Value": {"Fn::GetAtt": ["EventBus", "Name"]}}, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }"""
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  |     events = boto3.client("events", "us-west-2") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cf.create_stack(StackName="test_stack", TemplateBody=eventbus_template) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     stack = cf.describe_stacks(StackName="test_stack")["Stacks"][0] | 
					
						
							|  |  |  |     outputs = stack["Outputs"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     output_arn = list(filter(lambda item: item["OutputKey"] == "bus_arn", outputs))[0] | 
					
						
							|  |  |  |     output_name = list(filter(lambda item: item["OutputKey"] == "bus_name", outputs))[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     event_bus = events.list_event_buses(NamePrefix="MyEventBus")["EventBuses"][0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     output_arn["OutputValue"].should.equal(event_bus["Arn"]) | 
					
						
							|  |  |  |     output_name["OutputValue"].should.equal(event_bus["Name"]) | 
					
						
							| 
									
										
										
										
											2020-07-11 09:46:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							| 
									
										
										
										
											2022-03-11 21:29:16 -01:00
										 |  |  | @mock_dynamodb | 
					
						
							| 
									
										
										
										
											2020-07-11 09:46:03 +01:00
										 |  |  | def test_dynamodb_table_creation(): | 
					
						
							|  |  |  |     CFN_TEMPLATE = { | 
					
						
							|  |  |  |         "Outputs": {"MyTableName": {"Value": {"Ref": "MyTable"}}}, | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "MyTable": { | 
					
						
							|  |  |  |                 "Type": "AWS::DynamoDB::Table", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "KeySchema": [{"AttributeName": "id", "KeyType": "HASH"}], | 
					
						
							|  |  |  |                     "AttributeDefinitions": [ | 
					
						
							|  |  |  |                         {"AttributeName": "id", "AttributeType": "S"} | 
					
						
							|  |  |  |                     ], | 
					
						
							|  |  |  |                     "BillingMode": "PAY_PER_REQUEST", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     stack_name = "foobar" | 
					
						
							|  |  |  |     cfn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  |     cfn.create_stack(StackName=stack_name, TemplateBody=json.dumps(CFN_TEMPLATE)) | 
					
						
							|  |  |  |     # Wait until moto creates the stack | 
					
						
							|  |  |  |     waiter = cfn.get_waiter("stack_create_complete") | 
					
						
							|  |  |  |     waiter.wait(StackName=stack_name) | 
					
						
							|  |  |  |     # Verify the TableName is part of the outputs | 
					
						
							|  |  |  |     stack = cfn.describe_stacks(StackName=stack_name)["Stacks"][0] | 
					
						
							|  |  |  |     outputs = stack["Outputs"] | 
					
						
							|  |  |  |     outputs.should.have.length_of(1) | 
					
						
							|  |  |  |     outputs[0]["OutputKey"].should.equal("MyTableName") | 
					
						
							|  |  |  |     outputs[0]["OutputValue"].should.contain("foobar") | 
					
						
							|  |  |  |     # Assert the table is created | 
					
						
							|  |  |  |     ddb = boto3.client("dynamodb", "us-west-2") | 
					
						
							|  |  |  |     table_names = ddb.list_tables()["TableNames"] | 
					
						
							|  |  |  |     table_names.should.equal([outputs[0]["OutputValue"]]) | 
					
						
							| 
									
										
										
										
											2022-11-05 18:06:12 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_ssm | 
					
						
							|  |  |  | def test_ssm_parameter(): | 
					
						
							|  |  |  |     parameter_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "BasicParameter": { | 
					
						
							|  |  |  |                 "Type": "AWS::SSM::Parameter", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "test_ssm", | 
					
						
							|  |  |  |                     "Type": "String", | 
					
						
							|  |  |  |                     "Value": "Test SSM Parameter", | 
					
						
							|  |  |  |                     "Description": "Test SSM Description", | 
					
						
							|  |  |  |                     "AllowedPattern": "^[a-zA-Z]{1,10}$", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     stack_name = "test_stack" | 
					
						
							|  |  |  |     cfn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  |     cfn.create_stack(StackName=stack_name, TemplateBody=json.dumps(parameter_template)) | 
					
						
							|  |  |  |     # Wait until moto creates the stack | 
					
						
							|  |  |  |     waiter = cfn.get_waiter("stack_create_complete") | 
					
						
							|  |  |  |     waiter.wait(StackName=stack_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ssm_client = boto3.client("ssm", region_name="us-west-2") | 
					
						
							|  |  |  |     parameters = ssm_client.get_parameters(Names=["test_ssm"], WithDecryption=False)[ | 
					
						
							|  |  |  |         "Parameters" | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  |     parameters.should.have.length_of(1) | 
					
						
							|  |  |  |     parameters[0]["Name"].should.equal("test_ssm") | 
					
						
							|  |  |  |     parameters[0]["Value"].should.equal("Test SSM Parameter") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_ssm | 
					
						
							|  |  |  | def test_ssm_parameter_update_stack(): | 
					
						
							|  |  |  |     parameter_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "BasicParameter": { | 
					
						
							|  |  |  |                 "Type": "AWS::SSM::Parameter", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "test_ssm", | 
					
						
							|  |  |  |                     "Type": "String", | 
					
						
							|  |  |  |                     "Value": "Test SSM Parameter", | 
					
						
							|  |  |  |                     "Description": "Test SSM Description", | 
					
						
							|  |  |  |                     "AllowedPattern": "^[a-zA-Z]{1,10}$", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     stack_name = "test_stack" | 
					
						
							|  |  |  |     cfn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  |     cfn.create_stack(StackName=stack_name, TemplateBody=json.dumps(parameter_template)) | 
					
						
							|  |  |  |     # Wait until moto creates the stack | 
					
						
							|  |  |  |     waiter = cfn.get_waiter("stack_create_complete") | 
					
						
							|  |  |  |     waiter.wait(StackName=stack_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ssm_client = boto3.client("ssm", region_name="us-west-2") | 
					
						
							|  |  |  |     parameters = ssm_client.get_parameters(Names=["test_ssm"], WithDecryption=False)[ | 
					
						
							|  |  |  |         "Parameters" | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  |     parameters.should.have.length_of(1) | 
					
						
							|  |  |  |     parameters[0]["Name"].should.equal("test_ssm") | 
					
						
							|  |  |  |     parameters[0]["Value"].should.equal("Test SSM Parameter") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parameter_template["Resources"]["BasicParameter"]["Properties"][ | 
					
						
							|  |  |  |         "Value" | 
					
						
							|  |  |  |     ] = "Test SSM Parameter Updated" | 
					
						
							|  |  |  |     cfn.update_stack(StackName=stack_name, TemplateBody=json.dumps(parameter_template)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ssm_client = boto3.client("ssm", region_name="us-west-2") | 
					
						
							|  |  |  |     parameters = ssm_client.get_parameters(Names=["test_ssm"], WithDecryption=False)[ | 
					
						
							|  |  |  |         "Parameters" | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  |     parameters.should.have.length_of(1) | 
					
						
							|  |  |  |     parameters[0]["Name"].should.equal("test_ssm") | 
					
						
							|  |  |  |     parameters[0]["Value"].should.equal("Test SSM Parameter Updated") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_ssm | 
					
						
							|  |  |  | def test_ssm_parameter_update_stack_and_remove_resource(): | 
					
						
							|  |  |  |     parameter_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "BasicParameter": { | 
					
						
							|  |  |  |                 "Type": "AWS::SSM::Parameter", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "test_ssm", | 
					
						
							|  |  |  |                     "Type": "String", | 
					
						
							|  |  |  |                     "Value": "Test SSM Parameter", | 
					
						
							|  |  |  |                     "Description": "Test SSM Description", | 
					
						
							|  |  |  |                     "AllowedPattern": "^[a-zA-Z]{1,10}$", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     stack_name = "test_stack" | 
					
						
							|  |  |  |     cfn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  |     cfn.create_stack(StackName=stack_name, TemplateBody=json.dumps(parameter_template)) | 
					
						
							|  |  |  |     # Wait until moto creates the stack | 
					
						
							|  |  |  |     waiter = cfn.get_waiter("stack_create_complete") | 
					
						
							|  |  |  |     waiter.wait(StackName=stack_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ssm_client = boto3.client("ssm", region_name="us-west-2") | 
					
						
							|  |  |  |     parameters = ssm_client.get_parameters(Names=["test_ssm"], WithDecryption=False)[ | 
					
						
							|  |  |  |         "Parameters" | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  |     parameters.should.have.length_of(1) | 
					
						
							|  |  |  |     parameters[0]["Name"].should.equal("test_ssm") | 
					
						
							|  |  |  |     parameters[0]["Value"].should.equal("Test SSM Parameter") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parameter_template["Resources"].pop("BasicParameter") | 
					
						
							|  |  |  |     cfn.update_stack(StackName=stack_name, TemplateBody=json.dumps(parameter_template)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ssm_client = boto3.client("ssm", region_name="us-west-1") | 
					
						
							|  |  |  |     parameters = ssm_client.get_parameters(Names=["test_ssm"], WithDecryption=False)[ | 
					
						
							|  |  |  |         "Parameters" | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  |     parameters.should.have.length_of(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | @mock_ssm | 
					
						
							|  |  |  | def test_ssm_parameter_update_stack_and_add_resource(): | 
					
						
							|  |  |  |     parameter_template = {"AWSTemplateFormatVersion": "2010-09-09", "Resources": {}} | 
					
						
							|  |  |  |     stack_name = "test_stack" | 
					
						
							|  |  |  |     cfn = boto3.client("cloudformation", "us-west-2") | 
					
						
							|  |  |  |     cfn.create_stack(StackName=stack_name, TemplateBody=json.dumps(parameter_template)) | 
					
						
							|  |  |  |     # Wait until moto creates the stack | 
					
						
							|  |  |  |     waiter = cfn.get_waiter("stack_create_complete") | 
					
						
							|  |  |  |     waiter.wait(StackName=stack_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ssm_client = boto3.client("ssm", region_name="us-west-2") | 
					
						
							|  |  |  |     parameters = ssm_client.get_parameters(Names=["test_ssm"], WithDecryption=False)[ | 
					
						
							|  |  |  |         "Parameters" | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  |     parameters.should.have.length_of(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parameter_template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "BasicParameter": { | 
					
						
							|  |  |  |                 "Type": "AWS::SSM::Parameter", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "Name": "test_ssm", | 
					
						
							|  |  |  |                     "Type": "String", | 
					
						
							|  |  |  |                     "Value": "Test SSM Parameter", | 
					
						
							|  |  |  |                     "Description": "Test SSM Description", | 
					
						
							|  |  |  |                     "AllowedPattern": "^[a-zA-Z]{1,10}$", | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     cfn.update_stack(StackName=stack_name, TemplateBody=json.dumps(parameter_template)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ssm_client = boto3.client("ssm", region_name="us-west-2") | 
					
						
							|  |  |  |     parameters = ssm_client.get_parameters(Names=["test_ssm"], WithDecryption=False)[ | 
					
						
							|  |  |  |         "Parameters" | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  |     parameters.should.have.length_of(1) | 
					
						
							|  |  |  |     parameters[0]["Name"].should.equal("test_ssm") | 
					
						
							|  |  |  |     parameters[0]["Value"].should.equal("Test SSM Parameter") |