Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rds_cluster: add support for removing cluster from global db #1705

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ac9376a
add support for removing cluster from global db
mandar242 Aug 22, 2023
577e878
add changelogs fragment
mandar242 Aug 22, 2023
c974a8f
make linter happy
mandar242 Aug 23, 2023
0319842
make linter happy
mandar242 Aug 23, 2023
bace6a6
add integration test
mandar242 Aug 24, 2023
1ca22c6
restructure code logic to make remove_from_global_db a flag and not a…
mandar242 Aug 31, 2023
e1f22ba
update integration tests as per new logic
mandar242 Aug 31, 2023
e168c2d
modified based on review
mandar242 Sep 5, 2023
fd0a073
wait for cluster state to be available only when wait=true
mandar242 Sep 5, 2023
eedaa25
replace static 'sleep' with custom waiter to wait for status to chang…
mandar242 Sep 6, 2023
1c641a8
add amazon.cloud to test requirements.yml
mandar242 Sep 6, 2023
53fcb46
update logic for wait when remove_from_global_db for primary and repl…
mandar242 Sep 8, 2023
492fdcd
remove unused new param added earlier
mandar242 Sep 8, 2023
ba071bc
change engine version to fix integration test failure
mandar242 Sep 11, 2023
6d5fffb
doc fix, add required_if for remove_from_global_db
mandar242 Sep 11, 2023
8b19ae4
change engine version to fix integration test failure
mandar242 Sep 11, 2023
d5e650d
fix integration tests
mandar242 Sep 12, 2023
cc7091e
add another example
mandar242 Sep 13, 2023
b327e09
update logic to allow update without wait on remove_from_global_db
mandar242 Sep 19, 2023
d5ad59e
sanity fix
mandar242 Sep 20, 2023
6096c93
minor fix
mandar242 Sep 20, 2023
55b096e
minor fix
mandar242 Sep 20, 2023
0e748d8
modify as suggested
mandar242 Sep 21, 2023
3d4b523
increase wait time and retries
mandar242 Sep 26, 2023
3fa1d7a
fix edge case
mandar242 Sep 26, 2023
7844a8f
minor fix
mandar242 Sep 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
minor_changes:
- rds_cluster - Add support for removing cluster from global db (https://github.com/ansible-collections/amazon.aws/pull/1705).
2 changes: 2 additions & 0 deletions plugins/module_utils/rds.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ def get_rds_method_attribute(method_name, module):
waiter = "role_disassociated"
elif method_name == "promote_read_replica":
waiter = "read_replica_promoted"
elif method_name == "db_cluster_promoting":
waiter = "db_cluster_promoting"
else:
waiter = "db_instance_available"
# Handle retry codes
Expand Down
18 changes: 18 additions & 0 deletions plugins/module_utils/waiters.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,19 @@
rds_data = {
"version": 2,
"waiters": {
"DBClusterPromoting": {
"delay": 5,
"maxAttempts": 60,
"operation": "DescribeDBClusters",
"acceptors": [
{
"state": "success",
"matcher": "pathAll",
"argument": "DBClusters[].Status",
"expected": "promoting",
},
],
},
"DBInstanceStopped": {
"delay": 20,
"maxAttempts": 60,
Expand Down Expand Up @@ -911,6 +924,11 @@ def route53_model(name):
elbv2_model("LoadBalancersDeleted"),
core_waiter.NormalizedOperationMethod(elbv2.describe_load_balancers),
),
("RDS", "db_cluster_promoting"): lambda rds: core_waiter.Waiter(
"db_cluster_promoting",
rds_model("DBClusterPromoting"),
core_waiter.NormalizedOperationMethod(rds.describe_db_clusters),
),
("RDS", "db_instance_stopped"): lambda rds: core_waiter.Waiter(
"db_instance_stopped",
rds_model("DBInstanceStopped"),
Expand Down
85 changes: 84 additions & 1 deletion plugins/modules/rds_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,13 @@
aliases:
- maintenance_window
type: str
remove_from_global_db:
description:
mandar242 marked this conversation as resolved.
Show resolved Hide resolved
- If set to C(true), the cluster will be removed from global DB.
- Parameters I(global_cluster_identifier), I(db_cluster_identifier) must be specified when I(remove_from_global_db=true).
type: bool
required: False
mandar242 marked this conversation as resolved.
Show resolved Hide resolved
version_added: 6.5.0
replication_source_identifier:
description:
- The Amazon Resource Name (ARN) of the source DB instance or DB cluster if this DB cluster is created as a Read Replica.
Expand Down Expand Up @@ -463,6 +470,42 @@
engine: aurora-postgresql
state: present
db_instance_class: 'db.t3.medium'

- name: Remove a cluster from global DB (do not delete)
amazon.aws.rds_cluster:
db_cluster_identifier: '{{ cluster_id }}'
global_cluster_identifier: '{{ global_cluster_id }}'
remove_from_global_db: true

- name: Remove a cluster from global DB and Delete without creating a final snapshot
amazon.aws.rds_cluster:
engine: aurora
password: "{{ password }}"
username: "{{ username }}"
cluster_id: "{{ cluster_id }}"
skip_final_snapshot: true
remove_from_global_db: true
wait: true
state: absent
mandar242 marked this conversation as resolved.
Show resolved Hide resolved

- name: Update cluster port and WAIT for remove secondary DB cluster from global DB to complete
amazon.aws.rds_cluster:
db_cluster_identifier: "{{ secondary_cluster_name }}"
global_cluster_identifier: "{{ global_cluster_name }}"
remove_from_global_db: true
state: present
port: 3389
region: "{{ secondary_cluster_region }}"

- name: Update cluster port and DO NOT WAIT for remove secondary DB cluster from global DB to complete
amazon.aws.rds_cluster:
db_cluster_identifier: "{{ secondary_cluster_name }}"
global_cluster_identifier: "{{ global_cluster_name }}"
remove_from_global_db: true
state: present
port: 3389
region: "{{ secondary_cluster_region }}"
wait: false
"""

RETURN = r"""
Expand Down Expand Up @@ -1102,6 +1145,33 @@ def ensure_present(cluster, parameters, method_name, method_options_name):
return changed


def handle_remove_from_global_db(module, cluster):
global_cluster_id = module.params.get("global_cluster_identifier")
db_cluster_id = module.params.get("db_cluster_identifier")
db_cluster_arn = cluster["DBClusterArn"]

if module.check_mode:
return True

try:
client.remove_from_global_cluster(DbClusterIdentifier=db_cluster_arn, GlobalClusterIdentifier=global_cluster_id)
except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e:
module.fail_json_aws(
e, msg=f"Failed to remove cluster {db_cluster_id} from global DB cluster {global_cluster_id}."
)

# for replica cluster - wait for cluster to change status from 'available' to 'promoting'
# only replica/secondary clusters have "GlobalWriteForwardingStatus" field
if "GlobalWriteForwardingStatus" in cluster:
wait_for_cluster_status(client, module, db_cluster_id, "db_cluster_promoting")

# if wait=true, wait for db cluster remove from global db operation to complete
if module.params.get("wait"):
wait_for_cluster_status(client, module, db_cluster_id, "cluster_available")

return True


def main():
global module
global client
Expand Down Expand Up @@ -1154,6 +1224,7 @@ def main():
port=dict(type="int"),
preferred_backup_window=dict(aliases=["backup_window"]),
preferred_maintenance_window=dict(aliases=["maintenance_window"]),
remove_from_global_db=dict(type="bool"),
replication_source_identifier=dict(aliases=["replication_src_id"]),
restore_to_time=dict(),
restore_type=dict(choices=["full-copy", "copy-on-write"]),
Expand Down Expand Up @@ -1190,6 +1261,7 @@ def main():
required_if=[
["creation_source", "snapshot", ["snapshot_identifier", "engine"]],
["creation_source", "s3", required_by_s3_creation_source],
["remove_from_global_db", True, ["global_cluster_identifier", "db_cluster_identifier"]],
],
mutually_exclusive=[
["s3_bucket_name", "source_db_cluster_identifier", "snapshot_identifier"],
Expand Down Expand Up @@ -1245,12 +1317,17 @@ def main():
msg="skip_final_snapshot is False but all of the following are missing: final_snapshot_identifier"
)

parameters = arg_spec_to_rds_params(dict((k, module.params[k]) for k in module.params if k in parameter_options))
changed = False

parameters = arg_spec_to_rds_params(dict((k, module.params[k]) for k in module.params if k in parameter_options))
method_name, method_options_name = get_rds_method_attribute_name(cluster)

if method_name:
if method_name == "delete_db_cluster":
if cluster and module.params.get("remove_from_global_db"):
if cluster["Engine"] in ["aurora", "aurora-mysql", "aurora-postgresql"]:
mandar242 marked this conversation as resolved.
Show resolved Hide resolved
changed = handle_remove_from_global_db(module, cluster)

call_method(client, module, method_name, eval(method_options_name)(parameters))
changed = True
else:
Expand All @@ -1261,6 +1338,12 @@ def main():
else:
cluster_id = module.params["db_cluster_identifier"]

if cluster_id and get_cluster(cluster_id) and module.params.get("remove_from_global_db"):
if cluster["Engine"] in ["aurora", "aurora-mysql", "aurora-postgresql"]:
if changed:
wait_for_cluster_status(client, module, cluster_id, "cluster_available")
GomathiselviS marked this conversation as resolved.
Show resolved Hide resolved
changed |= handle_remove_from_global_db(module, cluster)

result = camel_dict_to_snake_dict(get_cluster(cluster_id))

if result:
Expand Down
1 change: 1 addition & 0 deletions tests/integration/requirements.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
collections:
- ansible.windows
- ansible.utils # ipv6 filter
- amazon.cloud # used by integration tests - rds_cluster_modify
17 changes: 17 additions & 0 deletions tests/integration/targets/rds_cluster_modify/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,20 @@ new_cluster_id: ansible-test-cluster-{{ tiny_prefix }}-new
new_port: 1155
new_password: test-rds_password-new
new_db_parameter_group_name: ansible-test-db-parameter-group-{{ tiny_prefix }}-new

test_engine: aurora-mysql
test_engine_version: 8.0
test_instance_class: db.r5.large

# Global cluster parameters ================================
test_global_cluster_name: ansible-test-global-{{ tiny_prefix }}

# Primary cluster parameters ================================
test_primary_cluster_name: ansible-test-primary-{{ tiny_prefix }}
test_primary_cluster_region: us-west-2
test_primary_cluster_instance_name: ansible-test-instance-primary-{{ tiny_prefix }}

# Replica cluster parameters ================================
test_replica_cluster_name: ansible-test-replica-{{ tiny_prefix }}
test_replica_cluster_region: eu-north-1
test_replica_cluster_instance_name: ansible-test-instance-replica-{{ tiny_prefix }}
8 changes: 7 additions & 1 deletion tests/integration/targets/rds_cluster_modify/tasks/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
secret_key: '{{ aws_secret_key }}'
session_token: '{{ security_token | default(omit) }}'
block:

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need group/amazon.cloud.aws under module_defaults for the amazon.cloud module to work?

Copy link
Contributor Author

@mandar242 mandar242 Sep 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had discussed this with Jill, it worked locally without group/amazon.cloud.aws after adding amazon.cloud to test requirements
https://github.com/ansible-collections/amazon.aws/pull/1705/files#diff-12ceb68f7a1282d864ebd30d4e5732b76b32fe7d3bdf77969043694f5b6346dfL3-R5

# Disabled: Below tests require use of more than 1 region, not supported by CI at the moment
# Tests have been ran, tested, and verified locally on us-west-2 (primary), eu-north-1 (replica)
# - name: Run tests for testing remove cluster from global db
# import_tasks: remove_from_global_db.yaml

- name: Ensure the resource doesn't exist
rds_cluster:
id: '{{ cluster_id }}'
Expand Down Expand Up @@ -177,7 +183,7 @@

- name: Create DB cluster parameter group if not exists
command: aws rds create-db-cluster-parameter-group --db-cluster-parameter-group-name
{{ new_db_parameter_group_name }} --db-parameter-group-family aurora-mysql5.7 --description
{{ new_db_parameter_group_name }} --db-parameter-group-family aurora-mysql8.0 --description
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: updated the engine version due to following failure seen in integration tests


2023-09-11 20:41:13.346386 | controller |   "msg": "Unable to modify DB cluster: An error occurred 
(InvalidParameterCombination) when calling the ModifyDBCluster operation: The Parameter Group 
ansible-test-db-parameter-group-e096d2ecba72-new with DBParameterGroupFamily aurora-mysql5.7 
cannot be used for this instance. Please use a Parameter Group with DBParameterGroupFamily
 aurora-mysql8.0",


"Test DB cluster parameter group"
environment:
AWS_ACCESS_KEY_ID: '{{ aws_access_key }}'
Expand Down
Loading
Loading