Repository: getmoto/moto
Pull request #7002 (2023-11-08 10:20:08)

RDS: Add validation for engine parameter before creating db_instance
There is no validation for parameter Engine before creating db instance
for example `Engine="invalid-engine"` is not supported by AWS

have fixed this problem. hope it makes sense for you

bblommers: Hi @jamesdongdong, can you fix the conflicts? Happy to merge this afterwards
jamesdongdong: > Hi @jamesdongdong, can you fix the conflicts? Happy to merge this afterwards

@bblommers 

thanks！ have fixed the conflicts

Patch:
diff --git a/moto/rds/models.py b/moto/rds/models.py
index 899ff6456..82a7c0755 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,
+    DbInstanceEngine,
     ClusterEngine,
 )
 
@@ -568,6 +569,10 @@ class Database(CloudFormationModel):
         self.account_id: str = kwargs["account_id"]
         self.region_name: str = kwargs["region"]
         self.engine = kwargs.get("engine")
+        if self.engine not in DbInstanceEngine.valid_db_instance_engine():
+            raise InvalidParameterValue(
+                f"Value {self.engine} for parameter Engine is invalid. Reason: engine {self.engine} not supported"
+            )
         self.engine_version = kwargs.get("engine_version", None)
         if not self.engine_version and self.engine in self.default_engine_versions:
             self.engine_version = self.default_engine_versions[self.engine]
diff --git a/moto/rds/utils.py b/moto/rds/utils.py
index 6c26c96d1..b890ff9b5 100644
--- a/moto/rds/utils.py
+++ b/moto/rds/utils.py
@@ -23,6 +23,34 @@ FilterDef = namedtuple(
 )
 
 
+class DbInstanceEngine(str, Enum):
+
+    # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/rds/client/create_db_instance.html
+    # 2023-11-08
+    AURORA_MYSQL = "aurora-mysql"
+    AURORA_POSTGRESQL = "aurora-postgresql"
+    CUSTOM_ORACLE_EE = "custom-oracle-ee"
+    CUSTOM_ORACLE_EE_CDB = "custom-oracle-ee-cdb"
+    CUSTOM_SQLSERVER_EE = "custom-sqlserver-ee"
+    CUSTOM_SQLSERVER_SE = "custom-sqlserver-se"
+    CUSTOM_SQLSERVER_WEB = "custom-sqlserver-web"
+    MARIADB = "mariadb"
+    MYSQL = "mysql"
+    ORACLE_EE = "oracle-ee"
+    ORACLE_EE_CDB = "oracle-ee-cdb"
+    ORACLE_SE2 = "oracle-se2"
+    ORACLE_SE2_CDB = "oracle-se2-cdb"
+    POSTGRES = "postgres"
+    SQLSERVER_EE = "sqlserver-ee"
+    SQLSERVER_SE = "sqlserver-se"
+    SQLSERVER_EX = "sqlserver-ex"
+    SQLSERVER_WEB = "sqlserver-web"
+
+    @classmethod
+    def valid_db_instance_engine(self) -> List[str]:
+        return sorted([item.value for item in DbInstanceEngine])
+
+
 class ClusterEngine(str, Enum):
     AURORA_POSTGRESQL = "aurora-postgresql"
     AURORA_MYSQL = "aurora-mysql"


