From 4d72b6903587ae0347206d24dee864b459f4cf98 Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Wed, 23 Oct 2019 14:27:08 +0200 Subject: [PATCH] rds_subnet_group : Sanity Check fixes (docs) and Integration tests (#63214) * rds_subnet_group: Fixup sanity test issues * rds_subnet_group: Add integration tests * rds_subnet_group: Add testing policy --- .../testing_policies/database-policy.json | 11 + .../modules/cloud/amazon/rds_subnet_group.py | 11 +- .../targets/rds_subnet_group/aliases | 2 + .../rds_subnet_group/defaults/main.yml | 8 + .../targets/rds_subnet_group/meta/main.yml | 3 + .../targets/rds_subnet_group/tasks/main.yml | 113 +++++++++ .../targets/rds_subnet_group/tasks/params.yml | 62 +++++ .../targets/rds_subnet_group/tasks/tests.yml | 221 ++++++++++++++++++ test/sanity/ignore.txt | 3 - 9 files changed, 428 insertions(+), 6 deletions(-) create mode 100644 test/integration/targets/rds_subnet_group/aliases create mode 100644 test/integration/targets/rds_subnet_group/defaults/main.yml create mode 100644 test/integration/targets/rds_subnet_group/meta/main.yml create mode 100644 test/integration/targets/rds_subnet_group/tasks/main.yml create mode 100644 test/integration/targets/rds_subnet_group/tasks/params.yml create mode 100644 test/integration/targets/rds_subnet_group/tasks/tests.yml diff --git a/hacking/aws_config/testing_policies/database-policy.json b/hacking/aws_config/testing_policies/database-policy.json index fb5ad477ad7..39fd43ac494 100644 --- a/hacking/aws_config/testing_policies/database-policy.json +++ b/hacking/aws_config/testing_policies/database-policy.json @@ -88,6 +88,17 @@ "Effect": "Allow", "Resource": "*" }, + { + "Sid": "AllowRDSSubnetGroups", + "Effect": "Allow", + "Action": [ + "rds:CreateDBSubnetGroup", + "rds:DeleteDBSubnetGroup", + "rds:DescribeDBSubnetGroups", + "rds:ModifyDBSubnetGroup" + ], + "Resource": ["*"] + }, { "Sid": "DMSEndpoints", "Effect": "Allow", diff --git a/lib/ansible/modules/cloud/amazon/rds_subnet_group.py b/lib/ansible/modules/cloud/amazon/rds_subnet_group.py index 68dccdaaf4f..008a7dc2594 100644 --- a/lib/ansible/modules/cloud/amazon/rds_subnet_group.py +++ b/lib/ansible/modules/cloud/amazon/rds_subnet_group.py @@ -23,18 +23,23 @@ options: description: - Specifies whether the subnet should be present or absent. required: true - default: present choices: [ 'present' , 'absent' ] + type: str name: description: - Database subnet group identifier. required: true + type: str description: description: - - Database subnet group description. Only set when a new group is added. + - Database subnet group description. + - Required when I(state=present). + type: str subnets: description: - List of subnet IDs that make up the database subnet group. + - Required when I(state=present). + type: list author: "Scott Anderson (@tastychutney)" extends_documentation_fragment: - aws @@ -138,7 +143,7 @@ def main(): group_subnets = module.params.get('subnets') or {} if state == 'present': - for required in ['name', 'description', 'subnets']: + for required in ['description', 'subnets']: if not module.params.get(required): module.fail_json(msg=str("Parameter %s required for state='present'" % required)) else: diff --git a/test/integration/targets/rds_subnet_group/aliases b/test/integration/targets/rds_subnet_group/aliases new file mode 100644 index 00000000000..6e3860bee23 --- /dev/null +++ b/test/integration/targets/rds_subnet_group/aliases @@ -0,0 +1,2 @@ +cloud/aws +shippable/aws/group2 diff --git a/test/integration/targets/rds_subnet_group/defaults/main.yml b/test/integration/targets/rds_subnet_group/defaults/main.yml new file mode 100644 index 00000000000..07e0fe93f8e --- /dev/null +++ b/test/integration/targets/rds_subnet_group/defaults/main.yml @@ -0,0 +1,8 @@ +vpc_cidr: '10.{{ 256 | random(seed=resource_prefix) }}.0.0/16' +subnet_a: '10.{{ 256 | random(seed=resource_prefix) }}.10.0/24' +subnet_b: '10.{{ 256 | random(seed=resource_prefix) }}.11.0/24' +subnet_c: '10.{{ 256 | random(seed=resource_prefix) }}.12.0/24' +subnet_d: '10.{{ 256 | random(seed=resource_prefix) }}.13.0/24' + +group_description: 'Created by integration test : {{ resource_prefix }}' +group_description_changed: 'Created by integration test : {{ resource_prefix }} - changed' diff --git a/test/integration/targets/rds_subnet_group/meta/main.yml b/test/integration/targets/rds_subnet_group/meta/main.yml new file mode 100644 index 00000000000..9d91be1705b --- /dev/null +++ b/test/integration/targets/rds_subnet_group/meta/main.yml @@ -0,0 +1,3 @@ +dependencies: +- prepare_tests +- setup_ec2 diff --git a/test/integration/targets/rds_subnet_group/tasks/main.yml b/test/integration/targets/rds_subnet_group/tasks/main.yml new file mode 100644 index 00000000000..44184e302db --- /dev/null +++ b/test/integration/targets/rds_subnet_group/tasks/main.yml @@ -0,0 +1,113 @@ +--- +# Tests for rds_subnet_group +# +# Note: (From Amazon's documentation) +# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/rds.html#RDS.Client.modify_db_subnet_group +# DB subnet groups must contain at least one subnet in at least two AZs in the +# AWS Region. + +- module_defaults: + group/aws: + aws_access_key: '{{ aws_access_key }}' + aws_secret_key: '{{ aws_secret_key }}' + security_token: '{{ security_token | default(omit) }}' + region: '{{ aws_region }}' + block: + + # ============================================================ + + - name: 'Fetch AZ availability' + aws_az_info: + register: az_info + + - name: 'Assert that we have multiple AZs available to us' + assert: + that: az_info.availability_zones | length >= 2 + + - name: 'Pick AZs' + set_fact: + az_one: '{{ az_info.availability_zones[0].zone_name }}' + az_two: '{{ az_info.availability_zones[1].zone_name }}' + + # ============================================================ + + - name: 'Create a VPC' + ec2_vpc_net: + state: present + cidr_block: '{{ vpc_cidr }}' + name: '{{ resource_prefix }}' + register: vpc + + - name: 'Create subnets' + ec2_vpc_subnet: + state: present + cidr: '{{ item.cidr }}' + az: '{{ item.az }}' + vpc_id: '{{ vpc.vpc.id }}' + tags: + Name: '{{ item.name }}' + with_items: + - cidr: '{{ subnet_a }}' + az: '{{ az_one }}' + name: '{{ resource_prefix }}-subnet-a' + - cidr: '{{ subnet_b }}' + az: '{{ az_two }}' + name: '{{ resource_prefix }}-subnet-b' + - cidr: '{{ subnet_c }}' + az: '{{ az_one }}' + name: '{{ resource_prefix }}-subnet-c' + - cidr: '{{ subnet_d }}' + az: '{{ az_two }}' + name: '{{ resource_prefix }}-subnet-d' + register: subnets + + - set_fact: + subnet_ids: '{{ subnets | json_query("results[].subnet.id") | list }}' + + # ============================================================ + + - include_tasks: 'params.yml' + + - include_tasks: 'tests.yml' + + # ============================================================ + + always: + - name: 'Remove subnet group' + rds_subnet_group: + state: absent + name: '{{ resource_prefix }}' + ignore_errors: yes + + - name: 'Remove subnets' + ec2_vpc_subnet: + state: absent + cidr: '{{ item.cidr }}' + vpc_id: '{{ vpc.vpc.id }}' + with_items: + - cidr: '{{ subnet_a }}' + name: '{{ resource_prefix }}-subnet-a' + - cidr: '{{ subnet_b }}' + name: '{{ resource_prefix }}-subnet-b' + - cidr: '{{ subnet_c }}' + name: '{{ resource_prefix }}-subnet-c' + - cidr: '{{ subnet_d }}' + name: '{{ resource_prefix }}-subnet-d' + ignore_errors: yes + register: removed_subnets + until: removed_subnets is succeeded + retries: 5 + delay: 5 + + - name: 'Remove the VPC' + ec2_vpc_net: + state: absent + cidr_block: '{{ vpc_cidr }}' + name: '{{ resource_prefix }}' + ignore_errors: yes + register: removed_vpc + until: removed_vpc is success + retries: 5 + delay: 5 + + # ============================================================ diff --git a/test/integration/targets/rds_subnet_group/tasks/params.yml b/test/integration/targets/rds_subnet_group/tasks/params.yml new file mode 100644 index 00000000000..74da381ff7a --- /dev/null +++ b/test/integration/targets/rds_subnet_group/tasks/params.yml @@ -0,0 +1,62 @@ +--- +# Try creating without a description +- name: 'Create a subnet group (no description)' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + ignore_errors: yes + register: create_missing_param +- assert: + that: + - create_missing_param is failed + - "'description' in create_missing_param.msg" + - "\"required for state='present'\" in create_missing_param.msg" + +# Try creating without subnets +- name: 'Create a subnet group (no subnets)' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + ignore_errors: yes + register: create_missing_param +- assert: + that: + - create_missing_param is failed + - "'subnets' in create_missing_param.msg" + - "\"required for state='present'\" in create_missing_param.msg" + +# XXX This feels like a bad pattern +# Try deleting with subnets +- name: 'Delete a subnet group (with subnets)' + rds_subnet_group: + state: absent + name: '{{ resource_prefix }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + ignore_errors: yes + register: delete_extra_param +- assert: + that: + - delete_extra_param is failed + - "'subnets' in delete_extra_param.msg" + - "\"not allowed for state='absent'\" in delete_extra_param.msg" + +# XXX This feels like a bad pattern +# Try deleting with a description +- name: 'Create a subnet group (with description)' + rds_subnet_group: + state: absent + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + ignore_errors: yes + register: delete_extra_param +- assert: + that: + - delete_extra_param is failed + - "'description' in delete_extra_param.msg" + - "\"not allowed for state='absent'\" in delete_extra_param.msg" diff --git a/test/integration/targets/rds_subnet_group/tasks/tests.yml b/test/integration/targets/rds_subnet_group/tasks/tests.yml new file mode 100644 index 00000000000..0b4e3d1b52a --- /dev/null +++ b/test/integration/targets/rds_subnet_group/tasks/tests.yml @@ -0,0 +1,221 @@ +--- +# XXX rds_subnet_group doesn't support check_mode yet + +# ============================================================ +# Basic creation +- name: 'Create a subnet group' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + register: result + +- assert: + that: + - result is changed + - result.subnet_group.description == group_description + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + +- name: 'Create a subnet group (idempotency)' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + register: result + +- assert: + that: + - result is not changed + - result.subnet_group.description == group_description + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + +# ============================================================ +# Update description + +- name: 'Update subnet group description' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + register: result + +- assert: + that: + - result is changed + - result.subnet_group.description == group_description_changed + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + +- name: 'Update subnet group description (idempotency)' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description_changed }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + register: result + +- assert: + that: + - result is not changed + - result.subnet_group.description == group_description_changed + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + +- name: 'Restore subnet group description' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + register: result + +- assert: + that: + - result is changed + - result.subnet_group.description == group_description + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + +# ============================================================ +# Update subnets + +- name: 'Update subnet group list' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[2] }}' + - '{{ subnet_ids[3] }}' + register: result + +- assert: + that: + - result is changed + - result.subnet_group.description == group_description + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[2] in result.subnet_group.subnet_ids + - subnet_ids[3] in result.subnet_group.subnet_ids + +- name: 'Update subnet group list (idempotency)' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[2] }}' + - '{{ subnet_ids[3] }}' + register: result + +- assert: + that: + - result is not changed + - result.subnet_group.description == group_description + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 2 + - subnet_ids[2] in result.subnet_group.subnet_ids + - subnet_ids[3] in result.subnet_group.subnet_ids + +- name: 'Add more subnets subnet group list' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + - '{{ subnet_ids[2] }}' + - '{{ subnet_ids[3] }}' + register: result + +- assert: + that: + - result is changed + - result.subnet_group.description == group_description + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 4 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + - subnet_ids[2] in result.subnet_group.subnet_ids + - subnet_ids[3] in result.subnet_group.subnet_ids + +- name: 'Add more members to subnet group list (idempotency)' + rds_subnet_group: + state: present + name: '{{ resource_prefix }}' + description: '{{ group_description }}' + subnets: + - '{{ subnet_ids[0] }}' + - '{{ subnet_ids[1] }}' + - '{{ subnet_ids[2] }}' + - '{{ subnet_ids[3] }}' + register: result + +- assert: + that: + - result is not changed + - result.subnet_group.description == group_description + - result.subnet_group.name == resource_prefix + - result.subnet_group.vpc_id == vpc.vpc.id + - result.subnet_group.subnet_ids | length == 4 + - subnet_ids[0] in result.subnet_group.subnet_ids + - subnet_ids[1] in result.subnet_group.subnet_ids + - subnet_ids[2] in result.subnet_group.subnet_ids + - subnet_ids[3] in result.subnet_group.subnet_ids + +# ============================================================ +# Deletion + +- name: 'Delete a subnet group' + rds_subnet_group: + state: absent + name: '{{ resource_prefix }}' + register: result + +- assert: + that: + - result is changed + +- name: 'Delete a subnet group (idempotency)' + rds_subnet_group: + state: absent + name: '{{ resource_prefix }}' + register: result + +- assert: + that: + - result is not changed diff --git a/test/sanity/ignore.txt b/test/sanity/ignore.txt index 2978f076123..cc6c705de68 100644 --- a/test/sanity/ignore.txt +++ b/test/sanity/ignore.txt @@ -1018,9 +1018,6 @@ lib/ansible/modules/cloud/amazon/rds_snapshot.py metaclass-boilerplate lib/ansible/modules/cloud/amazon/rds_snapshot_info.py future-import-boilerplate lib/ansible/modules/cloud/amazon/rds_snapshot_info.py metaclass-boilerplate lib/ansible/modules/cloud/amazon/rds_snapshot_info.py validate-modules:doc-missing-type -lib/ansible/modules/cloud/amazon/rds_subnet_group.py validate-modules:doc-default-does-not-match-spec -lib/ansible/modules/cloud/amazon/rds_subnet_group.py validate-modules:parameter-type-not-in-doc -lib/ansible/modules/cloud/amazon/rds_subnet_group.py validate-modules:doc-missing-type lib/ansible/modules/cloud/amazon/redshift.py validate-modules:undocumented-parameter lib/ansible/modules/cloud/amazon/redshift.py validate-modules:doc-choices-do-not-match-spec lib/ansible/modules/cloud/amazon/redshift.py validate-modules:parameter-type-not-in-doc