From 93638de380d01d28ac7027dfa42dc1d6bfd8ca55 Mon Sep 17 00:00:00 2001 From: Brian Pandola Date: Tue, 28 Mar 2023 00:54:41 -0700 Subject: [PATCH] Add filtering support for RDS::DBCluster (#6144) * Add filtering support for RDS::DBCluster * Add support for filtering by `db-cluster-id`. * Add support for filtering by `engine`. Obviates the need for the recent change (#6114) because the filter definition maps `db_cluster_id` to either `db_cluster_identifier` or `db_cluster_arn`. * No longer required due to filter configuration. * Account for Neptune weirdness... --- moto/rds/models.py | 27 +++++++++++++++-------- moto/rds/responses.py | 6 ++++- tests/test_neptune/test_clusters.py | 4 +++- tests/test_rds/test_rds_clusters.py | 34 +++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/moto/rds/models.py b/moto/rds/models.py index a89db9e2e..f5202583c 100644 --- a/moto/rds/models.py +++ b/moto/rds/models.py @@ -46,6 +46,13 @@ from .utils import ( class Cluster: + SUPPORTED_FILTERS = { + "db-cluster-id": FilterDef( + ["db_cluster_arn", "db_cluster_identifier"], "DB Cluster Identifiers" + ), + "engine": FilterDef(["engine"], "Engine Names"), + } + def __init__(self, **kwargs): self.db_name = kwargs.get("db_name") self.db_cluster_identifier = kwargs.get("db_cluster_identifier") @@ -1948,17 +1955,19 @@ class RDSBackend(BaseBackend): return self.cluster_snapshots.pop(db_snapshot_identifier) - def describe_db_clusters(self, cluster_identifier): + def describe_db_clusters(self, cluster_identifier=None, filters=None): + clusters = self.clusters + clusters_neptune = self.neptune.clusters if cluster_identifier: - # ARN to identifier - # arn:aws:rds:eu-north-1:123456789012:cluster:cluster --> cluster-id - cluster_identifier = cluster_identifier.split(":")[-1] - if cluster_identifier in self.clusters: - return [self.clusters[cluster_identifier]] - if cluster_identifier in self.neptune.clusters: - return [self.neptune.clusters[cluster_identifier]] + filters = merge_filters(filters, {"db-cluster-id": [cluster_identifier]}) + if filters: + clusters = self._filter_resources(clusters, filters, Cluster) + clusters_neptune = self._filter_resources( + clusters_neptune, filters, Cluster + ) + if cluster_identifier and not (clusters or clusters_neptune): raise DBClusterNotFoundError(cluster_identifier) - return list(self.clusters.values()) + list(self.neptune.clusters.values()) + return list(clusters.values()) + list(clusters_neptune.values()) def describe_db_cluster_snapshots( self, db_cluster_identifier, db_snapshot_identifier, filters=None diff --git a/moto/rds/responses.py b/moto/rds/responses.py index 4325e4bda..e698a1b39 100644 --- a/moto/rds/responses.py +++ b/moto/rds/responses.py @@ -583,7 +583,11 @@ class RDSResponse(BaseResponse): def describe_db_clusters(self): _id = self._get_param("DBClusterIdentifier") - clusters = self.backend.describe_db_clusters(cluster_identifier=_id) + filters = self._get_multi_param("Filters.Filter.") + filters = {f["Name"]: f["Values"] for f in filters} + clusters = self.backend.describe_db_clusters( + cluster_identifier=_id, filters=filters + ) template = self.response_template(DESCRIBE_CLUSTERS_TEMPLATE) return template.render(clusters=clusters) diff --git a/tests/test_neptune/test_clusters.py b/tests/test_neptune/test_clusters.py index b1f7db6c5..18602a582 100644 --- a/tests/test_neptune/test_clusters.py +++ b/tests/test_neptune/test_clusters.py @@ -64,7 +64,9 @@ def test_describe_db_clusters(): client.create_db_cluster(DBClusterIdentifier="cluster-id", Engine="neptune") - clusters = client.describe_db_clusters()["DBClusters"] + clusters = client.describe_db_clusters(DBClusterIdentifier="cluster-id")[ + "DBClusters" + ] clusters.should.have.length_of(1) clusters[0]["DBClusterIdentifier"].should.equal("cluster-id") clusters[0].should.have.key("Engine").equals("neptune") diff --git a/tests/test_rds/test_rds_clusters.py b/tests/test_rds/test_rds_clusters.py index d5e1be474..e022b609c 100644 --- a/tests/test_rds/test_rds_clusters.py +++ b/tests/test_rds/test_rds_clusters.py @@ -811,3 +811,37 @@ def test_create_db_cluster_with_enable_http_endpoint_invalid(): ) cluster = resp["DBCluster"] cluster.should.have.key("HttpEndpointEnabled").equal(False) + + +@mock_rds +def test_describe_db_clusters_filter_by_engine(): + client = boto3.client("rds", region_name="eu-north-1") + + client.create_db_cluster( + DBClusterIdentifier="id1", + Engine="aurora-mysql", + MasterUsername="root", + MasterUserPassword="hunter21", + ) + + client.create_db_cluster( + DBClusterIdentifier="id2", + Engine="aurora-postgresql", + MasterUsername="root", + MasterUserPassword="hunter21", + ) + + resp = client.describe_db_clusters( + Filters=[ + { + "Name": "engine", + "Values": ["aurora-postgresql"], + } + ] + ) + + clusters = resp["DBClusters"] + assert len(clusters) == 1 + cluster = clusters[0] + assert cluster["DBClusterIdentifier"] == "id2" + assert cluster["Engine"] == "aurora-postgresql"