diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md index 699c85d59..0d95af4cb 100644 --- a/IMPLEMENTATION_COVERAGE.md +++ b/IMPLEMENTATION_COVERAGE.md @@ -4294,7 +4294,7 @@ - [X] describe_db_clusters - [ ] describe_db_engine_versions - [ ] describe_db_instance_automated_backups -- [ ] describe_db_instances +- [X] describe_db_instances - [ ] describe_db_log_files - [X] describe_db_parameter_groups - [ ] describe_db_parameters diff --git a/docs/docs/services/rds.rst b/docs/docs/services/rds.rst index dfe0c6166..06d1a4994 100644 --- a/docs/docs/services/rds.rst +++ b/docs/docs/services/rds.rst @@ -82,7 +82,7 @@ rds - [X] describe_db_clusters - [ ] describe_db_engine_versions - [ ] describe_db_instance_automated_backups -- [ ] describe_db_instances +- [X] describe_db_instances - [ ] describe_db_log_files - [X] describe_db_parameter_groups - [ ] describe_db_parameters diff --git a/moto/rds/exceptions.py b/moto/rds/exceptions.py index 20306bb6d..4512df86e 100644 --- a/moto/rds/exceptions.py +++ b/moto/rds/exceptions.py @@ -7,14 +7,14 @@ class RDSClientError(BadRequest): super().__init__() template = Template( """ - + {{ code }} {{ message }} Sender 6876f774-7273-11e4-85dc-39e55ca848d1 - """ + """ ) self.description = template.render(code=code, message=message) diff --git a/moto/rds/models.py b/moto/rds/models.py index db7409e66..956499834 100644 --- a/moto/rds/models.py +++ b/moto/rds/models.py @@ -110,6 +110,9 @@ class Cluster: random.choice(string.ascii_uppercase + string.digits) for _ in range(26) ) self.tags = kwargs.get("tags", []) + self.enabled_cloudwatch_logs_exports = ( + kwargs.get("enable_cloudwatch_logs_exports") or [] + ) @property def db_cluster_arn(self): @@ -172,6 +175,11 @@ class Cluster: {{ cluster.copy_tags_to_snapshot }} false + + {% for export in cluster.enabled_cloudwatch_logs_exports %} + {{ export }} + {% endfor %} + {%- for tag in cluster.tags -%} @@ -426,6 +434,9 @@ class Database(CloudFormationModel): self.dbi_resource_id = "db-M5ENSHXFPU6XHZ4G4ZEI5QIO2U" self.tags = kwargs.get("tags", []) self.deletion_protection = kwargs.get("deletion_protection", False) + self.enabled_cloudwatch_logs_exports = ( + kwargs.get("enable_cloudwatch_logs_exports") or [] + ) @property def db_instance_arn(self): @@ -516,6 +527,11 @@ class Database(CloudFormationModel): {% endif %} + + {% for export in database.enabled_cloudwatch_logs_exports %} + {{ export }} + {% endfor %} + {% if database.is_replica %} {{ database.source_db_identifier }} {% endif %} @@ -1331,7 +1347,7 @@ class RDSBackend(BaseBackend): primary.add_replica(replica) return replica - def describe_databases(self, db_instance_identifier=None, filters=None): + def describe_db_instances(self, db_instance_identifier=None, filters=None): databases = self.databases if db_instance_identifier: filters = merge_filters( @@ -1362,7 +1378,7 @@ class RDSBackend(BaseBackend): return list(snapshots.values()) def modify_db_instance(self, db_instance_identifier, db_kwargs): - database = self.describe_databases(db_instance_identifier)[0] + database = self.describe_db_instances(db_instance_identifier)[0] if "new_db_instance_identifier" in db_kwargs: del self.databases[db_instance_identifier] db_instance_identifier = db_kwargs[ @@ -1373,7 +1389,7 @@ class RDSBackend(BaseBackend): return database def reboot_db_instance(self, db_instance_identifier): - database = self.describe_databases(db_instance_identifier)[0] + database = self.describe_db_instances(db_instance_identifier)[0] return database def restore_db_instance_from_db_snapshot(self, from_snapshot_id, overrides): @@ -1394,7 +1410,7 @@ class RDSBackend(BaseBackend): return self.create_db_instance(new_instance_props) def stop_db_instance(self, db_instance_identifier, db_snapshot_identifier=None): - database = self.describe_databases(db_instance_identifier)[0] + database = self.describe_db_instances(db_instance_identifier)[0] # todo: certain rds types not allowed to be stopped at this time. # https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_StopInstance.html#USER_StopInstance.Limitations if database.is_replica or ( @@ -1410,7 +1426,7 @@ class RDSBackend(BaseBackend): return database def start_db_instance(self, db_instance_identifier): - database = self.describe_databases(db_instance_identifier)[0] + database = self.describe_db_instances(db_instance_identifier)[0] # todo: bunch of different error messages to be generated from this api call if database.status != "stopped": raise InvalidDBInstanceStateError(db_instance_identifier, "start") @@ -1427,7 +1443,7 @@ class RDSBackend(BaseBackend): backend = self db_name = db_id - return backend.describe_databases(db_name)[0] + return backend.describe_db_instances(db_name)[0] def delete_db_instance(self, db_instance_identifier, db_snapshot_name=None): if db_instance_identifier in self.databases: diff --git a/moto/rds/responses.py b/moto/rds/responses.py index c2b7b9bac..77f01bb51 100644 --- a/moto/rds/responses.py +++ b/moto/rds/responses.py @@ -27,6 +27,9 @@ class RDSResponse(BaseResponse): "db_subnet_group_name": self._get_param("DBSubnetGroupName"), "engine": self._get_param("Engine"), "engine_version": self._get_param("EngineVersion"), + "enable_cloudwatch_logs_exports": self._get_params().get( + "EnableCloudwatchLogsExports" + ), "enable_iam_database_authentication": self._get_bool_param( "EnableIAMDatabaseAuthentication" ), @@ -92,6 +95,9 @@ class RDSResponse(BaseResponse): "availability_zones": self._get_multi_param( "AvailabilityZones.AvailabilityZone" ), + "enable_cloudwatch_logs_exports": self._get_params().get( + "EnableCloudwatchLogsExports" + ), "db_name": self._get_param("DatabaseName"), "db_cluster_identifier": self._get_param("DBClusterIdentifier"), "deletion_protection": self._get_bool_param("DeletionProtection"), @@ -174,7 +180,7 @@ class RDSResponse(BaseResponse): filters = self._get_multi_param("Filters.Filter.") filters = {f["Name"]: f["Values"] for f in filters} all_instances = list( - self.backend.describe_databases(db_instance_identifier, filters=filters) + self.backend.describe_db_instances(db_instance_identifier, filters=filters) ) marker = self._get_param("Marker") all_ids = [instance.db_instance_identifier for instance in all_instances] diff --git a/tests/test_rds/test_rds.py b/tests/test_rds/test_rds.py index 13df7ff38..522af30dd 100644 --- a/tests/test_rds/test_rds.py +++ b/tests/test_rds/test_rds.py @@ -21,6 +21,7 @@ def test_create_database(): Port=1234, DBSecurityGroups=["my_sg"], VpcSecurityGroupIds=["sg-123456"], + EnableCloudwatchLogsExports=["audit", "error"], ) db_instance = database["DBInstance"] db_instance["AllocatedStorage"].should.equal(10) @@ -40,6 +41,7 @@ def test_create_database(): db_instance["InstanceCreateTime"].should.be.a("datetime.datetime") db_instance["VpcSecurityGroups"][0]["VpcSecurityGroupId"].should.equal("sg-123456") db_instance["DeletionProtection"].should.equal(False) + db_instance["EnabledCloudwatchLogsExports"].should.equal(["audit", "error"]) @mock_rds diff --git a/tests/test_rds/test_rds_clusters.py b/tests/test_rds/test_rds_clusters.py index 9e6fd2c11..e9614c745 100644 --- a/tests/test_rds/test_rds_clusters.py +++ b/tests/test_rds/test_rds_clusters.py @@ -157,6 +157,7 @@ def test_create_db_cluster_additional_parameters(): MasterUserPassword="hunter2_", Port=1234, DeletionProtection=True, + EnableCloudwatchLogsExports=["audit"], ) cluster = resp["DBCluster"] @@ -167,6 +168,7 @@ def test_create_db_cluster_additional_parameters(): cluster.should.have.key("EngineMode").equal("serverless") cluster.should.have.key("Port").equal(1234) cluster.should.have.key("DeletionProtection").equal(True) + cluster.should.have.key("EnabledCloudwatchLogsExports").equals(["audit"]) @mock_rds