RDS: improve global clustering behaviour (#6403)
This commit is contained in:
parent
932b7a25d6
commit
a15b14085b
@ -78,7 +78,7 @@ class GlobalCluster(BaseModel):
|
|||||||
self.deletion_protection = (
|
self.deletion_protection = (
|
||||||
deletion_protection and deletion_protection.lower() == "true"
|
deletion_protection and deletion_protection.lower() == "true"
|
||||||
)
|
)
|
||||||
self.members: List[str] = []
|
self.members: List[Cluster] = []
|
||||||
|
|
||||||
def to_xml(self) -> str:
|
def to_xml(self) -> str:
|
||||||
template = Template(
|
template = Template(
|
||||||
@ -92,10 +92,18 @@ class GlobalCluster(BaseModel):
|
|||||||
<StorageEncrypted>{{ 'true' if cluster.storage_encrypted else 'false' }}</StorageEncrypted>
|
<StorageEncrypted>{{ 'true' if cluster.storage_encrypted else 'false' }}</StorageEncrypted>
|
||||||
<DeletionProtection>{{ 'true' if cluster.deletion_protection else 'false' }}</DeletionProtection>
|
<DeletionProtection>{{ 'true' if cluster.deletion_protection else 'false' }}</DeletionProtection>
|
||||||
<GlobalClusterMembers>
|
<GlobalClusterMembers>
|
||||||
{% for cluster_arn in cluster.members %}
|
{% for cluster_member in cluster.members %}
|
||||||
<GlobalClusterMember>
|
<GlobalClusterMember>
|
||||||
<DBClusterArn>{{ cluster_arn }}</DBClusterArn>
|
<DBClusterArn>{{ cluster_member.db_cluster_arn }}</DBClusterArn>
|
||||||
<IsWriter>true</IsWriter>
|
<IsWriter>{{ 'true' if cluster_member.is_writer else 'false' }}</IsWriter>
|
||||||
|
{% if not cluster_member.is_writer %}<GlobalWriteForwardingStatus>disabled</GlobalWriteForwardingStatus>{% endif %}
|
||||||
|
<Readers>
|
||||||
|
{% if cluster_member.is_writer %}
|
||||||
|
{% for reader in cluster.members %}
|
||||||
|
{% if not reader.is_writer %}<Reader>{{ reader.db_cluster_arn }}</Reader>{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</Readers>
|
||||||
</GlobalClusterMember>
|
</GlobalClusterMember>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</GlobalClusterMembers>
|
</GlobalClusterMembers>
|
||||||
@ -141,11 +149,15 @@ class Cluster:
|
|||||||
engine=self.engine, storage_type=self.storage_type # type: ignore
|
engine=self.engine, storage_type=self.storage_type # type: ignore
|
||||||
)
|
)
|
||||||
self.master_username = kwargs.get("master_username")
|
self.master_username = kwargs.get("master_username")
|
||||||
if not self.master_username:
|
self.global_cluster_identifier = kwargs.get("global_cluster_identifier")
|
||||||
|
if not self.master_username and self.global_cluster_identifier:
|
||||||
|
pass
|
||||||
|
elif not self.master_username:
|
||||||
raise InvalidParameterValue(
|
raise InvalidParameterValue(
|
||||||
"The parameter MasterUsername must be provided and must not be blank."
|
"The parameter MasterUsername must be provided and must not be blank."
|
||||||
)
|
)
|
||||||
self.master_user_password = kwargs.get("master_user_password") # type: ignore
|
else:
|
||||||
|
self.master_user_password = kwargs.get("master_user_password") # type: ignore
|
||||||
|
|
||||||
self.availability_zones = kwargs.get("availability_zones")
|
self.availability_zones = kwargs.get("availability_zones")
|
||||||
if not self.availability_zones:
|
if not self.availability_zones:
|
||||||
@ -194,10 +206,10 @@ class Cluster:
|
|||||||
"timeout_action": "RollbackCapacityChange",
|
"timeout_action": "RollbackCapacityChange",
|
||||||
"seconds_before_timeout": 300,
|
"seconds_before_timeout": 300,
|
||||||
}
|
}
|
||||||
self.global_cluster_identifier = kwargs.get("global_cluster_identifier")
|
|
||||||
self.cluster_members: List[str] = list()
|
self.cluster_members: List[str] = list()
|
||||||
self.replication_source_identifier = kwargs.get("replication_source_identifier")
|
self.replication_source_identifier = kwargs.get("replication_source_identifier")
|
||||||
self.read_replica_identifiers: List[str] = list()
|
self.read_replica_identifiers: List[str] = list()
|
||||||
|
self.is_writer: bool = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_multi_az(self) -> bool:
|
def is_multi_az(self) -> bool:
|
||||||
@ -2119,7 +2131,27 @@ class RDSBackend(BaseBackend):
|
|||||||
and cluster.global_cluster_identifier in self.global_clusters
|
and cluster.global_cluster_identifier in self.global_clusters
|
||||||
):
|
):
|
||||||
global_cluster = self.global_clusters[cluster.global_cluster_identifier]
|
global_cluster = self.global_clusters[cluster.global_cluster_identifier]
|
||||||
global_cluster.members.append(cluster.db_cluster_arn)
|
|
||||||
|
# Main DB cluster, does RW on global cluster
|
||||||
|
setattr(cluster, "is_writer", True)
|
||||||
|
# self.clusters[cluster_id] = cluster
|
||||||
|
global_cluster.members.append(cluster)
|
||||||
|
|
||||||
|
# search all backend to check if global cluster named global_cluster_identifier exists
|
||||||
|
# anywhere else
|
||||||
|
if (
|
||||||
|
cluster.global_cluster_identifier
|
||||||
|
and cluster.global_cluster_identifier not in self.global_clusters
|
||||||
|
):
|
||||||
|
for regional_backend in rds_backends[self.account_id]:
|
||||||
|
if (
|
||||||
|
cluster.global_cluster_identifier
|
||||||
|
in rds_backends[self.account_id][regional_backend].global_clusters
|
||||||
|
):
|
||||||
|
global_cluster = rds_backends[self.account_id][
|
||||||
|
regional_backend
|
||||||
|
].global_clusters[cluster.global_cluster_identifier]
|
||||||
|
global_cluster.members.append(cluster)
|
||||||
|
|
||||||
if cluster.replication_source_identifier:
|
if cluster.replication_source_identifier:
|
||||||
cluster_identifier = cluster.replication_source_identifier
|
cluster_identifier = cluster.replication_source_identifier
|
||||||
@ -2623,7 +2655,7 @@ class RDSBackend(BaseBackend):
|
|||||||
self.global_clusters[global_cluster_identifier] = global_cluster
|
self.global_clusters[global_cluster_identifier] = global_cluster
|
||||||
if source_cluster is not None:
|
if source_cluster is not None:
|
||||||
source_cluster.global_cluster_identifier = global_cluster.global_cluster_arn
|
source_cluster.global_cluster_identifier = global_cluster.global_cluster_arn
|
||||||
global_cluster.members.append(source_cluster.db_cluster_arn)
|
global_cluster.members.append(source_cluster)
|
||||||
return global_cluster
|
return global_cluster
|
||||||
|
|
||||||
def describe_global_clusters(self) -> List[GlobalCluster]:
|
def describe_global_clusters(self) -> List[GlobalCluster]:
|
||||||
@ -2650,7 +2682,7 @@ class RDSBackend(BaseBackend):
|
|||||||
cluster = self.describe_db_clusters(
|
cluster = self.describe_db_clusters(
|
||||||
cluster_identifier=db_cluster_identifier
|
cluster_identifier=db_cluster_identifier
|
||||||
)[0]
|
)[0]
|
||||||
global_cluster.members.remove(cluster.db_cluster_arn)
|
global_cluster.members.remove(cluster)
|
||||||
return global_cluster
|
return global_cluster
|
||||||
except: # noqa: E722 Do not use bare except
|
except: # noqa: E722 Do not use bare except
|
||||||
pass
|
pass
|
||||||
|
@ -91,6 +91,66 @@ def test_create_global_cluster_from_regular_cluster():
|
|||||||
assert global_cluster["GlobalClusterMembers"][0]["DBClusterArn"] == cluster_arn
|
assert global_cluster["GlobalClusterMembers"][0]["DBClusterArn"] == cluster_arn
|
||||||
|
|
||||||
|
|
||||||
|
@mock_rds
|
||||||
|
def test_create_global_cluster_from_regular_cluster_with_reader():
|
||||||
|
east_client = boto3.client("rds", "eu-west-1")
|
||||||
|
west_client = boto3.client("rds", "eu-west-2")
|
||||||
|
|
||||||
|
# Create global cluster
|
||||||
|
east_client.create_global_cluster(
|
||||||
|
GlobalClusterIdentifier="test-global-db",
|
||||||
|
Engine="aurora-mysql",
|
||||||
|
DeletionProtection=False,
|
||||||
|
DatabaseName="test-db",
|
||||||
|
StorageEncrypted=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
east_client.create_db_cluster(
|
||||||
|
DBClusterIdentifier="test-primary-cluster",
|
||||||
|
Engine="aurora-mysql",
|
||||||
|
GlobalClusterIdentifier="test-global-db",
|
||||||
|
MasterUsername="testUsername",
|
||||||
|
MasterUserPassword="testPassword",
|
||||||
|
)
|
||||||
|
|
||||||
|
east_client.create_db_instance(
|
||||||
|
DBInstanceIdentifier="test-primary-cluster-i1",
|
||||||
|
DBInstanceClass="db.r5.large",
|
||||||
|
Engine="aurora-mysql",
|
||||||
|
PubliclyAccessible=False,
|
||||||
|
DBClusterIdentifier="test-primary-cluster",
|
||||||
|
)
|
||||||
|
|
||||||
|
west_client.create_db_cluster(
|
||||||
|
DBClusterIdentifier="test-secondary-cluster",
|
||||||
|
Engine="aurora-mysql",
|
||||||
|
GlobalClusterIdentifier="test-global-db",
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = east_client.describe_global_clusters(
|
||||||
|
GlobalClusterIdentifier="test-global-db"
|
||||||
|
)
|
||||||
|
members = resp["GlobalClusters"][0]["GlobalClusterMembers"]
|
||||||
|
assert len(members) == 2
|
||||||
|
assert (
|
||||||
|
members[0]["DBClusterArn"]
|
||||||
|
== "arn:aws:rds:eu-west-1:123456789012:cluster:test-primary-cluster"
|
||||||
|
)
|
||||||
|
assert len(members[0]["Readers"]) == 1
|
||||||
|
assert (
|
||||||
|
members[0]["Readers"][0]
|
||||||
|
== "arn:aws:rds:eu-west-2:123456789012:cluster:test-secondary-cluster"
|
||||||
|
)
|
||||||
|
assert members[0]["IsWriter"]
|
||||||
|
|
||||||
|
assert (
|
||||||
|
members[1]["DBClusterArn"]
|
||||||
|
== "arn:aws:rds:eu-west-2:123456789012:cluster:test-secondary-cluster"
|
||||||
|
)
|
||||||
|
assert len(members[1]["Readers"]) == 0
|
||||||
|
assert not members[1]["IsWriter"]
|
||||||
|
|
||||||
|
|
||||||
@mock_rds
|
@mock_rds
|
||||||
def test_create_global_cluster_from_regular_cluster__using_name():
|
def test_create_global_cluster_from_regular_cluster__using_name():
|
||||||
client = boto3.client("rds", "us-east-1")
|
client = boto3.client("rds", "us-east-1")
|
||||||
|
Loading…
Reference in New Issue
Block a user