diff --git a/meta/runtime.yml b/meta/runtime.yml index 1ce60f237a0..97e061bf88f 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -98,6 +98,7 @@ action_groups: - lambda_policy - rds_cluster - rds_cluster_info + - rds_global_cluster_info - rds_cluster_snapshot - rds_instance - rds_instance_info diff --git a/plugins/modules/rds_global_cluster_info.py b/plugins/modules/rds_global_cluster_info.py new file mode 100644 index 00000000000..e7fc827115f --- /dev/null +++ b/plugins/modules/rds_global_cluster_info.py @@ -0,0 +1,200 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 Ansible Project +# Copyright (c) 2023 Gomathi Selvi Srinivasan (@GomathiselviS) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +DOCUMENTATION = r""" +module: rds_global_cluster_info +version_added: 7.0.0 +short_description: Obtain information about Aurora global database clusters +description: + - Obtain information about Aurora global database clusters. +options: + global_cluster_identifier: + description: + - The user-supplied Global DB cluster identifier. + - If this parameter is specified, information from only the specific DB cluster is returned. + - This parameter is not case-sensitive. + - If supplied, must match an existing DBClusterIdentifier. + type: str + +author: + - Gomathi Selvi Srinivasan (@GomathiselviS) +notes: + - While developing this module, describe_global_cluster CLI did not yield any tag information. + - Consequently, the "tags" parameter is not included in this module. +extends_documentation_fragment: + - amazon.aws.common.modules + - amazon.aws.region.modules + - amazon.aws.boto3 +""" + +EXAMPLES = r""" +- name: Get info of all existing DB clusters + amazon.aws.rds_global_cluster_info: + register: _result_cluster_info + +- name: Get info on a specific DB cluster + amazon.aws.rds_global_cluster_info: + global_cluster_identifier: "{{ cluster_id }}" + register: _result_global_cluster_info + +""" + +RETURN = r""" +global_clusters: + description: List of global clusters. + returned: always + type: list + elements: dict + contains: + global_cluster_identifier: + description: User-supplied global database cluster identifier. + type: str + sample: "ansible-test-global-cluster" + global_cluster_resource_id: + description: + - The Amazon Web Services Region-unique, immutable identifier for the global database cluster. + type: str + sample: cluster-xxx + global_cluster_arn: + description: + - The Amazon Resource Name (ARN) for the global database cluster. + type: str + sample: "arn:aws:rds::xxx:global-cluster:ansible-test-global-cluster" + status: + description: The status of the DB cluster. + type: str + sample: available + engine: + description: The database engine of the DB cluster. + type: str + sample: aurora-postgresql + engine_version: + description: The database engine version. + type: str + sample: 14.8 + storage_encrypted: + description: Whether the DB cluster is storage encrypted. + type: bool + sample: false + deletion_protection: + description: + - Indicates if the DB cluster has deletion protection enabled. + The database can't be deleted when deletion protection is enabled. + type: bool + sample: false + gloabl_cluster_members: + description: + - The list of primary and secondary clusters within the global database + cluster. + type: list + elements: dict + contains: + db_cluster_arn: + description: The Amazon Resource Name (ARN) for each Aurora DB cluster in the global cluster. + type: str + sample: arn:aws:rds:us-east-1:123456789012:cluster:ansible-test-primary + readers: + description: The Amazon Resource Name (ARN) for each read-only secondary cluster associated with the global cluster. + type: list + elements: str + sample: arn:aws:rds:us-east-2:123456789012:cluster:ansible-test-secondary + is_writer: + description: + - Indicates whether the Aurora DB cluster is the primary cluster for the global cluster with which it is associated. + type: bool + sample: false + global_write_forwarding_status: + description: The status of write forwarding for a secondary cluster in the global cluster. + type: str + sample: disabled + failover_state: + description: + - A data object containing all properties for the current state of an in-process or + pending switchover or failover process for this global cluster (Aurora global database). + - This object is empty unless the SwitchoverGlobalCluster or FailoverGlobalCluster operation was called on this global cluster. + type: dict + contains: + status: + description: + - The current status of the global cluster. + type: str + sample: "pending" + from_db_cluster_arn: + description: The Amazon Resource Name (ARN) of the Aurora DB cluster that is currently being demoted, and which is associated with this state. + type: str + sample: arn:aws:rds:us-east-1:123456789012:cluster:ansible-test-primary + to_db_cluster_arn: + description: The Amazon Resource Name (ARN) of the Aurora DB cluster that is currently being promoted, and which is associated with this state. + type: str + sample: arn:aws:rds:us-east-2:123456789012:cluster:ansible-test-secondary + is_data_loss_allowed: + description: + - Indicates whether the operation is a global switchover or a global failover. + - If data loss is allowed, then the operation is a global failover. Otherwise, it is a switchover. + type: bool + sample: false +""" + + +try: + import botocore +except ImportError: + pass # handled by AnsibleAWSModule + +from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict + +from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code +from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry + + +@AWSRetry.jittered_backoff(retries=10) +def _describe_global_clusters(client, **params): + try: + paginator = client.get_paginator("describe_global_clusters") + return paginator.paginate(**params).build_full_result()["GlobalClusters"] + except is_boto3_error_code("GlobalClusterNotFoundFault"): + return [] + + +def cluster_info(client, module): + global_cluster_id = module.params.get("global_cluster_identifier") + + params = dict() + if global_cluster_id: + params["GlobalClusterIdentifier"] = global_cluster_id + + try: + result = _describe_global_clusters(client, **params) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, "Couldn't get Global cluster information.") + + return dict( + changed=False, global_clusters=[camel_dict_to_snake_dict(cluster, ignore_list=["Tags"]) for cluster in result] + ) + + +def main(): + argument_spec = dict( + global_cluster_identifier=dict(), + ) + + module = AnsibleAWSModule( + argument_spec=argument_spec, + supports_check_mode=True, + ) + + try: + client = module.client("rds", retry_decorator=AWSRetry.jittered_backoff(retries=10)) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Failed to connect to AWS.") + + module.exit_json(**cluster_info(client, module)) + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/rds_global_cluster_create/aliases b/tests/integration/targets/rds_global_cluster_create/aliases new file mode 100644 index 00000000000..41096e9b970 --- /dev/null +++ b/tests/integration/targets/rds_global_cluster_create/aliases @@ -0,0 +1,6 @@ +# Multi region not supported in the CI AWS account +disabled +time=20m +cloud/aws +rds_cluster +rds_global_cluster_info diff --git a/tests/integration/targets/rds_global_cluster_create/defaults/main.yml b/tests/integration/targets/rds_global_cluster_create/defaults/main.yml new file mode 100644 index 00000000000..ed6ed7b34c4 --- /dev/null +++ b/tests/integration/targets/rds_global_cluster_create/defaults/main.yml @@ -0,0 +1,12 @@ +# defaults file for rds_global_cluster_create + +# Create cluster +global_cluster_id: global-cluster-{{ resource_prefix }} +primary_cluster_id: primary-cluster-{{ resource_prefix }} +primary_instance_id: primary-instance-{{ resource_prefix }} +secondary_cluster_id: secondary-cluster-{{ resource_prefix }} +instance_class: db.r5.large +username: testrdsusername +password: testrdspassword +engine: aurora-mysql +engine_version: 5.7 diff --git a/tests/integration/targets/rds_global_cluster_create/tasks/main.yaml b/tests/integration/targets/rds_global_cluster_create/tasks/main.yaml new file mode 100644 index 00000000000..6f34d3782b4 --- /dev/null +++ b/tests/integration/targets/rds_global_cluster_create/tasks/main.yaml @@ -0,0 +1,108 @@ +- module_defaults: + group/aws: + region: "{{ aws_region }}" + access_key: "{{ aws_access_key }}" + secret_key: "{{ aws_secret_key }}" + session_token: "{{ security_token | default(omit) }}" + group/amazon.cloud.aws: + aws_access_key: "{{ aws_access_key }}" + aws_secret_key: "{{ aws_secret_key }}" + security_token: "{{ security_token | default(omit) }}" + region: "{{ aws_region }}" + block: + - name: Create aurora global cluster + amazon.cloud.rds_global_cluster: + global_cluster_identifier: "{{ global_cluster_id }}" + engine: "{{ engine }}" + engine_version: "{{ engine_version }}" + region: "{{ aws_region }}" + state: present + + - name: Create a primary cluster for global database + amazon.aws.rds_cluster: + db_cluster_identifier: "{{ primary_cluster_id }}" + engine: "{{ engine }}" + engine_version: "{{ engine_version }}" + master_username: "{{ username }}" + master_user_password: "{{ password }}" + global_cluster_identifier: "{{ global_cluster_id }}" + region: "{{ aws_region }}" + register: primary_cluster + + - name: Create an instance connected to primary cluster + amazon.aws.rds_instance: + db_cluster_identifier: "{{ primary_cluster_id }}" + db_instance_identifier: "{{ primary_instance_id }}" + region: "{{ aws_region }}" + engine: "{{ engine }}" + db_instance_class: "{{ instance_class }}" + + - name: Create a read replica cluster for global database + amazon.aws.rds_cluster: + db_cluster_identifier: "{{ secondary_cluster_id }}" + region: "eu-north-1" + engine: "{{ engine }}" + engine_version: "{{ engine_version }}" + global_cluster_identifier: "{{ global_cluster_id }}" + register: replica_cluster + + - name: Get Global DB information + amazon.aws.rds_global_cluster_info: + global_cluster_identifier: "{{ global_cluster_id }}" + region: "{{ aws_region }}" + register: global_cluster_info + + - name: Get primary cluster info + amazon.aws.rds_cluster_info: + db_cluster_identifier: "{{ primary_cluster_id }}" + region: "{{ aws_region }}" + register: primary_cluster_info_result + + - name: Get secondary cluster info + amazon.aws.rds_cluster_info: + db_cluster_identifier: "{{ secondary_cluster_id }}" + region: "eu-north-1" + register: secondary_cluster_info_result + + - name: Assert that the primary and secondary clusters are members of the global cluster + ansible.builtin.assert: + that: + - global_cluster_info.global_clusters[0].global_cluster_members[0].db_cluster_arn == primary_cluster_info_result.clusters[0].db_cluster_arn + - global_cluster_info.global_clusters[0].global_cluster_members[1].db_cluster_arn == secondary_cluster_info_result.clusters[0].db_cluster_arn + - global_cluster_info.global_clusters[0].engine == engine + + always: + - name: Delete secondary cluster without creating a final snapshot + amazon.aws.rds_cluster: + cluster_id: "{{ secondary_cluster_id }}" + region: "eu-north-1" + global_cluster_identifier: "{{ global_cluster_id }}" + remove_from_global_db: true + skip_final_snapshot: True + state: absent + ignore_errors: true + + - name: Delete instance attached to primary cluster + amazon.aws.rds_instance: + db_instance_identifier: "{{ primary_instance_id }}" + region: "{{ aws_region }}" + skip_final_snapshot: true + wait: false + state: absent + ignore_errors: true + + - name: Delete primary cluster without creating a final snapshot + amazon.aws.rds_cluster: + cluster_id: "{{ primary_cluster_id }}" + global_cluster_identifier: "{{ global_cluster_id }}" + skip_final_snapshot: True + region: "{{ aws_region }}" + state: absent + ignore_errors: true + + - name: Delete Global DB cluster + amazon.cloud.rds_global_cluster: + state: absent + global_cluster_identifier: "{{ global_cluster_id }}" + region: "{{ aws_region }}" + ignore_errors: true