diff --git a/moto/rds/models.py b/moto/rds/models.py index db0042cac..899ff6456 100644 --- a/moto/rds/models.py +++ b/moto/rds/models.py @@ -49,6 +49,7 @@ from .utils import ( merge_filters, validate_filters, valid_preferred_maintenance_window, + ClusterEngine, ) @@ -129,6 +130,17 @@ class Cluster: self.db_cluster_instance_class = kwargs.get("db_cluster_instance_class") self.deletion_protection = kwargs.get("deletion_protection") self.engine = kwargs.get("engine") + if self.engine not in ClusterEngine.list_cluster_engines(): + raise InvalidParameterValue( + ( + "Engine '{engine}' is not supported " + "to satisfy constraint: Member must satisfy enum value set: " + "{valid_engines}" + ).format( + engine=self.engine, + valid_engines=ClusterEngine.list_cluster_engines(), + ) + ) self.engine_version = kwargs.get("engine_version") or Cluster.default_engine_version(self.engine) # type: ignore self.engine_mode = kwargs.get("engine_mode") or "provisioned" self.iops = kwargs.get("iops") @@ -1591,7 +1603,10 @@ class RDSBackend(BaseBackend): if cluster_id is not None: cluster = self.clusters.get(cluster_id) if cluster is not None: - if cluster.engine == "aurora" and cluster.engine_mode == "serverless": + if ( + cluster.engine in ClusterEngine.serverless_engines() + and cluster.engine_mode == "serverless" + ): raise InvalidParameterValue( "Instances cannot be added to Aurora Serverless clusters." ) diff --git a/moto/rds/utils.py b/moto/rds/utils.py index 75038d2e5..6c26c96d1 100644 --- a/moto/rds/utils.py +++ b/moto/rds/utils.py @@ -1,6 +1,7 @@ import copy from collections import namedtuple -from typing import Any, Dict, Tuple, Optional +from typing import Any, Dict, Tuple, Optional, List +from enum import Enum from botocore.utils import merge_dicts @@ -22,6 +23,21 @@ FilterDef = namedtuple( ) +class ClusterEngine(str, Enum): + AURORA_POSTGRESQL = "aurora-postgresql" + AURORA_MYSQL = "aurora-mysql" + RDS_POSTGRESQL = "postgres" + RDS_MYSQL = "mysql" + + @classmethod + def list_cluster_engines(self) -> List[str]: + return sorted([item.value for item in ClusterEngine]) + + @classmethod + def serverless_engines(self) -> List[str]: + return [ClusterEngine.AURORA_MYSQL, ClusterEngine.AURORA_POSTGRESQL] + + def get_object_value(obj: Any, attr: str) -> Any: """Retrieves an arbitrary attribute value from an object. diff --git a/tests/test_rds/test_rds_clusters.py b/tests/test_rds/test_rds_clusters.py index 2c261d498..b099e0f6b 100644 --- a/tests/test_rds/test_rds_clusters.py +++ b/tests/test_rds/test_rds_clusters.py @@ -31,12 +31,29 @@ def test_describe_db_cluster_fails_for_non_existent_cluster(): assert err["Message"] == "DBCluster cluster-id not found." +@mock_rds +def test_create_db_cluster_invalid_engine(): + client = boto3.client("rds", region_name=RDS_REGION) + + with pytest.raises(ClientError) as ex: + client.create_db_cluster( + DBClusterIdentifier="cluster-id", Engine="aurora-postgresql" + ) + err = ex.value.response["Error"] + assert err["Code"] == "InvalidParameterValue" + assert err["Message"] == ( + "The parameter MasterUsername must be provided and must not be blank." + ) + + @mock_rds def test_create_db_cluster_needs_master_username(): client = boto3.client("rds", region_name=RDS_REGION) with pytest.raises(ClientError) as ex: - client.create_db_cluster(DBClusterIdentifier="cluster-id", Engine="aurora") + client.create_db_cluster( + DBClusterIdentifier="cluster-id", Engine="aurora-postgresql" + ) err = ex.value.response["Error"] assert err["Code"] == "InvalidParameterValue" assert err["Message"] == ( @@ -50,7 +67,9 @@ def test_create_db_cluster_needs_master_user_password(): with pytest.raises(ClientError) as ex: client.create_db_cluster( - DBClusterIdentifier="cluster-id", Engine="aurora", MasterUsername="root" + DBClusterIdentifier="cluster-id", + Engine="aurora-postgresql", + MasterUsername="root", ) err = ex.value.response["Error"] assert err["Code"] == "InvalidParameterValue" @@ -66,7 +85,7 @@ def test_create_db_cluster_needs_long_master_user_password(): with pytest.raises(ClientError) as ex: client.create_db_cluster( DBClusterIdentifier="cluster-id", - Engine="aurora", + Engine="aurora-postgresql", MasterUsername="root", MasterUserPassword="hunter2", ) @@ -84,7 +103,7 @@ def test_modify_db_cluster_needs_long_master_user_password(): client.create_db_cluster( DBClusterIdentifier="cluster-id", - Engine="aurora", + Engine="aurora-postgresql", MasterUsername="root", MasterUserPassword="hunter21", ) @@ -110,7 +129,7 @@ def test_modify_db_cluster_new_cluster_identifier(): client.create_db_cluster( DBClusterIdentifier=old_id, - Engine="aurora", + Engine="aurora-postgresql", MasterUsername="root", MasterUserPassword="hunter21", ) @@ -137,7 +156,7 @@ def test_create_db_cluster__verify_default_properties(): resp = client.create_db_cluster( DBClusterIdentifier="cluster-id", - Engine="aurora", + Engine="aurora-mysql", MasterUsername="root", MasterUserPassword="hunter2_", ) @@ -169,8 +188,8 @@ def test_create_db_cluster__verify_default_properties(): ) assert cluster["ReaderEndpoint"] == expected_readonly assert cluster["MultiAZ"] is False - assert cluster["Engine"] == "aurora" - assert cluster["EngineVersion"] == "5.6.mysql_aurora.1.22.5" + assert cluster["Engine"] == "aurora-mysql" + assert cluster["EngineVersion"] == "5.7.mysql_aurora.2.07.2" assert cluster["Port"] == 3306 assert cluster["MasterUsername"] == "root" assert cluster["PreferredBackupWindow"] == "01:37-02:07" @@ -206,7 +225,7 @@ def test_create_db_cluster_additional_parameters(): AvailabilityZones=["eu-north-1b"], DatabaseName="users", DBClusterIdentifier="cluster-id", - Engine="aurora", + Engine="aurora-postgresql", EngineVersion="8.0.mysql_aurora.3.01.0", EngineMode="serverless", MasterUsername="root", @@ -232,7 +251,7 @@ def test_create_db_cluster_additional_parameters(): assert cluster["AvailabilityZones"] == ["eu-north-1b"] assert cluster["DatabaseName"] == "users" - assert cluster["Engine"] == "aurora" + assert cluster["Engine"] == "aurora-postgresql" assert cluster["EngineVersion"] == "8.0.mysql_aurora.3.01.0" assert cluster["EngineMode"] == "serverless" assert cluster["Port"] == 1234 @@ -259,14 +278,14 @@ def test_describe_db_cluster_after_creation(): client.create_db_cluster( DBClusterIdentifier="cluster-id1", - Engine="aurora", + Engine="aurora-postgresql", MasterUsername="root", MasterUserPassword="hunter2_", ) cluster_arn = client.create_db_cluster( DBClusterIdentifier="cluster-id2", - Engine="aurora", + Engine="aurora-postgresql", MasterUsername="root", MasterUserPassword="hunter2_", )["DBCluster"]["DBClusterArn"] @@ -292,7 +311,7 @@ def test_delete_db_cluster(): client.create_db_cluster( DBClusterIdentifier="cluster-id", - Engine="aurora", + Engine="aurora-postgresql", MasterUsername="root", MasterUserPassword="hunter2_", ) @@ -308,7 +327,7 @@ def test_delete_db_cluster_do_snapshot(): client.create_db_cluster( DBClusterIdentifier="cluster-id", - Engine="aurora", + Engine="aurora-postgresql", MasterUsername="root", MasterUserPassword="hunter2_", ) @@ -329,7 +348,7 @@ def test_delete_db_cluster_that_is_protected(): client.create_db_cluster( DBClusterIdentifier="cluster-id", - Engine="aurora", + Engine="aurora-postgresql", MasterUsername="root", MasterUserPassword="hunter2_", DeletionProtection=True, @@ -369,7 +388,7 @@ def test_start_db_cluster_after_stopping(): client.create_db_cluster( DBClusterIdentifier="cluster-id", - Engine="aurora", + Engine="aurora-postgresql", MasterUsername="root", MasterUserPassword="hunter2_", ) @@ -386,7 +405,7 @@ def test_start_db_cluster_without_stopping(): client.create_db_cluster( DBClusterIdentifier="cluster-id", - Engine="aurora", + Engine="aurora-postgresql", MasterUsername="root", MasterUserPassword="hunter2_", ) @@ -404,7 +423,7 @@ def test_stop_db_cluster(): client.create_db_cluster( DBClusterIdentifier="cluster-id", - Engine="aurora", + Engine="aurora-postgresql", MasterUsername="root", MasterUserPassword="hunter2_", ) @@ -425,7 +444,7 @@ def test_stop_db_cluster_already_stopped(): client.create_db_cluster( DBClusterIdentifier="cluster-id", - Engine="aurora", + Engine="aurora-postgresql", MasterUsername="root", MasterUserPassword="hunter2_", ) @@ -838,7 +857,7 @@ def test_create_db_cluster_with_enable_http_endpoint_invalid(): resp = client.create_db_cluster( DBClusterIdentifier="cluster-id", DatabaseName="users", - Engine="aurora-mysql", + Engine="aurora-postgresql", EngineMode="serverless", EngineVersion="5.7.0", MasterUsername="root", diff --git a/tests/test_rds/test_rds_clusters_with_instances.py b/tests/test_rds/test_rds_clusters_with_instances.py index 66caeed7f..c7352bad1 100644 --- a/tests/test_rds/test_rds_clusters_with_instances.py +++ b/tests/test_rds/test_rds_clusters_with_instances.py @@ -74,7 +74,7 @@ def test_add_instance_to_serverless_cluster(): _ = client.create_db_cluster( DBClusterIdentifier="dbci", - Engine="aurora", + Engine="aurora-postgresql", EngineMode="serverless", MasterUsername="masterusername", MasterUserPassword="hunter2_",