RDS: detect rds instance / cluster engine mismatch (#6994)

This commit is contained in:
rafcio19 2023-11-06 21:22:28 +01:00 committed by GitHub
parent 3945decb60
commit 0a5e2d3e4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 74 additions and 25 deletions

View File

@ -201,3 +201,11 @@ class InvalidDBInstanceIdentifier(InvalidParameterValue):
"Identifiers must begin with a letter; must contain only ASCII letters, digits, and hyphens; " "Identifiers must begin with a letter; must contain only ASCII letters, digits, and hyphens; "
"and must not end with a hyphen or contain two consecutive hyphens." "and must not end with a hyphen or contain two consecutive hyphens."
) )
class InvalidDBInstanceEngine(InvalidParameterCombination):
def __init__(self, instance_engine: str, cluster_engine: str) -> None:
super().__init__(
f"The engine name requested for your DB instance ({instance_engine}) doesn't match "
f"the engine name of your DB cluster ({cluster_engine})."
)

View File

@ -27,6 +27,7 @@ from .exceptions import (
DBClusterParameterGroupNotFoundError, DBClusterParameterGroupNotFoundError,
OptionGroupNotFoundFaultError, OptionGroupNotFoundFaultError,
InvalidDBClusterStateFaultError, InvalidDBClusterStateFaultError,
InvalidDBInstanceEngine,
InvalidDBInstanceStateError, InvalidDBInstanceStateError,
SnapshotQuotaExceededError, SnapshotQuotaExceededError,
DBSnapshotAlreadyExistsError, DBSnapshotAlreadyExistsError,
@ -1593,6 +1594,10 @@ class RDSBackend(BaseBackend):
raise InvalidParameterValue( raise InvalidParameterValue(
"Instances cannot be added to Aurora Serverless clusters." "Instances cannot be added to Aurora Serverless clusters."
) )
if database.engine != cluster.engine:
raise InvalidDBInstanceEngine(
str(database.engine), str(cluster.engine)
)
cluster.cluster_members.append(database_id) cluster.cluster_members.append(database_id)
self.databases[database_id] = database self.databases[database_id] = database
return database return database

View File

@ -7,10 +7,12 @@ import pytest
from moto import mock_rds from moto import mock_rds
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
RDS_REGION = "eu-north-1"
@mock_rds @mock_rds
def test_describe_db_cluster_initial(): def test_describe_db_cluster_initial():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
resp = client.describe_db_clusters() resp = client.describe_db_clusters()
assert len(resp["DBClusters"]) == 0 assert len(resp["DBClusters"]) == 0
@ -18,7 +20,7 @@ def test_describe_db_cluster_initial():
@mock_rds @mock_rds
def test_describe_db_cluster_fails_for_non_existent_cluster(): def test_describe_db_cluster_fails_for_non_existent_cluster():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
resp = client.describe_db_clusters() resp = client.describe_db_clusters()
assert len(resp["DBClusters"]) == 0 assert len(resp["DBClusters"]) == 0
@ -31,7 +33,7 @@ def test_describe_db_cluster_fails_for_non_existent_cluster():
@mock_rds @mock_rds
def test_create_db_cluster_needs_master_username(): def test_create_db_cluster_needs_master_username():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
with pytest.raises(ClientError) as ex: with pytest.raises(ClientError) as ex:
client.create_db_cluster(DBClusterIdentifier="cluster-id", Engine="aurora") client.create_db_cluster(DBClusterIdentifier="cluster-id", Engine="aurora")
@ -44,7 +46,7 @@ def test_create_db_cluster_needs_master_username():
@mock_rds @mock_rds
def test_create_db_cluster_needs_master_user_password(): def test_create_db_cluster_needs_master_user_password():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
with pytest.raises(ClientError) as ex: with pytest.raises(ClientError) as ex:
client.create_db_cluster( client.create_db_cluster(
@ -59,7 +61,7 @@ def test_create_db_cluster_needs_master_user_password():
@mock_rds @mock_rds
def test_create_db_cluster_needs_long_master_user_password(): def test_create_db_cluster_needs_long_master_user_password():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
with pytest.raises(ClientError) as ex: with pytest.raises(ClientError) as ex:
client.create_db_cluster( client.create_db_cluster(
@ -78,7 +80,7 @@ def test_create_db_cluster_needs_long_master_user_password():
@mock_rds @mock_rds
def test_modify_db_cluster_needs_long_master_user_password(): def test_modify_db_cluster_needs_long_master_user_password():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
client.create_db_cluster( client.create_db_cluster(
DBClusterIdentifier="cluster-id", DBClusterIdentifier="cluster-id",
@ -102,7 +104,7 @@ def test_modify_db_cluster_needs_long_master_user_password():
@mock_rds @mock_rds
def test_modify_db_cluster_new_cluster_identifier(): def test_modify_db_cluster_new_cluster_identifier():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
old_id = "cluster-id" old_id = "cluster-id"
new_id = "new-cluster-id" new_id = "new-cluster-id"
@ -131,7 +133,7 @@ def test_modify_db_cluster_new_cluster_identifier():
@mock_rds @mock_rds
def test_create_db_cluster__verify_default_properties(): def test_create_db_cluster__verify_default_properties():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
resp = client.create_db_cluster( resp = client.create_db_cluster(
DBClusterIdentifier="cluster-id", DBClusterIdentifier="cluster-id",
@ -198,7 +200,7 @@ def test_create_db_cluster__verify_default_properties():
@mock_rds @mock_rds
def test_create_db_cluster_additional_parameters(): def test_create_db_cluster_additional_parameters():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
resp = client.create_db_cluster( resp = client.create_db_cluster(
AvailabilityZones=["eu-north-1b"], AvailabilityZones=["eu-north-1b"],
@ -253,7 +255,7 @@ def test_create_db_cluster_additional_parameters():
@mock_rds @mock_rds
def test_describe_db_cluster_after_creation(): def test_describe_db_cluster_after_creation():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
client.create_db_cluster( client.create_db_cluster(
DBClusterIdentifier="cluster-id1", DBClusterIdentifier="cluster-id1",
@ -286,7 +288,7 @@ def test_describe_db_cluster_after_creation():
@mock_rds @mock_rds
def test_delete_db_cluster(): def test_delete_db_cluster():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
client.create_db_cluster( client.create_db_cluster(
DBClusterIdentifier="cluster-id", DBClusterIdentifier="cluster-id",
@ -302,7 +304,7 @@ def test_delete_db_cluster():
@mock_rds @mock_rds
def test_delete_db_cluster_do_snapshot(): def test_delete_db_cluster_do_snapshot():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
client.create_db_cluster( client.create_db_cluster(
DBClusterIdentifier="cluster-id", DBClusterIdentifier="cluster-id",
@ -323,7 +325,7 @@ def test_delete_db_cluster_do_snapshot():
@mock_rds @mock_rds
def test_delete_db_cluster_that_is_protected(): def test_delete_db_cluster_that_is_protected():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
client.create_db_cluster( client.create_db_cluster(
DBClusterIdentifier="cluster-id", DBClusterIdentifier="cluster-id",
@ -341,7 +343,7 @@ def test_delete_db_cluster_that_is_protected():
@mock_rds @mock_rds
def test_delete_db_cluster_unknown_cluster(): def test_delete_db_cluster_unknown_cluster():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
with pytest.raises(ClientError) as ex: with pytest.raises(ClientError) as ex:
client.delete_db_cluster(DBClusterIdentifier="cluster-unknown") client.delete_db_cluster(DBClusterIdentifier="cluster-unknown")
@ -352,7 +354,7 @@ def test_delete_db_cluster_unknown_cluster():
@mock_rds @mock_rds
def test_start_db_cluster_unknown_cluster(): def test_start_db_cluster_unknown_cluster():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
with pytest.raises(ClientError) as ex: with pytest.raises(ClientError) as ex:
client.start_db_cluster(DBClusterIdentifier="cluster-unknown") client.start_db_cluster(DBClusterIdentifier="cluster-unknown")
@ -363,7 +365,7 @@ def test_start_db_cluster_unknown_cluster():
@mock_rds @mock_rds
def test_start_db_cluster_after_stopping(): def test_start_db_cluster_after_stopping():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
client.create_db_cluster( client.create_db_cluster(
DBClusterIdentifier="cluster-id", DBClusterIdentifier="cluster-id",
@ -380,7 +382,7 @@ def test_start_db_cluster_after_stopping():
@mock_rds @mock_rds
def test_start_db_cluster_without_stopping(): def test_start_db_cluster_without_stopping():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
client.create_db_cluster( client.create_db_cluster(
DBClusterIdentifier="cluster-id", DBClusterIdentifier="cluster-id",
@ -398,7 +400,7 @@ def test_start_db_cluster_without_stopping():
@mock_rds @mock_rds
def test_stop_db_cluster(): def test_stop_db_cluster():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
client.create_db_cluster( client.create_db_cluster(
DBClusterIdentifier="cluster-id", DBClusterIdentifier="cluster-id",
@ -419,7 +421,7 @@ def test_stop_db_cluster():
@mock_rds @mock_rds
def test_stop_db_cluster_already_stopped(): def test_stop_db_cluster_already_stopped():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
client.create_db_cluster( client.create_db_cluster(
DBClusterIdentifier="cluster-id", DBClusterIdentifier="cluster-id",
@ -439,7 +441,7 @@ def test_stop_db_cluster_already_stopped():
@mock_rds @mock_rds
def test_stop_db_cluster_unknown_cluster(): def test_stop_db_cluster_unknown_cluster():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
with pytest.raises(ClientError) as ex: with pytest.raises(ClientError) as ex:
client.stop_db_cluster(DBClusterIdentifier="cluster-unknown") client.stop_db_cluster(DBClusterIdentifier="cluster-unknown")
@ -807,7 +809,7 @@ def test_add_tags_to_cluster_snapshot():
@mock_rds @mock_rds
def test_create_serverless_db_cluster(): def test_create_serverless_db_cluster():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
resp = client.create_db_cluster( resp = client.create_db_cluster(
DBClusterIdentifier="cluster-id", DBClusterIdentifier="cluster-id",
@ -831,7 +833,7 @@ def test_create_serverless_db_cluster():
@mock_rds @mock_rds
def test_create_db_cluster_with_enable_http_endpoint_invalid(): def test_create_db_cluster_with_enable_http_endpoint_invalid():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
resp = client.create_db_cluster( resp = client.create_db_cluster(
DBClusterIdentifier="cluster-id", DBClusterIdentifier="cluster-id",
@ -850,7 +852,7 @@ def test_create_db_cluster_with_enable_http_endpoint_invalid():
@mock_rds @mock_rds
def test_describe_db_clusters_filter_by_engine(): def test_describe_db_clusters_filter_by_engine():
client = boto3.client("rds", region_name="eu-north-1") client = boto3.client("rds", region_name=RDS_REGION)
client.create_db_cluster( client.create_db_cluster(
DBClusterIdentifier="id1", DBClusterIdentifier="id1",
@ -922,3 +924,37 @@ def test_replicate_cluster():
replica = us_west.describe_db_clusters()["DBClusters"][0] replica = us_west.describe_db_clusters()["DBClusters"][0]
assert "ReplicationSourceIdentifier" not in replica assert "ReplicationSourceIdentifier" not in replica
assert replica["MultiAZ"] is False assert replica["MultiAZ"] is False
@mock_rds
def test_createdb_instance_engine_mismatch_fail():
# Setup
client = boto3.client("rds", "us-east-1")
cluster_name = "test-cluster"
client.create_db_cluster(
DBClusterIdentifier=cluster_name,
Engine="aurora-postgresql",
EngineVersion="12.14",
MasterUsername="testuser",
MasterUserPassword="password",
)
# Execute
with pytest.raises(ClientError) as exc:
client.create_db_instance(
DBClusterIdentifier=cluster_name,
Engine="mysql",
EngineVersion="12.14",
DBInstanceIdentifier="test-instance",
DBInstanceClass="db.t4g.medium",
)
# Verify
err = exc.value.response["Error"]
assert err["Code"] == "InvalidParameterCombination"
assert (
err["Message"]
== "The engine name requested for your DB instance (mysql) doesn't match "
"the engine name of your DB cluster (aurora-postgresql)."
)

View File

@ -21,7 +21,7 @@ def test_add_instance_as_cluster_member():
DBInstanceIdentifier="dbi", DBInstanceIdentifier="dbi",
DBClusterIdentifier="dbci", DBClusterIdentifier="dbci",
DBInstanceClass="db.r5.large", DBInstanceClass="db.r5.large",
Engine="aurora-postgresql", Engine="mysql",
) )
cluster = client.describe_db_clusters()["DBClusters"][0] cluster = client.describe_db_clusters()["DBClusters"][0]
@ -53,7 +53,7 @@ def test_remove_instance_from_cluster():
DBInstanceIdentifier="dbi", DBInstanceIdentifier="dbi",
DBClusterIdentifier="dbci", DBClusterIdentifier="dbci",
DBInstanceClass="db.r5.large", DBInstanceClass="db.r5.large",
Engine="aurora-postgresql", Engine="mysql",
) )
client.delete_db_instance( client.delete_db_instance(