Test patch:
diff --git a/tests/test_cloudformation/fixtures/rds_mysql_with_db_parameter_group.py b/tests/test_cloudformation/fixtures/rds_mysql_with_db_parameter_group.py
index b0dac055b..71ac3fe4f 100644
--- a/tests/test_cloudformation/fixtures/rds_mysql_with_db_parameter_group.py
+++ b/tests/test_cloudformation/fixtures/rds_mysql_with_db_parameter_group.py
@@ -150,7 +150,7 @@ template = {
                 "DBName": {"Ref": "DBName"},
                 "AllocatedStorage": {"Ref": "DBAllocatedStorage"},
                 "DBInstanceClass": {"Ref": "DBInstanceClass"},
-                "Engine": "MySQL",
+                "Engine": "mysql",
                 "DBSubnetGroupName": {
                     "Fn::If": [
                         "Is-EC2-VPC",
diff --git a/tests/test_cloudformation/fixtures/rds_mysql_with_read_replica.py b/tests/test_cloudformation/fixtures/rds_mysql_with_read_replica.py
index a21589966..25f4537a6 100644
--- a/tests/test_cloudformation/fixtures/rds_mysql_with_read_replica.py
+++ b/tests/test_cloudformation/fixtures/rds_mysql_with_read_replica.py
@@ -142,7 +142,7 @@ template = {
                 "DBName": {"Ref": "DBName"},
                 "AllocatedStorage": {"Ref": "DBAllocatedStorage"},
                 "DBInstanceClass": {"Ref": "DBInstanceClass"},
-                "Engine": "MySQL",
+                "Engine": "mysql",
                 "DBSubnetGroupName": {
                     "Fn::If": [
                         "Is-EC2-VPC",
diff --git a/tests/test_rds/test_rds.py b/tests/test_rds/test_rds.py
index 4fafa9d40..613a5118c 100644
--- a/tests/test_rds/test_rds.py
+++ b/tests/test_rds/test_rds.py
@@ -482,7 +482,7 @@ def test_get_databases():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -492,7 +492,7 @@ def test_get_databases():
         DBInstanceIdentifier="db-master-2",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -554,7 +554,7 @@ def test_modify_db_instance():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -586,7 +586,7 @@ def test_modify_db_instance_not_existent_db_parameter_group_name():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -608,7 +608,7 @@ def test_modify_db_instance_valid_preferred_maintenance_window():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -632,7 +632,7 @@ def test_modify_db_instance_valid_preferred_maintenance_window_uppercase():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -656,7 +656,7 @@ def test_modify_db_instance_invalid_preferred_maintenance_window_more_than_24_ho
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -679,7 +679,7 @@ def test_modify_db_instance_invalid_preferred_maintenance_window_less_than_30_mi
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -702,7 +702,7 @@ def test_modify_db_instance_invalid_preferred_maintenance_window_value():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -725,7 +725,7 @@ def test_modify_db_instance_invalid_preferred_maintenance_window_format():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -751,7 +751,7 @@ def test_modify_db_instance_maintenance_backup_window_no_spill():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -777,7 +777,7 @@ def test_modify_db_instance_maintenance_backup_window_maintenance_spill():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -803,7 +803,7 @@ def test_modify_db_instance_maintenance_backup_window_backup_spill():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -829,7 +829,7 @@ def test_modify_db_instance_maintenance_backup_window_both_spill():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -855,7 +855,7 @@ def test_rename_db_instance():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -892,7 +892,7 @@ def test_reboot_db_instance():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -1484,7 +1484,7 @@ def test_list_tags_db():
         DBInstanceIdentifier="db-with-tags",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -1507,7 +1507,7 @@ def test_add_tags_db():
         DBInstanceIdentifier="db-without-tags",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -1535,7 +1535,7 @@ def test_remove_tags_db():
         DBInstanceIdentifier="db-with-tags",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -1807,7 +1807,7 @@ def test_add_security_group_to_database():
         DBInstanceIdentifier="db-master-1",
         AllocatedStorage=10,
         DBInstanceClass="postgres",
-        Engine="db.m1.small",
+        Engine="postgres",
         MasterUsername="root",
         MasterUserPassword="hunter2",
         Port=1234,
@@ -2629,6 +2629,26 @@ def test_validate_db_identifier():
     validation_helper(exc)
 
 
+@mock_rds
+def test_createdb_instance_engine_with_invalid_value():
+    client = boto3.client("rds", region_name=DEFAULT_REGION)
+    with pytest.raises(ClientError) as exc:
+        client.create_db_instance(
+            DBInstanceIdentifier="test-db-instance",
+            Engine="invalid-engine",
+            DBName="staging-postgres",
+            DBInstanceClass="db.m1.small",
+        )
+
+    err = exc.value.response["Error"]
+
+    assert err["Code"] == "InvalidParameterValue"
+    assert (
+        err["Message"]
+        == "Value invalid-engine for parameter Engine is invalid. Reason: engine invalid-engine not supported"
+    )
+
+
 def validation_helper(exc):
     err = exc.value.response["Error"]
     assert err["Code"] == "InvalidParameterValue"
diff --git a/tests/test_rds/test_server.py b/tests/test_rds/test_server.py
index 9f6a0fbcd..82dab5db2 100644
--- a/tests/test_rds/test_server.py
+++ b/tests/test_rds/test_server.py
@@ -19,7 +19,7 @@ def test_create_db_instance():
         "Action": "CreateDBInstance",
         "DBInstanceIdentifier": "hi",
         "DBInstanceClass": "db.m4.large",
-        "Engine": "aurora",
+        "Engine": "aurora-mysql",
         "StorageType": "standard",
         "Port": 3306,
     }