diff --git a/moto/s3/models.py b/moto/s3/models.py index c0c5512dd..17282739a 100644 --- a/moto/s3/models.py +++ b/moto/s3/models.py @@ -66,7 +66,7 @@ OWNER = "75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a" def get_moto_s3_account_id(): """This makes it easy for mocking AWS Account IDs when using AWS Config - -- Simply mock.patch the ACCOUNT_ID here, and Config gets it for free. + -- Simply mock.patch the ACCOUNT_ID here, and Config gets it for free. """ return ACCOUNT_ID @@ -1061,12 +1061,16 @@ class FakeBucket(CloudFormationModel): def get_cfn_attribute(self, attribute_name): from moto.cloudformation.exceptions import UnformattedGetAttTemplateException - if attribute_name == "DomainName": - raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "DomainName" ]"') - elif attribute_name == "WebsiteURL": - raise NotImplementedError('"Fn::GetAtt" : [ "{0}" , "WebsiteURL" ]"') - elif attribute_name == "Arn": + if attribute_name == "Arn": return self.arn + elif attribute_name == "DomainName": + return self.domain_name + elif attribute_name == "DualStackDomainName": + return self.dual_stack_domain_name + elif attribute_name == "RegionalDomainName": + return self.regional_domain_name + elif attribute_name == "WebsiteURL": + return self.website_url raise UnformattedGetAttTemplateException() def set_acl(self, acl): @@ -1076,6 +1080,24 @@ class FakeBucket(CloudFormationModel): def arn(self): return "arn:aws:s3:::{}".format(self.name) + @property + def domain_name(self): + return "{}.s3.amazonaws.com".format(self.name) + + @property + def dual_stack_domain_name(self): + return "{}.s3.dualstack.{}.amazonaws.com".format(self.name, self.region_name) + + @property + def regional_domain_name(self): + return "{}.s3.{}.amazonaws.com".format(self.name, self.region_name) + + @property + def website_url(self): + return "http://{}.s3-website.{}.amazonaws.com".format( + self.name, self.region_name + ) + @property def physical_resource_id(self): return self.name diff --git a/tests/test_s3/test_s3_cloudformation.py b/tests/test_s3/test_s3_cloudformation.py index e3803aa2c..ebaa03b78 100644 --- a/tests/test_s3/test_s3_cloudformation.py +++ b/tests/test_s3/test_s3_cloudformation.py @@ -148,8 +148,9 @@ def test_s3_bucket_cloudformation_update_replacement(): @mock_s3 @mock_cloudformation def test_s3_bucket_cloudformation_outputs(): - s3 = boto3.client("s3", region_name="us-east-1") - cf = boto3.resource("cloudformation", region_name="us-east-1") + region_name = "us-east-1" + s3 = boto3.client("s3", region_name=region_name) + cf = boto3.resource("cloudformation", region_name=region_name) stack_name = "test-stack" bucket_name = "test-bucket" template = { @@ -165,6 +166,26 @@ def test_s3_bucket_cloudformation_outputs(): "Value": {"Fn::GetAtt": ["TestBucket", "Arn"]}, "Export": {"Name": {"Fn::Sub": "${AWS::StackName}:BucketARN"}}, }, + "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"}}, + }, "BucketName": { "Value": {"Ref": "TestBucket"}, "Export": {"Name": {"Fn::Sub": "${AWS::StackName}:BucketName"}}, @@ -176,4 +197,22 @@ def test_s3_bucket_cloudformation_outputs(): output = {item["OutputKey"]: item["OutputValue"] for item in outputs_list} s3.head_bucket(Bucket=output["BucketName"]) output["BucketARN"].should.match("arn:aws:s3.+{bucket}".format(bucket=bucket_name)) + output["BucketDomainName"].should.equal( + "{bucket}.s3.amazonaws.com".format(bucket=bucket_name) + ) + output["BucketDualStackDomainName"].should.equal( + "{bucket}.s3.dualstack.{region}.amazonaws.com".format( + bucket=bucket_name, region=region_name + ) + ) + output["BucketRegionalDomainName"].should.equal( + "{bucket}.s3.{region}.amazonaws.com".format( + bucket=bucket_name, region=region_name + ) + ) + output["BucketWebsiteURL"].should.equal( + "http://{bucket}.s3-website.{region}.amazonaws.com".format( + bucket=bucket_name, region=region_name + ) + ) output["BucketName"].should.equal(bucket_name)