import time from datetime import datetime import boto3 import sure # noqa from botocore.exceptions import ClientError import pytest from moto import mock_ram, mock_organizations from moto.core import ACCOUNT_ID @mock_ram def test_create_resource_share(): # given client = boto3.client("ram", region_name="us-east-1") # when response = client.create_resource_share(name="test") # then resource = response["resourceShare"] resource["allowExternalPrincipals"].should.be.ok resource["creationTime"].should.be.a(datetime) resource["lastUpdatedTime"].should.be.a(datetime) resource["name"].should.equal("test") resource["owningAccountId"].should.equal(ACCOUNT_ID) resource["resourceShareArn"].should.match( r"arn:aws:ram:us-east-1:\d{12}:resource-share/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" ) resource["status"].should.equal("ACTIVE") resource.should_not.have.key("featureSet") # creating a resource share with the name should result in a second one # not overwrite/update the old one # when response = client.create_resource_share( name="test", allowExternalPrincipals=False, resourceArns=[ "arn:aws:ec2:us-east-1:{}:transit-gateway/tgw-123456789".format(ACCOUNT_ID) ], ) # then resource = response["resourceShare"] resource["allowExternalPrincipals"].should_not.be.ok resource["creationTime"].should.be.a(datetime) resource["lastUpdatedTime"].should.be.a(datetime) resource["name"].should.equal("test") resource["owningAccountId"].should.equal(ACCOUNT_ID) resource["resourceShareArn"].should.match( r"arn:aws:ram:us-east-1:\d{12}:resource-share/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" ) resource["status"].should.equal("ACTIVE") response = client.get_resource_shares(resourceOwner="SELF") response["resourceShares"].should.have.length_of(2) @mock_ram def test_create_resource_share_errors(): # given client = boto3.client("ram", region_name="us-east-1") # invalid ARN # when with pytest.raises(ClientError) as e: client.create_resource_share(name="test", resourceArns=["inalid-arn"]) ex = e.value ex.operation_name.should.equal("CreateResourceShare") ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) ex.response["Error"]["Code"].should.contain("MalformedArnException") ex.response["Error"]["Message"].should.equal( "The specified resource ARN inalid-arn is not valid. " "Verify the ARN and try again." ) # valid ARN, but not shareable resource type # when with pytest.raises(ClientError) as e: client.create_resource_share( name="test", resourceArns=["arn:aws:iam::{}:role/test".format(ACCOUNT_ID)] ) ex = e.value ex.operation_name.should.equal("CreateResourceShare") ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) ex.response["Error"]["Code"].should.contain("MalformedArnException") ex.response["Error"]["Message"].should.equal( "You cannot share the selected resource type." ) # invalid principal ID # when with pytest.raises(ClientError) as e: client.create_resource_share( name="test", principals=["invalid"], resourceArns=[ "arn:aws:ec2:us-east-1:{}:transit-gateway/tgw-123456789".format( ACCOUNT_ID ) ], ) ex = e.value ex.operation_name.should.equal("CreateResourceShare") ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) ex.response["Error"]["Code"].should.contain("InvalidParameterException") ex.response["Error"]["Message"].should.equal( "Principal ID invalid is malformed. Verify the ID and try again." ) @mock_ram @mock_organizations def test_create_resource_share_with_organization(): # given client = boto3.client("organizations", region_name="us-east-1") org_arn = client.create_organization(FeatureSet="ALL")["Organization"]["Arn"] root_id = client.list_roots()["Roots"][0]["Id"] ou_arn = client.create_organizational_unit(ParentId=root_id, Name="test")[ "OrganizationalUnit" ]["Arn"] client = boto3.client("ram", region_name="us-east-1") # share in whole Organization # when response = client.create_resource_share( name="test", principals=[org_arn], resourceArns=[ "arn:aws:ec2:us-east-1:{}:transit-gateway/tgw-123456789".format(ACCOUNT_ID) ], ) # then response["resourceShare"]["name"].should.equal("test") # share in an OU # when response = client.create_resource_share( name="test", principals=[ou_arn], resourceArns=[ "arn:aws:ec2:us-east-1:{}:transit-gateway/tgw-123456789".format(ACCOUNT_ID) ], ) # then response["resourceShare"]["name"].should.equal("test") @mock_ram @mock_organizations def test_create_resource_share_with_organization_errors(): # given client = boto3.client("organizations", region_name="us-east-1") client.create_organization(FeatureSet="ALL") root_id = client.list_roots()["Roots"][0]["Id"] client.create_organizational_unit(ParentId=root_id, Name="test") client = boto3.client("ram", region_name="us-east-1") # unknown Organization # when with pytest.raises(ClientError) as e: client.create_resource_share( name="test", principals=[ "arn:aws:organizations::{}:organization/o-unknown".format(ACCOUNT_ID) ], resourceArns=[ "arn:aws:ec2:us-east-1:{}:transit-gateway/tgw-123456789".format( ACCOUNT_ID ) ], ) ex = e.value ex.operation_name.should.equal("CreateResourceShare") ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) ex.response["Error"]["Code"].should.contain("UnknownResourceException") ex.response["Error"]["Message"].should.equal( "Organization o-unknown could not be found." ) # unknown OU # when with pytest.raises(ClientError) as e: client.create_resource_share( name="test", principals=[ "arn:aws:organizations::{}:ou/o-unknown/ou-unknown".format(ACCOUNT_ID) ], resourceArns=[ "arn:aws:ec2:us-east-1:{}:transit-gateway/tgw-123456789".format( ACCOUNT_ID ) ], ) ex = e.value ex.operation_name.should.equal("CreateResourceShare") ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) ex.response["Error"]["Code"].should.contain("UnknownResourceException") ex.response["Error"]["Message"].should.equal( "OrganizationalUnit ou-unknown in unknown organization could not be found." ) @mock_ram def test_get_resource_shares(): # given client = boto3.client("ram", region_name="us-east-1") client.create_resource_share(name="test") # when response = client.get_resource_shares(resourceOwner="SELF") # then response["resourceShares"].should.have.length_of(1) resource = response["resourceShares"][0] resource["allowExternalPrincipals"].should.be.ok resource["creationTime"].should.be.a(datetime) resource["featureSet"].should.equal("STANDARD") resource["lastUpdatedTime"].should.be.a(datetime) resource["name"].should.equal("test") resource["owningAccountId"].should.equal(ACCOUNT_ID) resource["resourceShareArn"].should.match( r"arn:aws:ram:us-east-1:\d{12}:resource-share/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" ) resource["status"].should.equal("ACTIVE") @mock_ram def test_get_resource_shares_errors(): # given client = boto3.client("ram", region_name="us-east-1") # invalid resource owner # when with pytest.raises(ClientError) as e: client.get_resource_shares(resourceOwner="invalid") ex = e.value ex.operation_name.should.equal("GetResourceShares") ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) ex.response["Error"]["Code"].should.contain("InvalidParameterException") ex.response["Error"]["Message"].should.equal( "invalid is not a valid resource owner. " "Specify either SELF or OTHER-ACCOUNTS and try again." ) @mock_ram def test_update_resource_share(): # given client = boto3.client("ram", region_name="us-east-1") arn = client.create_resource_share(name="test")["resourceShare"]["resourceShareArn"] # when time.sleep(0.1) response = client.update_resource_share(resourceShareArn=arn, name="test-update") # then resource = response["resourceShare"] resource["allowExternalPrincipals"].should.be.ok resource["name"].should.equal("test-update") resource["owningAccountId"].should.equal(ACCOUNT_ID) resource["resourceShareArn"].should.match( r"arn:aws:ram:us-east-1:\d{12}:resource-share/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" ) resource["status"].should.equal("ACTIVE") resource.should_not.have.key("featureSet") creation_time = resource["creationTime"] resource["lastUpdatedTime"].should.be.greater_than(creation_time) response = client.get_resource_shares(resourceOwner="SELF") response["resourceShares"].should.have.length_of(1) @mock_ram def test_update_resource_share_errors(): # given client = boto3.client("ram", region_name="us-east-1") # invalid resource owner # when with pytest.raises(ClientError) as e: client.update_resource_share( resourceShareArn="arn:aws:ram:us-east-1:{}:resource-share/not-existing".format( ACCOUNT_ID ), name="test-update", ) ex = e.value ex.operation_name.should.equal("UpdateResourceShare") ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) ex.response["Error"]["Code"].should.contain("UnknownResourceException") ex.response["Error"]["Message"].should.equal( "ResourceShare arn:aws:ram:us-east-1:{}:resource-share/not-existing could not be found.".format( ACCOUNT_ID ) ) @mock_ram def test_delete_resource_share(): # given client = boto3.client("ram", region_name="us-east-1") arn = client.create_resource_share(name="test")["resourceShare"]["resourceShareArn"] # when time.sleep(0.1) response = client.delete_resource_share(resourceShareArn=arn) # then response["returnValue"].should.be.ok response = client.get_resource_shares(resourceOwner="SELF") response["resourceShares"].should.have.length_of(1) resource = response["resourceShares"][0] resource["status"].should.equal("DELETED") creation_time = resource["creationTime"] resource["lastUpdatedTime"].should.be.greater_than(creation_time) @mock_ram def test_delete_resource_share_errors(): # given client = boto3.client("ram", region_name="us-east-1") # invalid resource owner # when with pytest.raises(ClientError) as e: client.delete_resource_share( resourceShareArn="arn:aws:ram:us-east-1:{}:resource-share/not-existing".format( ACCOUNT_ID ) ) ex = e.value ex.operation_name.should.equal("DeleteResourceShare") ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) ex.response["Error"]["Code"].should.contain("UnknownResourceException") ex.response["Error"]["Message"].should.equal( "ResourceShare arn:aws:ram:us-east-1:{}:resource-share/not-existing could not be found.".format( ACCOUNT_ID ) ) @mock_ram @mock_organizations def test_enable_sharing_with_aws_organization(): # given client = boto3.client("organizations", region_name="us-east-1") client.create_organization(FeatureSet="ALL") client = boto3.client("ram", region_name="us-east-1") # when response = client.enable_sharing_with_aws_organization() # then response["returnValue"].should.be.ok @mock_ram @mock_organizations def test_enable_sharing_with_aws_organization_errors(): # given client = boto3.client("ram", region_name="us-east-1") # no Organization defined # when with pytest.raises(ClientError) as e: client.enable_sharing_with_aws_organization() ex = e.value ex.operation_name.should.equal("EnableSharingWithAwsOrganization") ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400) ex.response["Error"]["Code"].should.contain("OperationNotPermittedException") ex.response["Error"]["Message"].should.equal( "Unable to enable sharing with AWS Organizations. " "Received AccessDeniedException from AWSOrganizations with the following error message: " "You don't have permissions to access this resource." )