| 
									
										
										
										
											2020-08-27 05:11:47 -04:00
										 |  |  | import json | 
					
						
							|  |  |  | import boto3 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-11 20:28:45 -01:00
										 |  |  | import sure  # noqa # pylint: disable=unused-import | 
					
						
							| 
									
										
										
										
											2020-08-27 05:11:47 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | from moto import mock_s3, mock_cloudformation | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_s3 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | def test_s3_bucket_cloudformation_basic(): | 
					
						
							|  |  |  |     s3 = boto3.client("s3", region_name="us-east-1") | 
					
						
							|  |  |  |     cf = boto3.client("cloudformation", region_name="us-east-1") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							| 
									
										
										
										
											2022-03-10 13:39:59 -01:00
										 |  |  |         "Resources": {"testInstance": {"Type": "AWS::S3::Bucket", "Properties": {}}}, | 
					
						
							| 
									
										
										
										
											2020-08-27 05:11:47 -04:00
										 |  |  |         "Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}}, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     template_json = json.dumps(template) | 
					
						
							| 
									
										
										
										
											2021-10-18 19:44:29 +00:00
										 |  |  |     cf.create_stack(StackName="test_stack", TemplateBody=template_json) | 
					
						
							| 
									
										
										
										
											2020-08-27 05:11:47 -04:00
										 |  |  |     stack_description = cf.describe_stacks(StackName="test_stack")["Stacks"][0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     s3.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_s3 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | def test_s3_bucket_cloudformation_with_properties(): | 
					
						
							|  |  |  |     s3 = boto3.client("s3", region_name="us-east-1") | 
					
						
							|  |  |  |     cf = boto3.client("cloudformation", region_name="us-east-1") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bucket_name = "MyBucket" | 
					
						
							|  |  |  |     template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "testInstance": { | 
					
						
							|  |  |  |                 "Type": "AWS::S3::Bucket", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "BucketName": bucket_name, | 
					
						
							|  |  |  |                     "BucketEncryption": { | 
					
						
							|  |  |  |                         "ServerSideEncryptionConfiguration": [ | 
					
						
							|  |  |  |                             { | 
					
						
							|  |  |  |                                 "ServerSideEncryptionByDefault": { | 
					
						
							|  |  |  |                                     "SSEAlgorithm": "AES256" | 
					
						
							|  |  |  |                                 } | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         ] | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}}, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     template_json = json.dumps(template) | 
					
						
							| 
									
										
										
										
											2021-10-18 19:44:29 +00:00
										 |  |  |     cf.create_stack(StackName="test_stack", TemplateBody=template_json) | 
					
						
							|  |  |  |     cf.describe_stacks(StackName="test_stack") | 
					
						
							| 
									
										
										
										
											2020-08-27 05:11:47 -04:00
										 |  |  |     s3.head_bucket(Bucket=bucket_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     encryption = s3.get_bucket_encryption(Bucket=bucket_name) | 
					
						
							|  |  |  |     encryption["ServerSideEncryptionConfiguration"]["Rules"][0][ | 
					
						
							|  |  |  |         "ApplyServerSideEncryptionByDefault" | 
					
						
							|  |  |  |     ]["SSEAlgorithm"].should.equal("AES256") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_s3 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | def test_s3_bucket_cloudformation_update_no_interruption(): | 
					
						
							|  |  |  |     s3 = boto3.client("s3", region_name="us-east-1") | 
					
						
							|  |  |  |     cf = boto3.client("cloudformation", region_name="us-east-1") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": {"testInstance": {"Type": "AWS::S3::Bucket"}}, | 
					
						
							|  |  |  |         "Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}}, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     template_json = json.dumps(template) | 
					
						
							|  |  |  |     cf.create_stack(StackName="test_stack", TemplateBody=template_json) | 
					
						
							|  |  |  |     stack_description = cf.describe_stacks(StackName="test_stack")["Stacks"][0] | 
					
						
							|  |  |  |     s3.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "testInstance": { | 
					
						
							|  |  |  |                 "Type": "AWS::S3::Bucket", | 
					
						
							|  |  |  |                 "Properties": { | 
					
						
							|  |  |  |                     "BucketEncryption": { | 
					
						
							|  |  |  |                         "ServerSideEncryptionConfiguration": [ | 
					
						
							|  |  |  |                             { | 
					
						
							|  |  |  |                                 "ServerSideEncryptionByDefault": { | 
					
						
							|  |  |  |                                     "SSEAlgorithm": "AES256" | 
					
						
							|  |  |  |                                 } | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         ] | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}}, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     template_json = json.dumps(template) | 
					
						
							|  |  |  |     cf.update_stack(StackName="test_stack", TemplateBody=template_json) | 
					
						
							|  |  |  |     encryption = s3.get_bucket_encryption( | 
					
						
							|  |  |  |         Bucket=stack_description["Outputs"][0]["OutputValue"] | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     encryption["ServerSideEncryptionConfiguration"]["Rules"][0][ | 
					
						
							|  |  |  |         "ApplyServerSideEncryptionByDefault" | 
					
						
							|  |  |  |     ]["SSEAlgorithm"].should.equal("AES256") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_s3 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | def test_s3_bucket_cloudformation_update_replacement(): | 
					
						
							|  |  |  |     s3 = boto3.client("s3", region_name="us-east-1") | 
					
						
							|  |  |  |     cf = boto3.client("cloudformation", region_name="us-east-1") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": {"testInstance": {"Type": "AWS::S3::Bucket"}}, | 
					
						
							|  |  |  |         "Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}}, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     template_json = json.dumps(template) | 
					
						
							|  |  |  |     cf.create_stack(StackName="test_stack", TemplateBody=template_json) | 
					
						
							|  |  |  |     stack_description = cf.describe_stacks(StackName="test_stack")["Stacks"][0] | 
					
						
							|  |  |  |     s3.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "testInstance": { | 
					
						
							|  |  |  |                 "Type": "AWS::S3::Bucket", | 
					
						
							|  |  |  |                 "Properties": {"BucketName": "MyNewBucketName"}, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}}, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     template_json = json.dumps(template) | 
					
						
							|  |  |  |     cf.update_stack(StackName="test_stack", TemplateBody=template_json) | 
					
						
							|  |  |  |     stack_description = cf.describe_stacks(StackName="test_stack")["Stacks"][0] | 
					
						
							|  |  |  |     s3.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"]) | 
					
						
							| 
									
										
										
										
											2020-10-16 03:29:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @mock_s3 | 
					
						
							|  |  |  | @mock_cloudformation | 
					
						
							|  |  |  | def test_s3_bucket_cloudformation_outputs(): | 
					
						
							| 
									
										
										
										
											2020-10-27 09:04:32 -07:00
										 |  |  |     region_name = "us-east-1" | 
					
						
							|  |  |  |     s3 = boto3.client("s3", region_name=region_name) | 
					
						
							|  |  |  |     cf = boto3.resource("cloudformation", region_name=region_name) | 
					
						
							| 
									
										
										
										
											2020-10-16 03:29:26 -07:00
										 |  |  |     stack_name = "test-stack" | 
					
						
							|  |  |  |     bucket_name = "test-bucket" | 
					
						
							|  |  |  |     template = { | 
					
						
							|  |  |  |         "AWSTemplateFormatVersion": "2010-09-09", | 
					
						
							|  |  |  |         "Resources": { | 
					
						
							|  |  |  |             "TestBucket": { | 
					
						
							|  |  |  |                 "Type": "AWS::S3::Bucket", | 
					
						
							|  |  |  |                 "Properties": {"BucketName": bucket_name}, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         "Outputs": { | 
					
						
							|  |  |  |             "BucketARN": { | 
					
						
							|  |  |  |                 "Value": {"Fn::GetAtt": ["TestBucket", "Arn"]}, | 
					
						
							|  |  |  |                 "Export": {"Name": {"Fn::Sub": "${AWS::StackName}:BucketARN"}}, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2020-10-27 09:04:32 -07:00
										 |  |  |             "BucketDomainName": { | 
					
						
							|  |  |  |                 "Value": {"Fn::GetAtt": ["TestBucket", "DomainName"]}, | 
					
						
							|  |  |  |                 "Export": {"Name": {"Fn::Sub": "${AWS::StackName}:BucketDomainName"}}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "BucketDualStackDomainName": { | 
					
						
							|  |  |  |                 "Value": {"Fn::GetAtt": ["TestBucket", "DualStackDomainName"]}, | 
					
						
							|  |  |  |                 "Export": { | 
					
						
							|  |  |  |                     "Name": {"Fn::Sub": "${AWS::StackName}:BucketDualStackDomainName"} | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "BucketRegionalDomainName": { | 
					
						
							|  |  |  |                 "Value": {"Fn::GetAtt": ["TestBucket", "RegionalDomainName"]}, | 
					
						
							|  |  |  |                 "Export": { | 
					
						
							|  |  |  |                     "Name": {"Fn::Sub": "${AWS::StackName}:BucketRegionalDomainName"} | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             "BucketWebsiteURL": { | 
					
						
							|  |  |  |                 "Value": {"Fn::GetAtt": ["TestBucket", "WebsiteURL"]}, | 
					
						
							|  |  |  |                 "Export": {"Name": {"Fn::Sub": "${AWS::StackName}:BucketWebsiteURL"}}, | 
					
						
							|  |  |  |             }, | 
					
						
							| 
									
										
										
										
											2020-10-16 03:29:26 -07:00
										 |  |  |             "BucketName": { | 
					
						
							|  |  |  |                 "Value": {"Ref": "TestBucket"}, | 
					
						
							|  |  |  |                 "Export": {"Name": {"Fn::Sub": "${AWS::StackName}:BucketName"}}, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     cf.create_stack(StackName=stack_name, TemplateBody=json.dumps(template)) | 
					
						
							|  |  |  |     outputs_list = cf.Stack(stack_name).outputs | 
					
						
							|  |  |  |     output = {item["OutputKey"]: item["OutputValue"] for item in outputs_list} | 
					
						
							|  |  |  |     s3.head_bucket(Bucket=output["BucketName"]) | 
					
						
							| 
									
										
										
										
											2022-11-17 21:41:08 -01:00
										 |  |  |     output["BucketARN"].should.match(f"arn:aws:s3.+{bucket_name}") | 
					
						
							|  |  |  |     output["BucketDomainName"].should.equal(f"{bucket_name}.s3.amazonaws.com") | 
					
						
							| 
									
										
										
										
											2020-10-27 09:04:32 -07:00
										 |  |  |     output["BucketDualStackDomainName"].should.equal( | 
					
						
							| 
									
										
										
										
											2022-11-17 21:41:08 -01:00
										 |  |  |         f"{bucket_name}.s3.dualstack.{region_name}.amazonaws.com" | 
					
						
							| 
									
										
										
										
											2020-10-27 09:04:32 -07:00
										 |  |  |     ) | 
					
						
							|  |  |  |     output["BucketRegionalDomainName"].should.equal( | 
					
						
							| 
									
										
										
										
											2022-11-17 21:41:08 -01:00
										 |  |  |         f"{bucket_name}.s3.{region_name}.amazonaws.com" | 
					
						
							| 
									
										
										
										
											2020-10-27 09:04:32 -07:00
										 |  |  |     ) | 
					
						
							|  |  |  |     output["BucketWebsiteURL"].should.equal( | 
					
						
							| 
									
										
										
										
											2022-11-17 21:41:08 -01:00
										 |  |  |         f"http://{bucket_name}.s3-website.{region_name}.amazonaws.com" | 
					
						
							| 
									
										
										
										
											2020-10-27 09:04:32 -07:00
										 |  |  |     ) | 
					
						
							| 
									
										
										
										
											2020-10-16 03:29:26 -07:00
										 |  |  |     output["BucketName"].should.equal(bucket_name) |