diff --git a/moto/redshift/models.py b/moto/redshift/models.py index 7062b521c..a7096d956 100644 --- a/moto/redshift/models.py +++ b/moto/redshift/models.py @@ -8,6 +8,7 @@ from moto.compat import OrderedDict from moto.core import BaseBackend, BaseModel from moto.core.utils import iso_8601_datetime_with_milliseconds from moto.ec2 import ec2_backends +from moto.iam import iam_backends from .exceptions import ( ClusterNotFoundError, ClusterParameterGroupNotFoundError, @@ -67,7 +68,7 @@ class Cluster(TaggableResourceMixin, BaseModel): preferred_maintenance_window, cluster_parameter_group_name, automated_snapshot_retention_period, port, cluster_version, allow_version_upgrade, number_of_nodes, publicly_accessible, - encrypted, region_name, tags=None, iam_roles=None): + encrypted, region_name, tags=None, iam_roles_arn=[]): super(Cluster, self).__init__(region_name, tags) self.redshift_backend = redshift_backend self.cluster_identifier = cluster_identifier @@ -112,8 +113,7 @@ class Cluster(TaggableResourceMixin, BaseModel): else: self.number_of_nodes = 1 - if iam_roles: - self.iam_roles = iam_roles + self.iam_roles_arn = iam_roles_arn @classmethod def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name): @@ -196,6 +196,14 @@ class Cluster(TaggableResourceMixin, BaseModel): def resource_id(self): return self.cluster_identifier + @property + def iam_roles(self): + return [ + iam_role for iam_role + in self.redshift_backend.iam_backend.get_roles() + if iam_role.arn in self.iam_roles_arn + ] + def to_json(self): return { "MasterUsername": self.master_username, @@ -231,7 +239,11 @@ class Cluster(TaggableResourceMixin, BaseModel): "Port": self.port }, "PendingModifiedValues": [], - "Tags": self.tags + "Tags": self.tags, + "IamRoles": [{ + "ApplyStatus": "in-sync", + "IamRoleArn": iam_role.arn + } for iam_role in self.iam_roles] } @@ -354,7 +366,7 @@ class Snapshot(TaggableResourceMixin, BaseModel): resource_type = 'snapshot' - def __init__(self, cluster, snapshot_identifier, region_name, tags=None): + def __init__(self, cluster, snapshot_identifier, region_name, tags=None, iam_roles_arn=[]): super(Snapshot, self).__init__(region_name, tags) self.cluster = copy.copy(cluster) self.snapshot_identifier = snapshot_identifier @@ -362,6 +374,7 @@ class Snapshot(TaggableResourceMixin, BaseModel): self.status = 'available' self.create_time = iso_8601_datetime_with_milliseconds( datetime.datetime.now()) + self.iam_roles_arn = iam_roles_arn @property def resource_id(self): @@ -383,7 +396,8 @@ class Snapshot(TaggableResourceMixin, BaseModel): 'NodeType': self.cluster.node_type, 'NumberOfNodes': self.cluster.number_of_nodes, 'DBName': self.cluster.db_name, - 'Tags': self.tags + 'Tags': self.tags, + 'IamRoles': self.iam_roles_arn } @@ -413,6 +427,7 @@ class RedshiftBackend(BaseBackend): 'snapshot': self.snapshots, 'subnetgroup': self.subnet_groups } + self.iam_backend = iam_backends['global'] def reset(self): ec2_backend = self.ec2_backend diff --git a/moto/redshift/responses.py b/moto/redshift/responses.py index 54cd51744..34f116bd5 100644 --- a/moto/redshift/responses.py +++ b/moto/redshift/responses.py @@ -134,7 +134,7 @@ class RedshiftResponse(BaseResponse): "encrypted": self._get_param("Encrypted"), "region_name": self.region, "tags": self.unpack_complex_list_params('Tags.Tag', ('Key', 'Value')), - "iam_roles": self._get_iam_roles(), + "iam_roles_arn": self._get_iam_roles(), } cluster = self.redshift_backend.create_cluster(**cluster_kwargs).to_json() cluster['ClusterStatus'] = 'creating' @@ -169,7 +169,7 @@ class RedshiftResponse(BaseResponse): "automated_snapshot_retention_period": self._get_int_param( 'AutomatedSnapshotRetentionPeriod'), "region_name": self.region, - "iam_roles": self._get_iam_roles(), + "iam_roles_arn": self._get_iam_roles(), } cluster = self.redshift_backend.restore_from_cluster_snapshot(**restore_kwargs).to_json() cluster['ClusterStatus'] = 'creating' @@ -217,7 +217,7 @@ class RedshiftResponse(BaseResponse): "number_of_nodes": self._get_int_param('NumberOfNodes'), "publicly_accessible": self._get_param("PubliclyAccessible"), "encrypted": self._get_param("Encrypted"), - "iam_roles": self._get_iam_roles(), + "iam_roles_arn": self._get_iam_roles(), } cluster_kwargs = {} # We only want parameters that were actually passed in, otherwise diff --git a/tests/test_redshift/test_redshift.py b/tests/test_redshift/test_redshift.py index 3267b3acf..b617ac797 100644 --- a/tests/test_redshift/test_redshift.py +++ b/tests/test_redshift/test_redshift.py @@ -296,7 +296,7 @@ def test_create_cluster_with_vpc_security_groups_boto3(): @mock_redshift def test_create_cluster_with_iam_roles(): - iam_role = 'arn:aws:iam:::role/my-iam-role' + iam_roles_arn = ['arn:aws:iam:::role/my-iam-role',] client = boto3.client('redshift', region_name='us-east-1') cluster_id = 'my_cluster' client.create_cluster( @@ -304,12 +304,12 @@ def test_create_cluster_with_iam_roles(): NodeType="dw.hs1.xlarge", MasterUsername="username", MasterUserPassword="password", - IamRoles=[iam_role], + IamRoles=iam_roles_arn ) response = client.describe_clusters(ClusterIdentifier=cluster_id) cluster = response['Clusters'][0] iam_roles = [role['IamRoleArn'] for role in cluster['IamRoles']] - list(iam_roles).should.equal([iam_role.arn]) + iam_roles_arn.should.equal(iam_roles) @mock_redshift_deprecated