Repository: ansible-collections/amazon.aws

Issue:
[6.0.0] Drop support for EC2 Classic networking
### Summary

[Amazon announced that they're dropping support for "EC2 Classic" (non-VPC networking) in July 2021](https://aws.amazon.com/blogs/aws/ec2-classic-is-retiring-heres-how-to-prepare/).  This is sometimes referred to as "Classic-Link"

Specifically stating that:
> On August 15, 2022 [Amazon AWS] expect all migrations to be complete, with no remaining EC2-Classic resources present in any AWS account.

We're now past that date, it's reasonable to start dropping support for EC2-Classic for 6.0.0.  Anyone who's got an exception from Amazon to continue to support EC2 Classic will still be able to use our 5.x releases.

### Issue Type

Feature Idea

### Component Name

(Known examples)
plugins/modules/ec2_eip.py (`in_vpc` parameter - `Domain` when passed to boto3 should now always be `vpc`)
plugins/modules/ec2_vpc_net.py
plugins/modules/ec2_security_group.py
plugins/module_utils/botocore.py
plugins/lookup/aws_account_attribute.py  (see also #1092)

### Additional Information

**Note**: This does _NOT_ include Classic ELBs which _are_ still supported.

### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct


Discussion:

Resolving patch:
diff --git a/plugins/modules/rds_option_group.py b/plugins/modules/rds_option_group.py
new file mode 100644
--- /dev/null
+++ b/plugins/modules/rds_option_group.py
@@ -0,0 +1,665 @@
+#!/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: Manages the creation, modification, deletion of RDS option groups
+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
+            elements: dict
+            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
+            elements: str
+        vpc_security_group_memberships:
+            description: A list of C(VpcSecurityGroupMembership) name strings used for this option.
+            required: false
+            type: list
+            elements: str
+  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
+  - amazon.aws.tags
+'''
+
+EXAMPLES = r'''
+# Create an RDS Mysql Option group
+- name: Create an RDS Mysql option group
+  amazon.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
+  amazon.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
+  amazon.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
+  amazon.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', aliases=['resource_tags']),
+        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
--- /dev/null
+++ b/plugins/modules/rds_option_group_info.py
@@ -0,0 +1,326 @@
+#!/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
+  amazon.aws.rds_option_group_info:
+    option_group_name: test-mysql-option-group
+  register: option_group
+
+- name: List all the option groups
+  amazon.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 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()


Test patch:
diff --git a/tests/integration/targets/rds_option_group/aliases b/tests/integration/targets/rds_option_group/aliases
new file mode 100644
--- /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
--- /dev/null
+++ b/tests/integration/targets/rds_option_group/defaults/main.yml
@@ -0,0 +1,17 @@
+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/meta/main.yml b/tests/integration/targets/rds_option_group/meta/main.yml
new file mode 100644
--- /dev/null
+++ b/tests/integration/targets/rds_option_group/meta/main.yml
@@ -0,0 +1 @@
+dependencies: []
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
--- /dev/null
+++ b/tests/integration/targets/rds_option_group/tasks/main.yml
@@ -0,0 +1,948 @@
+- name: rds_option_group tests
+  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