From 63df0adc17fe8f9a8852881e6e5e99f2c9b5492a Mon Sep 17 00:00:00 2001 From: Will Thames Date: Mon, 28 Aug 2017 11:52:22 -0500 Subject: [PATCH] [cloud] Update RDS parameter group for boto3 (#25345) * Update RDS parameter group for boto3 * Update to boto3 * Update to latest ansible standards * Remove choices list for valid engines (See #19221 for context) * Allow tagging * Return some useful information, and document that information * Add tests for rds_param_group * Improve testing of rds_param_group * Add purge_tags option for rds_param_group * Fix remaining broken rds_param_group tests * Ensure the group name is lowercased. Fixes integration tests when run on OSX --- .gitignore | 1 + .../testing_policies/rds-policy.json | 17 + .../modules/cloud/amazon/rds_param_group.py | 379 ++++++++++-------- .../targets/rds_param_group/aliases | 2 + .../targets/rds_param_group/defaults/main.yml | 30 ++ .../targets/rds_param_group/meta/main.yml | 3 + .../targets/rds_param_group/tasks/main.yml | 321 +++++++++++++++ test/sanity/pep8/legacy-files.txt | 1 - 8 files changed, 595 insertions(+), 159 deletions(-) create mode 100644 test/integration/targets/rds_param_group/aliases create mode 100644 test/integration/targets/rds_param_group/defaults/main.yml create mode 100644 test/integration/targets/rds_param_group/meta/main.yml create mode 100644 test/integration/targets/rds_param_group/tasks/main.yml diff --git a/.gitignore b/.gitignore index 8b36dee09f..753edbde16 100644 --- a/.gitignore +++ b/.gitignore @@ -78,6 +78,7 @@ packaging/release/ansible_release /test/integration/inventory.remote /test/integration/inventory.networking /test/integration/inventory.winrm +/test/integration/cloud-config-aws.yml # python 'rope' stuff .ropeproject # local 'ack' config files diff --git a/hacking/aws_config/testing_policies/rds-policy.json b/hacking/aws_config/testing_policies/rds-policy.json index 6284bd56e2..e74f857b65 100644 --- a/hacking/aws_config/testing_policies/rds-policy.json +++ b/hacking/aws_config/testing_policies/rds-policy.json @@ -46,6 +46,23 @@ "arn:aws:rds:{{aws_region}}:{{aws_account}}:snapshot:rds-*", "arn:aws:rds:{{aws_region}}:{{aws_account}}:db:rds-*" ] + }, + { + "Sid": "AllowRDSParameterGroupManagement", + "Effect": "Allow", + "Action": [ + "rds:DescribeDBParameterGroups", + "rds:DescribeDBParameters", + "rds:CreateDBParameterGroup", + "rds:DeleteDBParameterGroup", + "rds:ModifyDBParameterGroup", + "rds:ListTagsForResource", + "rds:AddTagsToResource", + "rds:RemoveTagsFromResource" + ], + "Resource": [ + "arn:aws:rds:{{aws_region}}:{{aws_account}}:pg:*" + ] } ] } diff --git a/lib/ansible/modules/cloud/amazon/rds_param_group.py b/lib/ansible/modules/cloud/amazon/rds_param_group.py index ba7d1efea6..da627d91d8 100644 --- a/lib/ansible/modules/cloud/amazon/rds_param_group.py +++ b/lib/ansible/modules/cloud/amazon/rds_param_group.py @@ -32,26 +32,17 @@ options: - Specifies whether the group should be present or absent. required: true default: present - aliases: [] choices: [ 'present' , 'absent' ] name: description: - Database parameter group identifier. required: true - default: null - aliases: [] description: description: - Database parameter group description. Only set when a new group is added. - required: false - default: null - aliases: [] engine: description: - The type of database for this group. Required for state=present. - required: false - default: null - aliases: [] choices: - 'aurora5.6' - 'mariadb10.0' @@ -84,17 +75,23 @@ options: immediate: description: - Whether to apply the changes immediately, or after the next reboot of any associated instances. - required: false - default: null - aliases: [] + aliases: + - apply_immediately params: description: - Map of parameter names and values. Numeric values may be represented as K for kilo (1024), M for mega (1024^2), G for giga (1024^3), or T for tera (1024^4), and these values will be expanded into the appropriate number before being set in the parameter group. - required: false - default: null - aliases: [] -author: "Scott Anderson (@tastychutney)" + tags: + description: + - Dictionary of tags to attach to the parameter group + version_added: "2.4" + purge_tags: + description: + - Whether or not to remove tags that do not appear in the I(tags) list. Defaults to false. + version_added: "2.4" +author: + - "Scott Anderson (@tastychutney)" + - "Will Thames (@willthames)" extends_documentation_fragment: - aws - ec2 @@ -109,6 +106,9 @@ EXAMPLES = ''' engine: 'mysql5.6' params: auto_increment_increment: "42K" + tags: + Environment: production + Application: parrot # Remove a parameter group - rds_param_group: @@ -116,19 +116,48 @@ EXAMPLES = ''' name: norwegian_blue ''' -try: - import boto.rds - from boto.exception import BotoServerError - HAS_BOTO = True -except ImportError: - HAS_BOTO = False +RETURN = ''' +db_parameter_group_name: + description: Name of DB parameter group + type: string + returned: when state is present +db_parameter_group_family: + description: DB parameter group family that this DB parameter group is compatible with. + type: string + returned: when state is present +db_parameter_group_arn: + description: ARN of the DB parameter group + type: string + returned: when state is present +description: + description: description of the DB parameter group + type: string + returned: when state is present +errors: + description: list of errors from attempting to modify parameters that are not modifiable + type: list + returned: when state is present +tags: + description: dictionary of tags + type: dict + returned: when state is present +''' from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.ec2 import connect_to_aws, ec2_argument_spec, get_aws_connection_info +from ansible.module_utils.ec2 import ec2_argument_spec, get_aws_connection_info, boto3_conn +from ansible.module_utils.ec2 import camel_dict_to_snake_dict, HAS_BOTO3, compare_aws_tags +from ansible.module_utils.ec2 import ansible_dict_to_boto3_tag_list, boto3_tag_list_to_ansible_dict from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE from ansible.module_utils.six import string_types from ansible.module_utils._text import to_native +import traceback + +try: + import botocore +except ImportError: + pass # caught by imported HAS_BOTO3 + VALID_ENGINES = [ 'aurora5.6', @@ -169,181 +198,215 @@ INT_MODIFIERS = { } -# returns a tuple: (whether or not a parameter was changed, the remaining parameters that weren't found in this parameter group) - -class NotModifiableError(Exception): - def __init__(self, error_message, *args): - super(NotModifiableError, self).__init__(error_message, *args) - self.error_message = error_message - - def __repr__(self): - return 'NotModifiableError: %s' % self.error_message - - def __str__(self): - return 'NotModifiableError: %s' % self.error_message - - -def set_parameter(param, value, immediate): +def convert_parameter(param, value): """ Allows setting parameters with 10M = 10* 1024 * 1024 and so on. """ converted_value = value - if param.type == 'string': - converted_value = str(value) - - elif param.type == 'integer': + if param['DataType'] == 'integer': if isinstance(value, string_types): try: for modifier in INT_MODIFIERS.keys(): if value.endswith(modifier): converted_value = int(value[:-1]) * INT_MODIFIERS[modifier] - converted_value = int(converted_value) except ValueError: # may be based on a variable (ie. {foo*3/4}) so # just pass it on through to boto - converted_value = str(value) + pass elif isinstance(value, bool): converted_value = 1 if value else 0 - else: - converted_value = int(value) - elif param.type == 'boolean': + elif param['DataType'] == 'boolean': if isinstance(value, string_types): converted_value = to_native(value) in BOOLEANS_TRUE + # convert True/False to 1/0 + converted_value = 1 if converted_value else 0 + return str(converted_value) + + +def update_parameters(module, connection): + groupname = module.params['name'] + desired = module.params['params'] + apply_method = 'immediate' if module.params['immediate'] else 'pending-reboot' + errors = [] + modify_list = [] + parameters_paginator = connection.get_paginator('describe_db_parameters') + existing = parameters_paginator.paginate(DBParameterGroupName=groupname).build_full_result()['Parameters'] + lookup = dict((param['ParameterName'], param) for param in existing) + for param_key, param_value in desired.items(): + if param_key not in lookup: + errors.append("Parameter %s is not an available parameter for the %s engine" % + (param_key, module.params.get('engine'))) else: - converted_value = bool(value) - - param.value = converted_value - param.apply(immediate) - -def modify_group(group, params, immediate=False): - """ Set all of the params in a group to the provided new params. Raises NotModifiableError if any of the - params to be changed are read only. - """ - changed = {} - - new_params = dict(params) - - for key in new_params.keys(): - if key in group: - param = group[key] - new_value = new_params[key] + converted_value = convert_parameter(lookup[param_key], param_value) + # engine-default parameters do not have a ParameterValue, so we'll always override those. + if converted_value != lookup[param_key].get('ParameterValue'): + if lookup[param_key]['IsModifiable']: + modify_list.append(dict(ParameterValue=converted_value, ParameterName=param_key, ApplyMethod=apply_method)) + else: + errors.append("Parameter %s is not modifiable" % param_key) + # modify_db_parameters takes at most 20 parameters + if modify_list: + try: + from itertools import izip_longest as zip_longest # python 2 + except ImportError: + from itertools import zip_longest # python 3 + for modify_slice in zip_longest(*[iter(modify_list)] * 20, fillvalue=None): + non_empty_slice = [item for item in modify_slice if item] try: - old_value = param.value - except ValueError: - # some versions of boto have problems with retrieving - # integer values from params that may have their value - # based on a variable (ie. {foo*3/4}), so grab it in a - # way that bypasses the property functions - old_value = param._value + connection.modify_db_parameter_group(DBParameterGroupName=groupname, Parameters=non_empty_slice) + except botocore.exceptions.ClientError as e: + module.fail_json(msg="Couldn't update parameters: %s" % str(e), + exception=traceback.format_exc(), + **camel_dict_to_snake_dict(e.response)) + return True, errors + return False, errors - if old_value != new_value: - if not param.is_modifiable: - raise NotModifiableError('Parameter %s is not modifiable.' % key) - changed[key] = {'old': old_value, 'new': new_value} +def update_tags(module, connection, group, tags): + changed = False + existing_tags = connection.list_tags_for_resource(ResourceName=group['DBParameterGroupArn'])['TagList'] + to_update, to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(existing_tags), + tags, module.params['purge_tags']) + if to_update: + try: + connection.add_tags_to_resource(ResourceName=group['DBParameterGroupArn'], + Tags=ansible_dict_to_boto3_tag_list(to_update)) + changed = True + except botocore.exceptions.ClientError as e: + module.fail_json(msg="Couldn't add tags to parameter group: %s" % str(e), + exception=traceback.format_exc(), + **camel_dict_to_snake_dict(e.response)) + except botocore.exceptions.ParamValidationError as e: + # Usually a tag value has been passed as an int or bool, needs to be a string + # The AWS exception message is reasonably ok for this purpose + module.fail_json(msg="Couldn't add tags to parameter group: %s." % str(e), + exception=traceback.format_exc()) + if to_delete: + try: + connection.remove_tags_from_resource(ResourceName=group['DBParameterGroupArn'], + TagKeys=to_delete) + changed = True + except botocore.exceptions.ClientError as e: + module.fail_json(msg="Couldn't remove tags from parameter group: %s" % str(e), + exception=traceback.format_exc(), + **camel_dict_to_snake_dict(e.response)) + return changed - set_parameter(param, new_value, immediate) - del new_params[key] +def ensure_present(module, connection): + groupname = module.params['name'] + tags = module.params.get('tags') + changed = False + errors = [] + try: + response = connection.describe_db_parameter_groups(DBParameterGroupName=groupname) + except botocore.exceptions.ClientError as e: + if e.response['Error']['Code'] == 'DBParameterGroupNotFound': + response = None + else: + module.fail_json(msg="Couldn't access parameter group information: %s" % str(e), + exception=traceback.format_exc(), + **camel_dict_to_snake_dict(e.response)) + if not response: + params = dict(DBParameterGroupName=groupname, + DBParameterGroupFamily=module.params['engine'], + Description=module.params['description']) + if tags: + params['Tags'] = ansible_dict_to_boto3_tag_list(tags) + try: + response = connection.create_db_parameter_group(**params) + changed = True + except botocore.exceptions.ClientError as e: + module.fail_json(msg="Couldn't create parameter group: %s" % str(e), + exception=traceback.format_exc(), + **camel_dict_to_snake_dict(e.response)) + else: + group = response['DBParameterGroups'][0] + if tags: + changed = update_tags(module, connection, group, tags) - return changed, new_params + if module.params.get('params'): + params_changed, errors = update_parameters(module, connection) + changed = changed or params_changed + + try: + response = connection.describe_db_parameter_groups(DBParameterGroupName=groupname) + group = camel_dict_to_snake_dict(response['DBParameterGroups'][0]) + except botocore.exceptions.ClientError as e: + module.fail_json(msg="Couldn't obtain parameter group information: %s" % str(e), + exception=traceback.format_exc(), + **camel_dict_to_snake_dict(e.response)) + try: + tags = connection.list_tags_for_resource(ResourceName=group['db_parameter_group_arn'])['TagList'] + except botocore.exceptions.ClientError as e: + module.fail_json(msg="Couldn't obtain parameter group tags: %s" % str(e), + exception=traceback.format_exc(), + **camel_dict_to_snake_dict(e.response)) + group['tags'] = boto3_tag_list_to_ansible_dict(tags) + + module.exit_json(changed=changed, errors=errors, **group) + + +def ensure_absent(module, connection): + group = module.params['name'] + try: + response = connection.describe_db_parameter_groups(DBParameterGroupName=group) + except botocore.exceptions.ClientError as e: + if e.response['Error']['Code'] == 'DBParameterGroupNotFound': + module.exit_json(changed=False) + else: + module.fail_json(msg="Couldn't access parameter group information: %s" % str(e), + exception=traceback.format_exc(), + **camel_dict_to_snake_dict(e.response)) + try: + response = connection.delete_db_parameter_group(DBParameterGroupName=group) + module.exit_json(changed=True) + except botocore.exceptions.ClientError as e: + module.fail_json(msg="Couldn't delete parameter group: %s" % str(e), + exception=traceback.format_exc(), + **camel_dict_to_snake_dict(e.response)) def main(): argument_spec = ec2_argument_spec() - argument_spec.update(dict( - state = dict(required=True, choices=['present', 'absent']), - name = dict(required=True), - engine = dict(required=False, choices=VALID_ENGINES), - description = dict(required=False), - params = dict(required=False, aliases=['parameters'], type='dict'), - immediate = dict(required=False, type='bool'), + argument_spec.update( + dict( + state=dict(required=True, choices=['present', 'absent']), + name=dict(required=True), + engine=dict(), + description=dict(), + params=dict(aliases=['parameters'], type='dict'), + immediate=dict(type='bool', aliases=['apply_immediately']), + tags=dict(type='dict', default={}), + purge_tags=dict(type='bool', default=False) + ) ) - ) - module = AnsibleModule(argument_spec=argument_spec) + module = AnsibleModule(argument_spec=argument_spec, + required_if=[['state', 'present', ['description', 'engine']]]) - if not HAS_BOTO: - module.fail_json(msg='boto required for this module') - - state = module.params.get('state') - group_name = module.params.get('name').lower() - group_engine = module.params.get('engine') - group_description = module.params.get('description') - group_params = module.params.get('params') or {} - immediate = module.params.get('immediate') or False - - if state == 'present': - for required in ['name', 'description', 'engine']: - if not module.params.get(required): - module.fail_json(msg = str("Parameter %s required for state='present'" % required)) - else: - for not_allowed in ['description', 'engine', 'params']: - if module.params.get(not_allowed): - module.fail_json(msg = str("Parameter %s not allowed for state='absent'" % not_allowed)) + if not HAS_BOTO3: + module.fail_json(msg='boto3 and botocore are required for this module') # Retrieve any AWS settings from the environment. - region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module) + region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True) if not region: - module.fail_json(msg = str("Either region or AWS_REGION or EC2_REGION environment variable or boto config aws_region or ec2_region must be set.")) + module.fail_json(msg="Region must be present") try: - conn = connect_to_aws(boto.rds, region, **aws_connect_kwargs) - except boto.exception.BotoServerError as e: - module.fail_json(msg = e.error_message) + conn = boto3_conn(module, conn_type='client', resource='rds', region=region, endpoint=ec2_url, **aws_connect_kwargs) + except botocore.exceptions.NoCredentialsError as e: + module.fail_json(msg="Couldn't connect to AWS: %s" % str(e)) - group_was_added = False - - try: - changed = False - - try: - all_groups = conn.get_all_dbparameter_groups(group_name, max_records=100) - exists = len(all_groups) > 0 - except BotoServerError as e: - if e.error_code != 'DBParameterGroupNotFound': - module.fail_json(msg = e.error_message) - exists = False - - if state == 'absent': - if exists: - conn.delete_parameter_group(group_name) - changed = True - else: - changed = {} - if not exists: - new_group = conn.create_parameter_group(group_name, engine=group_engine, description=group_description) - group_was_added = True - - # If a "Marker" is present, this group has more attributes remaining to check. Get the next batch, but only - # if there are parameters left to set. - marker = None - while len(group_params): - next_group = conn.get_all_dbparameters(group_name, marker=marker) - - changed_params, group_params = modify_group(next_group, group_params, immediate) - changed.update(changed_params) - - if hasattr(next_group, 'Marker'): - marker = next_group.Marker - else: - break - - except BotoServerError as e: - module.fail_json(msg = e.error_message) - - except NotModifiableError as e: - msg = e.error_message - if group_was_added: - msg = '%s The group "%s" was added first.' % (msg, group_name) - module.fail_json(msg=msg) - - module.exit_json(changed=changed) + state = module.params.get('state') + if state == 'present': + ensure_present(module, conn) + if state == 'absent': + ensure_absent(module, conn) if __name__ == '__main__': main() - diff --git a/test/integration/targets/rds_param_group/aliases b/test/integration/targets/rds_param_group/aliases new file mode 100644 index 0000000000..495c6e74ed --- /dev/null +++ b/test/integration/targets/rds_param_group/aliases @@ -0,0 +1,2 @@ +cloud/aws +posix/ci/cloud/aws diff --git a/test/integration/targets/rds_param_group/defaults/main.yml b/test/integration/targets/rds_param_group/defaults/main.yml new file mode 100644 index 0000000000..8f9de71fbb --- /dev/null +++ b/test/integration/targets/rds_param_group/defaults/main.yml @@ -0,0 +1,30 @@ +--- +rds_param_group: + name: "{{ resource_prefix}}rds-param-group" + description: "Test group for rds_param_group Ansible module" + engine: postgres9.6 + +rds_long_param_list: + application_name: Test + logging_collector: on + log_directory: /var/log/postgresql + log_filename: postgresql.log.%Y-%m-%d-%H + log_file_mode: 0600 + event_source: RDS + log_min_messages: INFO + log_min_duration_statement: 500 + log_rotation_age: 60 + debug_print_parse: on + debug_print_rewritten: on + debug_print_plan: on + debug_pretty_print: on + log_checkpoints: on + log_connections: on + log_disconnections: on + log_duration: on + log_error_verbosity: VERBOSE + log_lock_waits: on + log_temp_files: 10K + log_timezone: UTC + log_statement: 'all' + log_replication_commands: on diff --git a/test/integration/targets/rds_param_group/meta/main.yml b/test/integration/targets/rds_param_group/meta/main.yml new file mode 100644 index 0000000000..1f64f1169a --- /dev/null +++ b/test/integration/targets/rds_param_group/meta/main.yml @@ -0,0 +1,3 @@ +dependencies: + - prepare_tests + - setup_ec2 diff --git a/test/integration/targets/rds_param_group/tasks/main.yml b/test/integration/targets/rds_param_group/tasks/main.yml new file mode 100644 index 0000000000..9af2776b3e --- /dev/null +++ b/test/integration/targets/rds_param_group/tasks/main.yml @@ -0,0 +1,321 @@ +--- +# A Note about ec2 environment variable name preference: +# - EC2_URL -> AWS_URL +# - EC2_ACCESS_KEY -> AWS_ACCESS_KEY_ID -> AWS_ACCESS_KEY +# - EC2_SECRET_KEY -> AWS_SECRET_ACCESS_KEY -> AWX_SECRET_KEY +# - EC2_REGION -> AWS_REGION +# +# TODO - name: test 'region' parameter +# TODO - name: test 'state=absent' parameter for existing key +# TODO - name: test 'state=absent' parameter for missing key +# TODO - name: test 'validate_certs' parameter + +# ============================================================ +# - include: ../../setup_ec2/tasks/common.yml module_name=rds_param_group + +- block: + + # ============================================================ + - name: test empty parameter group + rds_param_group: + name: "{{ rds_param_group.name }}" + engine: "{{ rds_param_group.engine }}" + description: "{{ rds_param_group.description }}" + state: present + region: "{{ ec2_region }}" + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + register: result + ignore_errors: true + + - name: assert rds parameter group changed + assert: + that: + - 'result.changed' + - "'{{ result.db_parameter_group_name | lower }}' == '{{ rds_param_group.name | lower }}'" + - 'result.tags == {}' + + # ============================================================ + - name: test empty parameter group with no arguments changes nothing + rds_param_group: + name: "{{ rds_param_group.name }}" + engine: "{{ rds_param_group.engine }}" + description: "{{ rds_param_group.description }}" + state: present + region: "{{ ec2_region }}" + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + register: result + ignore_errors: true + + - name: assert no change when running empty parameter group a second time + assert: + that: + - 'not result.changed' + + # ============================================================ + - name: test adding numeric tag + rds_param_group: + name: "{{ rds_param_group.name }}" + engine: "{{ rds_param_group.engine }}" + description: "{{ rds_param_group.description }}" + state: present + tags: + Environment: test + Test: 123 + region: "{{ ec2_region }}" + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + register: result + ignore_errors: true + + - name: adding numeric tag just silently converts + assert: + that: + - 'result.changed' + - 'result.tags.Test == "123"' + + # ============================================================ + - name: test tagging existing group + rds_param_group: + name: "{{ rds_param_group.name }}" + engine: "{{ rds_param_group.engine }}" + description: "{{ rds_param_group.description }}" + state: present + tags: + Environment: test + Test: "123" + NewTag: "hello" + region: "{{ ec2_region }}" + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + register: result + ignore_errors: true + + - name: assert tagging existing group changes it and adds tags + assert: + that: + - 'result.changed' + - 'result.tags.NewTag == "hello"' + + # ============================================================ + - name: test repeating tagging existing group + rds_param_group: + name: "{{ rds_param_group.name }}" + engine: "{{ rds_param_group.engine }}" + description: "{{ rds_param_group.description }}" + state: present + tags: + Environment: test + Test: "123" + NewTag: "hello" + region: "{{ ec2_region }}" + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + register: result + ignore_errors: true + + - name: assert tagging existing group changes it and adds tags + assert: + that: + - 'not result.changed' + - 'result.tags.Test == "123"' + + # ============================================================ + - name: test deleting tags from existing group + rds_param_group: + name: "{{ rds_param_group.name }}" + engine: "{{ rds_param_group.engine }}" + description: "{{ rds_param_group.description }}" + state: present + tags: + Environment: test + region: "{{ ec2_region }}" + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + purge_tags: yes + register: result + ignore_errors: true + + - name: assert removing tags from existing group changes it + assert: + that: + - 'result.changed' + - 'result.tags.Environment == "test"' + - '"NewTag" not in result.tags' + + # ============================================================ + - name: test state=absent with engine defined (expect changed=true) + rds_param_group: + name: "{{ rds_param_group.name }}" + engine: "{{ rds_param_group.engine }}" + state: absent + region: "{{ ec2_region }}" + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + register: result + ignore_errors: true + + - name: assert state=absent with engine defined (expect changed=true) + assert: + that: + - 'result.changed' + + # ============================================================ + - name: test creating group with parameters + rds_param_group: + name: "{{ rds_param_group.name }}" + engine: "{{ rds_param_group.engine }}" + description: "{{ rds_param_group.description }}" + state: present + params: + log_directory: /var/log/postgresql + log_statement: 'all' + log_duration: on + this_param_does_not_exist: oh_no + tags: + Environment: test + Test: "123" + region: "{{ ec2_region }}" + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + register: result + ignore_errors: true + + - name: assert creating a new group with parameter changes it + assert: + that: + - 'result.changed' + - 'result.tags.Test == "123"' + - 'result.errors|length == 2' + + # ============================================================ + - name: test repeating group with parameters + rds_param_group: + name: "{{ rds_param_group.name }}" + engine: "{{ rds_param_group.engine }}" + description: "{{ rds_param_group.description }}" + state: present + params: + log_directory: /var/log/postgresql + log_statement: 'all' + log_duration: on + this_param_does_not_exist: oh_no + tags: + Environment: test + Test: "123" + region: "{{ ec2_region }}" + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + register: result + ignore_errors: true + + - name: assert repeating group with parameters does not change it + assert: + that: + - 'not result.changed' + - 'result.tags.Test == "123"' + - 'result.errors|length == 2' + + # ============================================================ + - name: test state=absent with engine defined (expect changed=true) + rds_param_group: + name: "{{ rds_param_group.name }}" + engine: "{{ rds_param_group.engine }}" + state: absent + region: "{{ ec2_region }}" + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + register: result + ignore_errors: true + + - name: assert state=absent with engine defined (expect changed=true) + assert: + that: + - 'result.changed' + + # ============================================================ + - name: test repeating state=absent (expect changed=false) + rds_param_group: + name: "{{ rds_param_group.name }}" + engine: "{{ rds_param_group.engine }}" + state: absent + region: "{{ ec2_region }}" + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + register: result + ignore_errors: true + + - name: assert repeating state=absent (expect changed=false) + assert: + that: + - 'not result.changed' + + # ============================================================ + - name: test creating group with more than 20 parameters + rds_param_group: + name: "{{ rds_param_group.name }}" + engine: "{{ rds_param_group.engine }}" + description: "{{ rds_param_group.description }}" + params: "{{ rds_long_param_list }}" + state: present + region: "{{ ec2_region }}" + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + register: result + ignore_errors: true + + - name: assert creating a new group with lots of parameter changes it + assert: + that: + - 'result.changed' + + # ============================================================ + - name: test creating group with more than 20 parameters + rds_param_group: + name: "{{ rds_param_group.name }}" + engine: "{{ rds_param_group.engine }}" + description: "{{ rds_param_group.description }}" + params: "{{ rds_long_param_list }}" + region: "{{ ec2_region }}" + state: present + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + register: result + ignore_errors: true + + - name: assert repeating a group with lots of parameter does not change it + assert: + that: + - 'not result.changed' + + always: + # ============================================================ + - name: test state=absent (expect changed=false) + rds_param_group: + name: "{{ rds_param_group.name }}" + state: absent + region: "{{ ec2_region }}" + ec2_access_key: '{{ aws_access_key }}' + ec2_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token }}' + register: result + ignore_errors: true + + - name: assert state=absent (expect changed=false) + assert: + that: + - 'result.changed' diff --git a/test/sanity/pep8/legacy-files.txt b/test/sanity/pep8/legacy-files.txt index 7df9e4d0d6..e8a2456b0f 100644 --- a/test/sanity/pep8/legacy-files.txt +++ b/test/sanity/pep8/legacy-files.txt @@ -53,7 +53,6 @@ lib/ansible/modules/cloud/amazon/iam.py lib/ansible/modules/cloud/amazon/iam_policy.py lib/ansible/modules/cloud/amazon/lambda.py lib/ansible/modules/cloud/amazon/lambda_facts.py -lib/ansible/modules/cloud/amazon/rds_param_group.py lib/ansible/modules/cloud/amazon/rds_subnet_group.py lib/ansible/modules/cloud/amazon/redshift.py lib/ansible/modules/cloud/amazon/route53_health_check.py