From 142836bd59a615ee597d1e9354cd62c12c023bae Mon Sep 17 00:00:00 2001 From: Alina Buzachis Date: Mon, 25 Oct 2021 16:51:49 +0200 Subject: [PATCH] rds_option_group (_info) new modules (#517) rds_option_group (_info) new modules SUMMARY Attempt to resurrect ansible/ansible#25290 Fixes: #463 ISSUE TYPE New Module Pull Request COMPONENT NAME rds_option_group rds_option_group_info Requires: mattclay/aws-terminator#144 Reviewed-by: Mark Chappell Reviewed-by: Alina Buzachis Reviewed-by: None --- meta/runtime.yml | 2 + plugins/modules/rds_option_group.py | 671 +++++++++++++ plugins/modules/rds_option_group_info.py | 327 +++++++ .../targets/rds_option_group/aliases | 3 + .../rds_option_group/defaults/main.yml | 18 + .../targets/rds_option_group/tasks/main.yml | 918 ++++++++++++++++++ 6 files changed, 1939 insertions(+) create mode 100644 plugins/modules/rds_option_group.py create mode 100644 plugins/modules/rds_option_group_info.py create mode 100644 tests/integration/targets/rds_option_group/aliases create mode 100644 tests/integration/targets/rds_option_group/defaults/main.yml create mode 100644 tests/integration/targets/rds_option_group/tasks/main.yml diff --git a/meta/runtime.yml b/meta/runtime.yml index 39685c11f83..bf736a3d34d 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -192,6 +192,8 @@ action_groups: - rds_snapshot - rds_snapshot_info - rds_subnet_group + - rds_option_group + - rds_option_group_info - redshift - redshift_cross_region_snapshots - redshift_info diff --git a/plugins/modules/rds_option_group.py b/plugins/modules/rds_option_group.py new file mode 100644 index 00000000000..3b01eaeda82 --- /dev/null +++ b/plugins/modules/rds_option_group.py @@ -0,0 +1,671 @@ +#!/usr/bin/python +# Copyright: Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +module: rds_option_group +short_description: rds_option_group module +version_added: 2.1.0 +description: + - Manages the creation, modification, deletion of RDS option groups. +author: + - "Nick Aslanidis (@naslanidis)" + - "Will Thames (@willthames)" + - "Alina Buzachis (@alinabuzachis)" +options: + state: + description: + - Specifies whether the option group should be C(present) or C(absent). + required: true + choices: [ 'present', 'absent' ] + type: str + option_group_name: + description: + - Specifies the name of the option group to be created. + required: true + type: str + engine_name: + description: + - Specifies the name of the engine that this option group should be associated with. + type: str + major_engine_version: + description: + - Specifies the major version of the engine that this option group should be associated with. + type: str + option_group_description: + description: + - The description of the option group. + type: str + apply_immediately: + description: + - Indicates whether the changes should be applied immediately, or during the next maintenance window. + required: false + type: bool + default: false + options: + description: + - Options in this list are added to the option group. + - If already present, the specified configuration is used to update the existing configuration. + - If none are supplied, any existing options are removed. + type: list + elements: dict + suboptions: + option_name: + description: The configuration of options to include in a group. + required: false + type: str + port: + description: The optional port for the option. + required: false + type: int + option_version: + description: The version for the option. + required: false + type: str + option_settings: + description: The option settings to include in an option group. + required: false + type: list + suboptions: + name: + description: The name of the option that has settings that you can set. + required: false + type: str + value: + description: The current value of the option setting. + required: false + type: str + default_value: + description: The default value of the option setting. + required: false + type: str + description: + description: The description of the option setting. + required: false + type: str + apply_type: + description: The DB engine specific parameter type. + required: false + type: str + data_type: + description: The data type of the option setting. + required: false + type: str + allowed_values: + description: The allowed values of the option setting. + required: false + type: str + is_modifiable: + description: A Boolean value that, when C(true), indicates the option setting can be modified from the default. + required: false + type: bool + is_collection: + description: Indicates if the option setting is part of a collection. + required: false + type: bool + db_security_group_memberships: + description: A list of C(DBSecurityGroupMembership) name strings used for this option. + required: false + type: list + vpc_security_group_memberships: + description: A list of C(VpcSecurityGroupMembership) name strings used for this option. + required: false + type: list + tags: + description: + - A dictionary of key value pairs to assign the option group. + - To remove all tags set I(tags={}) and I(purge_tags=true). + type: dict + purge_tags: + description: + - Remove tags not listed in I(tags). + type: bool + default: true + wait: + description: Whether to wait for the cluster to be available or deleted. + type: bool + default: True +extends_documentation_fragment: +- amazon.aws.aws +- amazon.aws.ec2 +''' + +EXAMPLES = r''' +# Create an RDS Mysql Option group +- name: Create an RDS Mysql option group + community.aws.rds_option_group: + state: present + option_group_name: test-mysql-option-group + engine_name: mysql + major_engine_version: 5.6 + option_group_description: test mysql option group + apply_immediately: true + options: + - option_name: MEMCACHED + port: 11211 + vpc_security_group_memberships: + - "sg-d188c123" + option_settings: + - name: MAX_SIMULTANEOUS_CONNECTIONS + value: "20" + - name: CHUNK_SIZE_GROWTH_FACTOR + value: "1.25" + register: new_rds_mysql_option_group + +# Remove currently configured options for an option group by removing options argument +- name: Create an RDS Mysql option group + community.aws.rds_option_group: + state: present + option_group_name: test-mysql-option-group + engine_name: mysql + major_engine_version: 5.6 + option_group_description: test mysql option group + apply_immediately: true + register: rds_mysql_option_group + +- name: Create an RDS Mysql option group using tags + community.aws.rds_option_group: + state: present + option_group_name: test-mysql-option-group + engine_name: mysql + major_engine_version: 5.6 + option_group_description: test mysql option group + apply_immediately: true + tags: + Tag1: tag1 + Tag2: tag2 + register: rds_mysql_option_group + +# Delete an RDS Mysql Option group +- name: Delete an RDS Mysql option group + community.aws.rds_option_group: + state: absent + option_group_name: test-mysql-option-group + register: deleted_rds_mysql_option_group +''' + +RETURN = r''' +allows_vpc_and_non_vpc_instance_memberships: + description: Indicates whether this option group can be applied to both VPC and non-VPC instances. + returned: always + type: bool + sample: false +changed: + description: If the Option Group has changed. + type: bool + returned: always + sample: true +engine_name: + description: Indicates the name of the engine that this option group can be applied to. + returned: always + type: str + sample: "mysql" +major_engine_version: + description: Indicates the major engine version associated with this option group. + returned: always + type: str + sample: "5.6" +option_group_arn: + description: The Amazon Resource Name (ARN) for the option group. + returned: always + type: str + sample: "arn:aws:rds:ap-southeast-2:721066863947:og:ansible-test-option-group" +option_group_description: + description: Provides a description of the option group. + returned: always + type: str + sample: "test mysql option group" +option_group_name: + description: Specifies the name of the option group. + returned: always + type: str + sample: "test-mysql-option-group" +options: + description: Indicates what options are available in the option group. + returned: always + type: list + elements: dict + contains: + db_security_group_memberships: + description: If the option requires access to a port, then this DB security group allows access to the port. + returned: always + type: list + elements: dict + contains: + status: + description: The status of the DB security group. + returned: always + type: str + sample: "available" + db_security_group_name: + description: The name of the DB security group. + returned: always + type: str + sample: "mydbsecuritygroup" + option_description: + description: The description of the option. + returned: always + type: str + sample: "Innodb Memcached for MySQL" + option_name: + description: The name of the option. + returned: always + type: str + sample: "MEMCACHED" + option_settings: + description: The name of the option. + returned: always + type: list + contains: + allowed_values: + description: The allowed values of the option setting. + returned: always + type: str + sample: "1-2048" + apply_type: + description: The DB engine specific parameter type. + returned: always + type: str + sample: "STATIC" + data_type: + description: The data type of the option setting. + returned: always + type: str + sample: "INTEGER" + default_value: + description: The default value of the option setting. + returned: always + type: str + sample: "1024" + description: + description: The description of the option setting. + returned: always + type: str + sample: "Verbose level for memcached." + is_collection: + description: Indicates if the option setting is part of a collection. + returned: always + type: bool + sample: true + is_modifiable: + description: A Boolean value that, when true, indicates the option setting can be modified from the default. + returned: always + type: bool + sample: true + name: + description: The name of the option that has settings that you can set. + returned: always + type: str + sample: "INNODB_API_ENABLE_MDL" + value: + description: The current value of the option setting. + returned: always + type: str + sample: "0" + permanent: + description: Indicate if this option is permanent. + returned: always + type: bool + sample: true + persistent: + description: Indicate if this option is persistent. + returned: always + type: bool + sample: true + port: + description: If required, the port configured for this option to use. + returned: always + type: int + sample: 11211 + vpc_security_group_memberships: + description: If the option requires access to a port, then this VPC security group allows access to the port. + returned: always + type: list + elements: dict + contains: + status: + description: The status of the VPC security group. + returned: always + type: str + sample: "available" + vpc_security_group_id: + description: The name of the VPC security group. + returned: always + type: str + sample: "sg-0cd636a23ae76e9a4" +vpc_id: + description: If present, this option group can only be applied to instances that are in the VPC indicated by this field. + returned: always + type: str + sample: "vpc-bf07e9d6" +tags: + description: The tags associated the Internet Gateway. + type: dict + returned: always + sample: { + "Ansible": "Test" + } +''' + + +from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import compare_aws_tags +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_tag_list +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict + +from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict +from ansible.module_utils.common.dict_transformations import snake_dict_to_camel_dict + +from ansible_collections.amazon.aws.plugins.module_utils.rds import get_tags + +try: + import botocore +except ImportError: + pass # caught by AnsibleAWSModule + + +@AWSRetry.jittered_backoff(retries=10) +def _describe_option_groups(client, **params): + try: + paginator = client.get_paginator('describe_option_groups') + return paginator.paginate(**params).build_full_result()['OptionGroupsList'][0] + except is_boto3_error_code('OptionGroupNotFoundFault'): + return {} + + +def get_option_group(client, module): + params = dict() + params['OptionGroupName'] = module.params.get('option_group_name') + + try: + result = camel_dict_to_snake_dict(_describe_option_groups(client, **params)) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Couldn't describe option groups.") + + if result: + result['tags'] = get_tags(client, module, result['option_group_arn']) + + return result + + +def create_option_group_options(client, module): + changed = True + params = dict() + params['OptionGroupName'] = module.params.get('option_group_name') + options_to_include = module.params.get('options') + params['OptionsToInclude'] = snake_dict_to_camel_dict(options_to_include, capitalize_first=True) + + if module.params.get('apply_immediately'): + params['ApplyImmediately'] = module.params.get('apply_immediately') + + if module.check_mode: + return changed + + try: + client.modify_option_group(aws_retry=True, **params) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Unable to update Option Group.") + + return changed + + +def remove_option_group_options(client, module, options_to_remove): + changed = True + params = dict() + params['OptionGroupName'] = module.params.get('option_group_name') + params['OptionsToRemove'] = options_to_remove + + if module.params.get('apply_immediately'): + params['ApplyImmediately'] = module.params.get('apply_immediately') + + if module.check_mode: + return changed + + try: + client.modify_option_group(aws_retry=True, **params) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e) + + return changed + + +def create_option_group(client, module): + changed = True + params = dict() + params['OptionGroupName'] = module.params.get('option_group_name') + params['EngineName'] = module.params.get('engine_name') + params['MajorEngineVersion'] = str(module.params.get('major_engine_version')) + params['OptionGroupDescription'] = module.params.get('option_group_description') + + if module.params.get('tags'): + params['Tags'] = ansible_dict_to_boto3_tag_list(module.params.get('tags')) + else: + params['Tags'] = list() + + if module.check_mode: + return changed + try: + client.create_option_group(aws_retry=True, **params) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg='Unable to create Option Group.') + + return changed + + +def match_option_group_options(client, module): + requires_update = False + new_options = module.params.get('options') + + # Get existing option groups and compare to our new options spec + current_option = get_option_group(client, module) + + if current_option['options'] == [] and new_options: + requires_update = True + else: + for option in current_option['options']: + for setting_name in new_options: + if setting_name['option_name'] == option['option_name']: + + # Security groups need to be handled separately due to different keys on request and what is + # returned by the API + if any( + name in option.keys() - ['option_settings', 'vpc_security_group_memberships'] and + setting_name[name] != option[name] + for name in setting_name + ): + requires_update = True + + if any( + name in option and name == 'vpc_security_group_memberships' + for name in setting_name + ): + current_sg = set(sg['vpc_security_group_id'] for sg in option['vpc_security_group_memberships']) + new_sg = set(setting_name['vpc_security_group_memberships']) + if current_sg != new_sg: + requires_update = True + + if any( + new_option_setting['name'] == current_option_setting['name'] and + new_option_setting['value'] != current_option_setting['value'] + for new_option_setting in setting_name['option_settings'] + for current_option_setting in option['option_settings'] + ): + requires_update = True + else: + requires_update = True + + return requires_update + + +def compare_option_group(client, module): + to_be_added = None + to_be_removed = None + current_option = get_option_group(client, module) + new_options = module.params.get('options') + new_settings = set([item['option_name'] for item in new_options]) + old_settings = set([item['option_name'] for item in current_option['options']]) + + if new_settings != old_settings: + to_be_added = list(new_settings - old_settings) + to_be_removed = list(old_settings - new_settings) + + return to_be_added, to_be_removed + + +def setup_option_group(client, module): + results = [] + changed = False + to_be_added = None + to_be_removed = None + + # Check if there is an existing options group + existing_option_group = get_option_group(client, module) + + if existing_option_group: + results = existing_option_group + + # Check tagging + changed |= update_tags(client, module, existing_option_group) + + if module.params.get('options'): + # Check if existing options require updating + update_required = match_option_group_options(client, module) + + # Check if there are options to be added or removed + if update_required: + to_be_added, to_be_removed = compare_option_group(client, module) + + if to_be_added or update_required: + changed |= create_option_group_options(client, module) + + if to_be_removed: + changed |= remove_option_group_options(client, module, to_be_removed) + + # If changed, get updated version of option group + if changed: + results = get_option_group(client, module) + else: + # No options were supplied. If options exist, remove them + current_option_group = get_option_group(client, module) + + if current_option_group['options'] != []: + # Here we would call our remove options function + options_to_remove = [] + + for option in current_option_group['options']: + options_to_remove.append(option['option_name']) + + changed |= remove_option_group_options(client, module, options_to_remove) + + # If changed, get updated version of option group + if changed: + results = get_option_group(client, module) + else: + changed = create_option_group(client, module) + + if module.params.get('options'): + changed = create_option_group_options(client, module) + + results = get_option_group(client, module) + + return changed, results + + +def remove_option_group(client, module): + changed = False + params = dict() + params['OptionGroupName'] = module.params.get('option_group_name') + + # Check if there is an existing options group + existing_option_group = get_option_group(client, module) + + if existing_option_group: + + if module.check_mode: + return True, {} + + changed = True + try: + client.delete_option_group(aws_retry=True, **params) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Unable to delete option group.") + + return changed, {} + + +def update_tags(client, module, option_group): + if module.params.get('tags') is None: + return False + + try: + existing_tags = client.list_tags_for_resource(aws_retry=True, ResourceName=option_group['option_group_arn'])['TagList'] + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Couldn't obtain option group tags.") + + to_update, to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(existing_tags), + module.params['tags'], module.params['purge_tags']) + changed = bool(to_update or to_delete) + + if to_update: + try: + if module.check_mode: + return changed + client.add_tags_to_resource(aws_retry=True, ResourceName=option_group['option_group_arn'], + Tags=ansible_dict_to_boto3_tag_list(to_update)) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Couldn't add tags to option group.") + if to_delete: + try: + if module.check_mode: + return changed + client.remove_tags_from_resource(aws_retry=True, ResourceName=option_group['option_group_arn'], + TagKeys=to_delete) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Couldn't remove tags from option group.") + + return changed + + +def main(): + argument_spec = dict( + option_group_name=dict(required=True, type='str'), + engine_name=dict(type='str'), + major_engine_version=dict(type='str'), + option_group_description=dict(type='str'), + options=dict(required=False, type='list', elements='dict'), + apply_immediately=dict(type='bool', default=False), + state=dict(required=True, choices=['present', 'absent']), + tags=dict(required=False, type='dict'), + purge_tags=dict(type='bool', default=True), + wait=dict(type='bool', default=True), + ) + + module = AnsibleAWSModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[['state', 'present', ['engine_name', 'major_engine_version', 'option_group_description']]], + ) + + try: + client = module.client('rds', retry_decorator=AWSRetry.jittered_backoff()) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg='Failed to connect to AWS.') + + state = module.params.get('state') + + if state == 'present': + changed, results = setup_option_group(client, module) + else: + changed, results = remove_option_group(client, module) + + module.exit_json(changed=changed, **results) + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/rds_option_group_info.py b/plugins/modules/rds_option_group_info.py new file mode 100644 index 00000000000..b29479386ff --- /dev/null +++ b/plugins/modules/rds_option_group_info.py @@ -0,0 +1,327 @@ +#!/usr/bin/python +# Copyright: Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: rds_option_group_info +short_description: rds_option_group_info module +version_added: 2.1.0 +description: + - Gather information about RDS option groups. +author: "Alina Buzachis (@alinabuzachis)" +options: + option_group_name: + description: + - The name of the option group to describe. + - Can't be supplied together with I(engine_name) or I(major_engine_version). + default: '' + required: false + type: str + marker: + description: + - If this parameter is specified, the response includes only records beyond the marker, up to the value specified by I(max_records). + - Allowed values are between C(20) and C(100). + default: '' + required: false + type: str + max_records: + description: + - The maximum number of records to include in the response. + type: int + default: 100 + required: false + engine_name: + description: Filters the list of option groups to only include groups associated with a specific database engine. + type: str + default: '' + required: false + major_engine_version: + description: + - Filters the list of option groups to only include groups associated with a specific database engine version. + - If specified, then I(engine_name) must also be specified. + type: str + default: '' + required: false +extends_documentation_fragment: +- amazon.aws.aws +- amazon.aws.ec2 +''' + +EXAMPLES = r''' +# Note: These examples do not set authentication details, see the AWS Guide for details. + +- name: List an option group + community.aws.rds_option_group_info: + option_group_name: test-mysql-option-group + register: option_group + +- name: List all the option groups + community.aws.rds_option_group_info: + region: ap-southeast-2 + profile: production + register: option_group +''' + +RETURN = r''' +changed: + description: True if listing the RDS option group succeeds. + type: bool + returned: always + sample: false +option_groups_list: + description: The available RDS option groups. + returned: always + type: complex + contains: + allows_vpc_and_non_vpc_instance_memberships: + description: Indicates whether this option group can be applied to both VPC and non-VPC instances. + returned: always + type: bool + sample: false + engine_name: + description: Indicates the name of the engine that this option group can be applied to. + returned: always + type: str + sample: "mysql" + major_engine_version: + description: Indicates the major engine version associated with this option group. + returned: always + type: str + sample: "5.6" + option_group_arn: + description: The Amazon Resource Name (ARN) for the option group. + returned: always + type: str + sample: "arn:aws:rds:ap-southeast-2:721066863947:og:ansible-test-option-group" + option_group_description: + description: Provides a description of the option group. + returned: always + type: str + sample: "test mysql option group" + option_group_name: + description: Specifies the name of the option group. + returned: always + type: str + sample: "test-mysql-option-group" + options: + description: Indicates what options are available in the option group. + returned: always + type: complex + contains: + db_security_group_memberships: + description: If the option requires access to a port, then this DB security group allows access to the port. + returned: always + type: complex + sample: list + elements: dict + contains: + status: + description: The status of the DB security group. + returned: always + type: str + sample: "available" + db_security_group_name: + description: The name of the DB security group. + returned: always + type: str + sample: "mydbsecuritygroup" + option_description: + description: The description of the option. + returned: always + type: str + sample: "Innodb Memcached for MySQL" + option_name: + description: The name of the option. + returned: always + type: str + sample: "MEMCACHED" + option_settings: + description: The name of the option. + returned: always + type: complex + contains: + allowed_values: + description: The allowed values of the option setting. + returned: always + type: str + sample: "1-2048" + apply_type: + description: The DB engine specific parameter type. + returned: always + type: str + sample: "STATIC" + data_type: + description: The data type of the option setting. + returned: always + type: str + sample: "INTEGER" + default_value: + description: The default value of the option setting. + returned: always + type: str + sample: "1024" + description: + description: The description of the option setting. + returned: always + type: str + sample: "Verbose level for memcached." + is_collection: + description: Indicates if the option setting is part of a collection. + returned: always + type: bool + sample: true + is_modifiable: + description: A Boolean value that, when true, indicates the option setting can be modified from the default. + returned: always + type: bool + sample: true + name: + description: The name of the option that has settings that you can set. + returned: always + type: str + sample: "INNODB_API_ENABLE_MDL" + value: + description: The current value of the option setting. + returned: always + type: str + sample: "0" + permanent: + description: Indicate if this option is permanent. + returned: always + type: bool + sample: true + persistent: + description: Indicate if this option is persistent. + returned: always + type: bool + sample: true + port: + description: If required, the port configured for this option to use. + returned: always + type: int + sample: 11211 + vpc_security_group_memberships: + description: If the option requires access to a port, then this VPC security group allows access to the port. + returned: always + type: list + elements: dict + contains: + status: + description: The status of the VPC security group. + returned: always + type: str + sample: "available" + vpc_security_group_id: + description: The name of the VPC security group. + returned: always + type: str + sample: "sg-0cd636a23ae76e9a4" + vpc_id: + description: If present, this option group can only be applied to instances that are in the VPC indicated by this field. + returned: always + type: str + sample: "vpc-bf07e9d6" + tags: + description: The tags associated the Internet Gateway. + type: dict + returned: always + sample: { + "Ansible": "Test" + } + +''' + +try: + import botocore +except ImportError: + pass # Handled by AnsibleAWSModule + +from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import camel_dict_to_snake_dict + +from ansible_collections.amazon.aws.plugins.module_utils.rds import get_tags + + +@AWSRetry.jittered_backoff(retries=10) +def _describe_option_groups(client, **params): + try: + paginator = client.get_paginator('describe_option_groups') + return paginator.paginate(**params).build_full_result() + except is_boto3_error_code('OptionGroupNotFoundFault'): + return {} + + +def list_option_groups(client, module): + option_groups = list() + params = dict() + params['OptionGroupName'] = module.params.get('option_group_name') + + if module.params.get('marker'): + params['Marker'] = module.params.get('marker') + if int(params['Marker']) < 20 or int(params['Marker']) > 100: + module.fail_json(msg="marker must be between 20 and 100 minutes") + + if module.params.get('max_records'): + params['MaxRecords'] = module.params.get('max_records') + if params['MaxRecords'] > 100: + module.fail_json(msg="The maximum number of records to include in the response is 100.") + + params['EngineName'] = module.params.get('engine_name') + params['MajorEngineVersion'] = module.params.get('major_engine_version') + + try: + result = _describe_option_groups(client, **params) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg="Couldn't describe option groups.") + + for option_group in result['OptionGroupsList']: + # Turn the boto3 result into ansible_friendly_snaked_names + converted_option_group = camel_dict_to_snake_dict(option_group) + converted_option_group['tags'] = get_tags(client, module, converted_option_group['option_group_arn']) + option_groups.append(converted_option_group) + + return option_groups + + +def main(): + argument_spec = dict( + option_group_name=dict(default='', type='str'), + marker=dict(type='str'), + max_records=dict(type='int', default=100), + engine_name=dict(type='str', default=''), + major_engine_version=dict(type='str', default=''), + ) + + module = AnsibleAWSModule( + argument_spec=argument_spec, + supports_check_mode=True, + mutually_exclusive=[ + ['option_group_name', 'engine_name'], + ['option_group_name', 'major_engine_version'], + ], + required_together=[ + ['engine_name', 'major_engine_version'], + ], + ) + + # Validate Requirements + try: + connection = module.client('rds', retry_decorator=AWSRetry.jittered_backoff()) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + module.fail_json_aws(e, msg='Failed to connect to AWS') + + results = list_option_groups(connection, module) + + module.exit_json(result=results) + + +if __name__ == '__main__': + main() diff --git a/tests/integration/targets/rds_option_group/aliases b/tests/integration/targets/rds_option_group/aliases new file mode 100644 index 00000000000..658684afbff --- /dev/null +++ b/tests/integration/targets/rds_option_group/aliases @@ -0,0 +1,3 @@ +cloud/aws + +rds_option_group_info \ No newline at end of file diff --git a/tests/integration/targets/rds_option_group/defaults/main.yml b/tests/integration/targets/rds_option_group/defaults/main.yml new file mode 100644 index 00000000000..cb42fdb7c3e --- /dev/null +++ b/tests/integration/targets/rds_option_group/defaults/main.yml @@ -0,0 +1,18 @@ +--- +option_group_name: "{{ resource_prefix }}rds-option-group" +engine_name: mysql +major_engine_version: 5.6 +option_group_description: "{{ resource_prefix }}rds-option-group test" +instance_id: "{{ resource_prefix }}" +username: test +password: test12345678 +db_instance_class: db.t2.small +storage_encrypted_db_instance_class: db.t2.small +allocated_storage: 20 +vpc_name: "{{ resource_prefix }}-vpc" +vpc_seed: "{{ resource_prefix }}" +vpc_cidr: "10.0.0.0/16" +subnet_cidr: "10.0.{{ 256 | random(seed=vpc_seed) }}.0/24" +sg_1_name: "{{ resource_prefix }}-sg-1" +sg_2_name: "{{ resource_prefix }}-sg-2" +sg_3_name: "{{ resource_prefix }}-sg-3" diff --git a/tests/integration/targets/rds_option_group/tasks/main.yml b/tests/integration/targets/rds_option_group/tasks/main.yml new file mode 100644 index 00000000000..6d6b831bc9c --- /dev/null +++ b/tests/integration/targets/rds_option_group/tasks/main.yml @@ -0,0 +1,918 @@ +--- +- name: rds_option_group tests + collections: + - amazon.aws + + module_defaults: + group/aws: + region: '{{ aws_region }}' + aws_access_key: '{{ aws_access_key }}' + aws_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token | default(omit) }}' + + + block: + - name: create a VPC + ec2_vpc_net: + name: "{{ vpc_name }}" + state: present + cidr_block: "{{ vpc_cidr }}" + register: vpc_result + + - name: Assert success + assert: + that: + - vpc_result is successful + - '"vpc" in vpc_result' + - '"cidr_block" in vpc_result.vpc' + - vpc_result.vpc.cidr_block == vpc_cidr + - '"id" in vpc_result.vpc' + - vpc_result.vpc.id.startswith("vpc-") + - '"state" in vpc_result.vpc' + - vpc_result.vpc.state == 'available' + - '"tags" in vpc_result.vpc' + + - name: "set fact: VPC ID" + set_fact: + vpc_id: "{{ vpc_result.vpc.id }}" + + - name: create subnet + ec2_vpc_subnet: + cidr: "{{ subnet_cidr}}" + vpc_id: "{{ vpc_id }}" + state: present + register: subnet_result + + - name: Assert success + assert: + that: + - subnet_result is successful + - '"subnet" in subnet_result' + - '"cidr_block" in subnet_result.subnet' + - subnet_result.subnet.cidr_block == subnet_cidr + - '"id" in subnet_result.subnet' + - subnet_result.subnet.id.startswith("subnet-") + - '"state" in subnet_result.subnet' + - subnet_result.subnet.state == 'available' + - '"tags" in subnet_result.subnet' + - subnet_result.subnet.vpc_id == vpc_id + + - name: "set fact: VPC subnet ID" + set_fact: + subnet_id: "{{ subnet_result.subnet.id }}" + + + - name: Create security groups + ec2_group: + name: "{{ item }}" + description: "created by rds_instance integration tests" + state: present + vpc_id: "{{ vpc_id }}" + register: sgs_result + loop: + - "{{ sg_1_name }}" + - "{{ sg_2_name }}" + - "{{ sg_3_name }}" + + - name: Assert success + assert: + that: + - sgs_result is successful + + - name: "set fact: security groups ID" + set_fact: + sg_1: "{{ sgs_result.results.0.group_id }}" + sg_2: "{{ sgs_result.results.1.group_id }}" + sg_3: "{{ sgs_result.results.2.group_id }}" + + + - name: List all the option groups - CHECK_MODE + rds_option_group_info: + register: option_groups_result + check_mode: true + + - name: Assert success - CHECK_MODE + assert: + that: + - option_groups_result is successful + + + - name: List all the option groups + rds_option_group_info: + register: option_groups_result + check_mode: true + + - name: Assert success + assert: + that: + - option_groups_result is successful + + - name: Create an RDS Mysql option group - CHECK_MODE + rds_option_group: + state: present + option_group_name: "{{ option_group_name }}" + engine_name: "{{ engine_name }}" + major_engine_version: "{{ major_engine_version }}" + option_group_description: "{{ option_group_description }}" + apply_immediately: true + options: + - option_name: MEMCACHED + port: 11211 + vpc_security_group_memberships: + - "{{ sg_1 }}" + option_settings: + - name: MAX_SIMULTANEOUS_CONNECTIONS + value: '20' + - name: CHUNK_SIZE_GROWTH_FACTOR + value: '1.25' + check_mode: true + register: new_rds_mysql_option_group + + - name: Assert success - CHECK_MODE + assert: + that: + - new_rds_mysql_option_group.changed + + + - name: Create an RDS Mysql option group + rds_option_group: + state: present + option_group_name: "{{ option_group_name }}" + engine_name: "{{ engine_name }}" + major_engine_version: "{{ major_engine_version }}" + option_group_description: "{{ option_group_description }}" + apply_immediately: true + options: + - option_name: MEMCACHED + port: 11211 + vpc_security_group_memberships: + - "{{ sg_1 }}" + option_settings: + - name: MAX_SIMULTANEOUS_CONNECTIONS + value: '20' + - name: CHUNK_SIZE_GROWTH_FACTOR + value: '1.25' + register: new_rds_mysql_option_group + + - assert: + that: + - new_rds_mysql_option_group.changed + - "'engine_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.engine_name == "{{ engine_name }}" + - "'major_engine_version' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.major_engine_version == "{{ major_engine_version }}" + - "'option_group_arn' in new_rds_mysql_option_group" + - "'option_group_description' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_description == "{{ option_group_description }}" + - "'option_group_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_name == "{{ option_group_name }}" + - "'vpc_id' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.vpc_id == vpc_id + - "'options' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.options | length) > 0 + - "'option_name' in option" + - option.option_name == "MEMCACHED" + - "'permanent' in option" + - "'persistent' in option" + - "'port' in option" + - option.port == 11211 + - "'vpc_security_group_memberships' in option" + - (option.vpc_security_group_memberships | length) == 1 + - option.vpc_security_group_memberships[0].vpc_security_group_id == "{{ sg_1 }}" + - "'option_settings' in option" + - (option_settings | length) > 0 + - option_settings | selectattr('name','equalto','MAX_SIMULTANEOUS_CONNECTIONS') | list | count > 0 + - option_settings | selectattr('name','equalto','CHUNK_SIZE_GROWTH_FACTOR') | list | count > 0 + vars: + option: '{{ new_rds_mysql_option_group.options[0] }}' + option_settings: '{{ new_rds_mysql_option_group.options[0].option_settings }}' + + + - name: List specific option group + rds_option_group_info: + option_group_name: "{{ option_group_name }}" + register: option_groups_result + + - name: Assert success + assert: + that: + - option_groups_result is successful + - (option_groups_result.result | length) == 1 + - "'engine_name' in option_groups_list" + - option_groups_list.engine_name == "{{ engine_name }}" + - "'major_engine_version' in option_groups_list" + - option_groups_list.major_engine_version == "{{ major_engine_version }}" + - "'option_group_arn' in option_groups_list" + - "'option_group_description' in option_groups_list" + - option_groups_list.option_group_description == "{{ option_group_description }}" + - "'option_group_name' in option_groups_list" + - option_groups_list.option_group_name == "{{ option_group_name }}" + - "'vpc_id' in option_groups_list" + - new_rds_mysql_option_group.vpc_id == vpc_id + - "'options' in option_groups_list" + - (option_groups_list.options | length) > 0 + - "'option_name' in options" + - options.option_name == "MEMCACHED" + - "'permanent' in options" + - "'persistent' in options" + - "'port' in options" + - options.port == 11211 + - "'vpc_security_group_memberships' in options" + - (options.vpc_security_group_memberships | length) == 1 + - options.vpc_security_group_memberships[0].vpc_security_group_id == "{{ sg_1 }}" + - "'option_settings' in options" + - (options.option_settings | length) > 0 + vars: + option_groups_list: '{{ option_groups_result.result[0] }}' + options: '{{ option_groups_result.result[0].options[0] }}' + + + - name: Create an RDS Mysql option group (idempotency) - CHECK_MODE + rds_option_group: + state: present + option_group_name: "{{ option_group_name }}" + engine_name: "{{ engine_name }}" + major_engine_version: "{{ major_engine_version }}" + option_group_description: "{{ option_group_description }}" + apply_immediately: true + options: + - option_name: MEMCACHED + port: 11211 + vpc_security_group_memberships: + - "{{ sg_1 }}" + option_settings: + - name: MAX_SIMULTANEOUS_CONNECTIONS + value: '20' + - name: CHUNK_SIZE_GROWTH_FACTOR + value: '1.25' + check_mode: true + register: new_rds_mysql_option_group + + - name: Assert success - CHECK_MODE + assert: + that: + - not new_rds_mysql_option_group.changed + - "'engine_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.engine_name == "{{ engine_name }}" + - "'major_engine_version' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.major_engine_version == "{{ major_engine_version }}" + - "'option_group_arn' in new_rds_mysql_option_group" + - "'option_group_description' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_description == "{{ option_group_description }}" + - "'option_group_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_name == "{{ option_group_name }}" + - "'vpc_id' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.vpc_id == vpc_id + - "'options' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.options | length) > 0 + - "'option_name' in option" + - option.option_name == "MEMCACHED" + - "'permanent' in option" + - "'persistent' in option" + - "'port' in option" + - option.port == 11211 + - "'vpc_security_group_memberships' in option" + - (option.vpc_security_group_memberships | length) == 1 + - option.vpc_security_group_memberships[0].vpc_security_group_id == "{{ sg_1 }}" + - "'option_settings' in option" + - (option_settings | length) > 0 + - option_settings | selectattr('name','equalto','MAX_SIMULTANEOUS_CONNECTIONS') | list | count > 0 + - option_settings | selectattr('name','equalto','CHUNK_SIZE_GROWTH_FACTOR') | list | count > 0 + vars: + option: '{{ new_rds_mysql_option_group.options[0] }}' + option_settings: '{{ new_rds_mysql_option_group.options[0].option_settings }}' + + + - name: Create an RDS Mysql option group (idempotency) + rds_option_group: + state: present + option_group_name: "{{ option_group_name }}" + engine_name: "{{ engine_name }}" + major_engine_version: "{{ major_engine_version }}" + option_group_description: "{{ option_group_description }}" + apply_immediately: true + options: + - option_name: MEMCACHED + port: 11211 + vpc_security_group_memberships: + - "{{ sg_1 }}" + option_settings: + - name: MAX_SIMULTANEOUS_CONNECTIONS + value: '20' + - name: CHUNK_SIZE_GROWTH_FACTOR + value: '1.25' + register: new_rds_mysql_option_group + + - assert: + that: + - not new_rds_mysql_option_group.changed + - "'engine_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.engine_name == "{{ engine_name }}" + - "'major_engine_version' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.major_engine_version == "{{ major_engine_version }}" + - "'option_group_arn' in new_rds_mysql_option_group" + - "'option_group_description' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_description == "{{ option_group_description }}" + - "'option_group_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_name == "{{ option_group_name }}" + - "'vpc_id' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.vpc_id == vpc_id + - "'options' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.options | length) > 0 + - "'option_name' in option" + - option.option_name == "MEMCACHED" + - "'permanent' in option" + - "'persistent' in option" + - "'port' in option" + - option.port == 11211 + - "'vpc_security_group_memberships' in option" + - (option.vpc_security_group_memberships | length) == 1 + - option.vpc_security_group_memberships[0].vpc_security_group_id == "{{ sg_1 }}" + - "'option_settings' in option" + - (option_settings | length) > 0 + - option_settings | selectattr('name','equalto','MAX_SIMULTANEOUS_CONNECTIONS') | list | count > 0 + - option_settings | selectattr('name','equalto','CHUNK_SIZE_GROWTH_FACTOR') | list | count > 0 + vars: + option: '{{ new_rds_mysql_option_group.options[0] }}' + option_settings: '{{ new_rds_mysql_option_group.options[0].option_settings }}' + + + - name: List option groups with specific (engine_name and major_engine_version) + rds_option_group_info: + engine_name: "{{ engine_name }}" + major_engine_version: "{{ major_engine_version }}" + register: option_groups_result + + - name: Assert success + assert: + that: + - option_groups_result is successful + - (option_groups_result.result | length) > 0 + + + - name: Create an RDS Mysql option group - apply different changes (expected changed=true) + rds_option_group: + state: present + option_group_name: "{{ option_group_name }}" + engine_name: "{{ engine_name }}" + major_engine_version: "{{ major_engine_version }}" + option_group_description: "{{ option_group_description }}" + apply_immediately: true + options: + - option_name: MEMCACHED + port: 11211 + vpc_security_group_memberships: + - "{{ sg_1 }}" + - "{{ sg_2 }}" + - "{{ sg_3 }}" + option_settings: + - name: MAX_SIMULTANEOUS_CONNECTIONS + value: '30' + register: new_rds_mysql_option_group + + - assert: + that: + - new_rds_mysql_option_group.changed + - "'engine_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.engine_name == "{{ engine_name }}" + - "'major_engine_version' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.major_engine_version == "{{ major_engine_version }}" + - "'option_group_arn' in new_rds_mysql_option_group" + - "'option_group_description' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_description == "{{ option_group_description }}" + - "'option_group_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_name == "{{ option_group_name }}" + - "'vpc_id' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.vpc_id == vpc_id + - "'options' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.options | length) > 0 + - "'option_name' in option" + - option.option_name == "MEMCACHED" + - "'permanent' in option" + - "'persistent' in option" + - "'port' in option" + - option.port == 11211 + - "'vpc_security_group_memberships' in option" + - (option.vpc_security_group_memberships | length) == 3 + - "'option_settings' in option" + - (option_settings | length) > 0 + - option_settings | selectattr('name','equalto','CHUNK_SIZE_GROWTH_FACTOR') | list | count > 0 + vars: + option: '{{ new_rds_mysql_option_group.options[0] }}' + option_settings: '{{ new_rds_mysql_option_group.options[0].option_settings }}' + + + - name: Get info about an option group - CHECK_MODE + rds_option_group_info: + option_group_name: "{{ option_group_name }}" + check_mode: true + register: option_groups_result + + - name: Assert success - CHECK_MODE + assert: + that: + - option_groups_result is successful + - (option_groups_result.result | length) == 1 + - "'engine_name' in option_groups_list" + - option_groups_list.engine_name == "{{ engine_name }}" + - "'major_engine_version' in option_groups_list" + - option_groups_list.major_engine_version == "{{ major_engine_version }}" + - "'option_group_arn' in option_groups_list" + - "'option_group_description' in option_groups_list" + - option_groups_list.option_group_description == "{{ option_group_description }}" + - "'option_group_name' in option_groups_list" + - option_groups_list.option_group_name == "{{ option_group_name }}" + - "'vpc_id' in option_groups_list" + - new_rds_mysql_option_group.vpc_id == vpc_id + - "'options' in option_groups_list" + - (option_groups_list.options | length) > 0 + - "'option_name' in options" + - options.option_name == "MEMCACHED" + - "'permanent' in options" + - "'persistent' in options" + - "'port' in options" + - options.port == 11211 + - "'vpc_security_group_memberships' in options" + - (options.vpc_security_group_memberships | length) == 3 + - "'option_settings' in options" + - (options.option_settings | length) > 0 + vars: + option_groups_list: '{{ option_groups_result.result[0] }}' + options: '{{ option_groups_result.result[0].options[0] }}' + + + - name: RDS Mysql option group - apply tags - CHECK_MODE + rds_option_group: + state: present + option_group_name: "{{ option_group_name }}" + engine_name: "{{ engine_name }}" + major_engine_version: "{{ major_engine_version }}" + option_group_description: "{{ option_group_description }}" + apply_immediately: true + options: + - option_name: MEMCACHED + port: 11211 + vpc_security_group_memberships: + - "{{ sg_1 }}" + - "{{ sg_2 }}" + - "{{ sg_3 }}" + option_settings: + - name: CHUNK_SIZE_GROWTH_FACTOR + value: '1.2' + tags: + tag_one: '{{ option_group_name }} One' + "Tag Two": 'two {{ option_group_name }}' + check_mode: true + register: new_rds_mysql_option_group + + - name: Assert success - CHECK_MODE + assert: + that: + - new_rds_mysql_option_group.changed + - "'engine_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.engine_name == "{{ engine_name }}" + - "'major_engine_version' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.major_engine_version == "{{ major_engine_version }}" + - "'option_group_arn' in new_rds_mysql_option_group" + - "'option_group_description' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_description == "{{ option_group_description }}" + - "'option_group_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_name == "{{ option_group_name }}" + - "'vpc_id' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.vpc_id == vpc_id + - "'tags' in new_rds_mysql_option_group" + - "'options' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.options | length) > 0 + - "'option_name' in option" + - option.option_name == "MEMCACHED" + - "'permanent' in option" + - "'persistent' in option" + - "'port' in option" + - option.port == 11211 + - "'vpc_security_group_memberships' in option" + - (option.vpc_security_group_memberships | length) == 3 + - "'option_settings' in option" + - (option_settings | length) > 0 + - option_settings | selectattr('name','equalto','CHUNK_SIZE_GROWTH_FACTOR') | list | count > 0 + vars: + option: '{{ new_rds_mysql_option_group.options[0] }}' + option_settings: '{{ new_rds_mysql_option_group.options[0].option_settings }}' + + + - name: RDS Mysql option group - apply tags + rds_option_group: + state: present + option_group_name: "{{ option_group_name }}" + engine_name: "{{ engine_name }}" + major_engine_version: "{{ major_engine_version }}" + option_group_description: "{{ option_group_description }}" + apply_immediately: true + options: + - option_name: MEMCACHED + port: 11211 + vpc_security_group_memberships: + - "{{ sg_1 }}" + - "{{ sg_2 }}" + - "{{ sg_3 }}" + option_settings: + - name: CHUNK_SIZE_GROWTH_FACTOR + value: '1.2' + tags: + tag_one: '{{ option_group_name }} One' + "Tag Two": 'two {{ option_group_name }}' + register: new_rds_mysql_option_group + + - assert: + that: + - new_rds_mysql_option_group.changed + - "'engine_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.engine_name == "{{ engine_name }}" + - "'major_engine_version' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.major_engine_version == "{{ major_engine_version }}" + - "'option_group_arn' in new_rds_mysql_option_group" + - "'option_group_description' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_description == "{{ option_group_description }}" + - "'option_group_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_name == "{{ option_group_name }}" + - "'vpc_id' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.vpc_id == vpc_id + - "'tags' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.tags | length) == 2 + - new_rds_mysql_option_group.tags["tag_one"] == "{{ option_group_name }} One" + - new_rds_mysql_option_group.tags["Tag Two"] == "two {{ option_group_name }}" + - "'options' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.options | length) > 0 + - "'option_name' in option" + - option.option_name == "MEMCACHED" + - "'permanent' in option" + - "'persistent' in option" + - "'port' in option" + - option.port == 11211 + - "'vpc_security_group_memberships' in option" + - (option.vpc_security_group_memberships | length) == 3 + - "'option_settings' in option" + - (option_settings | length) > 0 + - option_settings | selectattr('name','equalto','CHUNK_SIZE_GROWTH_FACTOR') | list | count > 0 + vars: + option: '{{ new_rds_mysql_option_group.options[0] }}' + option_settings: '{{ new_rds_mysql_option_group.options[0].option_settings }}' + + + - name: RDS Mysql option group - apply tags (idempotency) + rds_option_group: + state: present + option_group_name: "{{ option_group_name }}" + engine_name: "{{ engine_name }}" + major_engine_version: "{{ major_engine_version }}" + option_group_description: "{{ option_group_description }}" + apply_immediately: true + options: + - option_name: MEMCACHED + port: 11211 + vpc_security_group_memberships: + - "{{ sg_1 }}" + - "{{ sg_2 }}" + - "{{ sg_3 }}" + option_settings: + - name: CHUNK_SIZE_GROWTH_FACTOR + value: '1.2' + tags: + tag_one: '{{ option_group_name }} One' + "Tag Two": 'two {{ option_group_name }}' + register: new_rds_mysql_option_group + + - assert: + that: + - not new_rds_mysql_option_group.changed + - "'engine_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.engine_name == "{{ engine_name }}" + - "'major_engine_version' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.major_engine_version == "{{ major_engine_version }}" + - "'option_group_arn' in new_rds_mysql_option_group" + - "'option_group_description' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_description == "{{ option_group_description }}" + - "'option_group_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_name == "{{ option_group_name }}" + - "'vpc_id' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.vpc_id == vpc_id + - "'tags' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.tags | length) == 2 + - new_rds_mysql_option_group.tags["tag_one"] == "{{ option_group_name }} One" + - new_rds_mysql_option_group.tags["Tag Two"] == "two {{ option_group_name }}" + - "'options' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.options | length) > 0 + - "'option_name' in option" + - option.option_name == "MEMCACHED" + - "'permanent' in option" + - "'persistent' in option" + - "'port' in option" + - option.port == 11211 + - "'vpc_security_group_memberships' in option" + - (option.vpc_security_group_memberships | length) == 3 + - "'option_settings' in option" + - (option_settings | length) > 0 + - option_settings | selectattr('name','equalto','CHUNK_SIZE_GROWTH_FACTOR') | list | count > 0 + vars: + option: '{{ new_rds_mysql_option_group.options[0] }}' + option_settings: '{{ new_rds_mysql_option_group.options[0].option_settings }}' + + + - name: RDS Mysql option group - update tags + rds_option_group: + state: present + option_group_name: "{{ option_group_name }}" + engine_name: "{{ engine_name }}" + major_engine_version: "{{ major_engine_version }}" + option_group_description: "{{ option_group_description }}" + apply_immediately: true + options: + - option_name: MEMCACHED + port: 11211 + vpc_security_group_memberships: + - "{{ sg_1 }}" + - "{{ sg_2 }}" + - "{{ sg_3 }}" + option_settings: + - name: CHUNK_SIZE_GROWTH_FACTOR + value: '1.2' + tags: + tag_three: '{{ option_group_name }} Three' + "Tag Two": 'two {{ option_group_name }}' + register: new_rds_mysql_option_group + + - assert: + that: + - new_rds_mysql_option_group.changed + - "'engine_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.engine_name == "{{ engine_name }}" + - "'major_engine_version' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.major_engine_version == "{{ major_engine_version }}" + - "'option_group_arn' in new_rds_mysql_option_group" + - "'option_group_description' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_description == "{{ option_group_description }}" + - "'option_group_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_name == "{{ option_group_name }}" + - "'vpc_id' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.vpc_id == vpc_id + - "'tags' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.tags | length) == 2 + - new_rds_mysql_option_group.tags["tag_three"] == "{{ option_group_name }} Three" + - new_rds_mysql_option_group.tags["Tag Two"] == "two {{ option_group_name }}" + - "'options' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.options | length) > 0 + - "'option_name' in option" + - option.option_name == "MEMCACHED" + - "'permanent' in option" + - "'persistent' in option" + - "'port' in option" + - option.port == 11211 + - "'vpc_security_group_memberships' in option" + - (option.vpc_security_group_memberships | length) == 3 + - "'option_settings' in option" + - (option_settings | length) > 0 + - option_settings | selectattr('name','equalto','CHUNK_SIZE_GROWTH_FACTOR') | list | count > 0 + vars: + option: '{{ new_rds_mysql_option_group.options[0] }}' + option_settings: '{{ new_rds_mysql_option_group.options[0].option_settings }}' + + + - name: RDS Mysql option group - update tags without purge (expected changed=true) + rds_option_group: + state: present + option_group_name: "{{ option_group_name }}" + engine_name: "{{ engine_name }}" + major_engine_version: "{{ major_engine_version }}" + option_group_description: "{{ option_group_description }}" + apply_immediately: true + options: + - option_name: MEMCACHED + port: 11211 + vpc_security_group_memberships: + - "{{ sg_1 }}" + - "{{ sg_2 }}" + - "{{ sg_3 }}" + option_settings: + - name: CHUNK_SIZE_GROWTH_FACTOR + value: '1.2' + purge_tags: no + tags: + tag_one: '{{ option_group_name }} One' + register: new_rds_mysql_option_group + + - assert: + that: + - new_rds_mysql_option_group.changed + - "'engine_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.engine_name == "{{ engine_name }}" + - "'major_engine_version' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.major_engine_version == "{{ major_engine_version }}" + - "'option_group_arn' in new_rds_mysql_option_group" + - "'option_group_description' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_description == "{{ option_group_description }}" + - "'option_group_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_name == "{{ option_group_name }}" + - "'vpc_id' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.vpc_id == vpc_id + - "'tags' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.tags | length) == 3 + - new_rds_mysql_option_group.tags["Tag Two"] == "two {{ option_group_name }}" + - new_rds_mysql_option_group.tags["tag_one"] == "{{ option_group_name }} One" + - new_rds_mysql_option_group.tags["tag_three"] == "{{ option_group_name }} Three" + - "'options' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.options | length) > 0 + - "'option_name' in option" + - option.option_name == "MEMCACHED" + - "'permanent' in option" + - "'persistent' in option" + - "'port' in option" + - option.port == 11211 + - "'vpc_security_group_memberships' in option" + - (option.vpc_security_group_memberships | length) == 3 + - "'option_settings' in option" + - (option_settings | length) > 0 + - option_settings | selectattr('name','equalto','CHUNK_SIZE_GROWTH_FACTOR') | list | count > 0 + vars: + option: '{{ new_rds_mysql_option_group.options[0] }}' + option_settings: '{{ new_rds_mysql_option_group.options[0].option_settings }}' + + + - name: RDS Mysql option group - update with CamelCase tags (expected changed=true) + rds_option_group: + state: present + option_group_name: "{{ option_group_name }}" + engine_name: "{{ engine_name }}" + major_engine_version: "{{ major_engine_version }}" + option_group_description: "{{ option_group_description }}" + apply_immediately: true + options: + - option_name: MEMCACHED + port: 11211 + vpc_security_group_memberships: + - "{{ sg_1 }}" + - "{{ sg_2 }}" + - "{{ sg_3 }}" + option_settings: + - name: CHUNK_SIZE_GROWTH_FACTOR + value: '1.2' + tags: + "lowercase spaced": 'hello cruel world' + "Title Case": 'Hello Cruel World' + CamelCase: 'SimpleCamelCase' + snake_case: 'simple_snake_case' + register: new_rds_mysql_option_group + + - assert: + that: + - new_rds_mysql_option_group.changed + - "'engine_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.engine_name == "{{ engine_name }}" + - "'major_engine_version' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.major_engine_version == "{{ major_engine_version }}" + - "'option_group_arn' in new_rds_mysql_option_group" + - "'option_group_description' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_description == "{{ option_group_description }}" + - "'option_group_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_name == "{{ option_group_name }}" + - "'vpc_id' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.vpc_id == vpc_id + - "'tags' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.tags | length) == 4 + - new_rds_mysql_option_group.tags["lowercase spaced"] == 'hello cruel world' + - new_rds_mysql_option_group.tags["Title Case"] == 'Hello Cruel World' + - new_rds_mysql_option_group.tags["CamelCase"] == 'SimpleCamelCase' + - new_rds_mysql_option_group.tags["snake_case"] == 'simple_snake_case' + - "'options' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.options | length) > 0 + - "'option_name' in option" + - option.option_name == "MEMCACHED" + - "'permanent' in option" + - "'persistent' in option" + - "'port' in option" + - option.port == 11211 + - "'vpc_security_group_memberships' in option" + - (option.vpc_security_group_memberships | length) == 3 + - "'option_settings' in option" + - (option_settings | length) > 0 + - option_settings | selectattr('name','equalto','CHUNK_SIZE_GROWTH_FACTOR') | list | count > 0 + vars: + option: '{{ new_rds_mysql_option_group.options[0] }}' + option_settings: '{{ new_rds_mysql_option_group.options[0].option_settings }}' + + - name: RDS Mysql option group - do not specify any tag to ensure previous tags are not removed + rds_option_group: + state: present + option_group_name: "{{ option_group_name }}" + engine_name: "{{ engine_name }}" + major_engine_version: "{{ major_engine_version }}" + option_group_description: "{{ option_group_description }}" + apply_immediately: true + options: + - option_name: MEMCACHED + port: 11211 + vpc_security_group_memberships: + - "{{ sg_1 }}" + - "{{ sg_2 }}" + - "{{ sg_3 }}" + option_settings: + - name: CHUNK_SIZE_GROWTH_FACTOR + value: '1.2' + register: new_rds_mysql_option_group + + - assert: + that: + - not new_rds_mysql_option_group.changed + - "'engine_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.engine_name == "{{ engine_name }}" + - "'major_engine_version' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.major_engine_version == "{{ major_engine_version }}" + - "'option_group_arn' in new_rds_mysql_option_group" + - "'option_group_description' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_description == "{{ option_group_description }}" + - "'option_group_name' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.option_group_name == "{{ option_group_name }}" + - "'vpc_id' in new_rds_mysql_option_group" + - new_rds_mysql_option_group.vpc_id == vpc_id + - "'tags' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.tags | length) == 4 + - new_rds_mysql_option_group.tags["lowercase spaced"] == 'hello cruel world' + - new_rds_mysql_option_group.tags["Title Case"] == 'Hello Cruel World' + - new_rds_mysql_option_group.tags["CamelCase"] == 'SimpleCamelCase' + - new_rds_mysql_option_group.tags["snake_case"] == 'simple_snake_case' + - "'options' in new_rds_mysql_option_group" + - (new_rds_mysql_option_group.options | length) > 0 + - "'option_name' in option" + - option.option_name == "MEMCACHED" + - "'permanent' in option" + - "'persistent' in option" + - "'port' in option" + - option.port == 11211 + - "'vpc_security_group_memberships' in option" + - (option.vpc_security_group_memberships | length) == 3 + - "'option_settings' in option" + - (option_settings | length) > 0 + - option_settings | selectattr('name','equalto','CHUNK_SIZE_GROWTH_FACTOR') | list | count > 0 + vars: + option: '{{ new_rds_mysql_option_group.options[0] }}' + option_settings: '{{ new_rds_mysql_option_group.options[0].option_settings }}' + + + - name: Delete an RDS Mysql option group - CHECK_MODE + rds_option_group: + state: absent + option_group_name: "{{ option_group_name }}" + check_mode: yes + register: deleted_rds_mysql_option_group + + - name: Assert success - CHECK_MODE + assert: + that: + - deleted_rds_mysql_option_group.changed + + + - name: Delete an RDS Mysql option group + rds_option_group: + state: absent + option_group_name: "{{ option_group_name }}" + register: deleted_rds_mysql_option_group + + - name: Assert success + assert: + that: + - deleted_rds_mysql_option_group.changed + + + always: + + - name: Delete an RDS Mysql option group + rds_option_group: + state: absent + option_group_name: "{{ option_group_name }}" + register: deleted_rds_mysql_option_group + ignore_errors: yes + + - name: Remove security groups + ec2_group: + name: "{{ item }}" + description: "created by rds_instance integration tests" + state: absent + register: sgs_result + loop: + - "{{ sg_1_name }}" + - "{{ sg_2_name }}" + - "{{ sg_3_name }}" + ignore_errors: yes + + - name: remove subnet + ec2_vpc_subnet: + cidr: "{{ subnet_cidr }}" + vpc_id: "{{ vpc_id }}" + state: absent + ignore_errors: yes + + - name: Delete VPC + ec2_vpc_net: + name: "{{ vpc_name }}" + cidr_block: "{{ vpc_cidr }}" + state: absent + purge_cidrs: yes + ignore_errors: yes \ No newline at end of file