dms_replication_subnet_group (#56980

* dms_replication_subnet_group implementation
This commit is contained in:
Rui Moreira 2019-06-26 18:04:27 +01:00 committed by Jill R
parent bc3c90f2f1
commit edcb5b6775
5 changed files with 438 additions and 0 deletions

View file

@ -0,0 +1,247 @@
#!/usr/bin/python
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: dms_replication_subnet_group
short_description: creates or destroys a data migration services subnet group
description:
- Creates or destroys a data migration services subnet group
version_added: "2.9"
options:
state:
description:
- State of the subnet group
default: present
choices: ['present', 'absent']
type: str
identifier:
description:
- The name for the replication subnet group.
This value is stored as a lowercase string.
Must contain no more than 255 alphanumeric characters,
periods, spaces, underscores, or hyphens. Must not be "default".
type: str
description:
description:
- The description for the subnet group.
type: str
subnet_ids:
description:
- A list containing the subnet ids for the replication subnet group,
needs to be at least 2 items in the list
type: list
author:
- "Rui Moreira (@ruimoreira)"
extends_documentation_fragment:
- aws
- ec2
'''
EXAMPLES = '''
- dms_replication_subnet_group:
state: present
identifier: "dev-sngroup"
description: "Development Subnet Group asdasdas"
subnet_ids: ['subnet-id1','subnet-id2']
'''
RETURN = ''' # '''
__metaclass__ = type
import traceback
from ansible.module_utils.aws.core import AnsibleAWSModule
from ansible.module_utils.ec2 import boto3_conn, HAS_BOTO3, \
camel_dict_to_snake_dict, get_aws_connection_info, AWSRetry
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
backoff_params = dict(tries=5, delay=1, backoff=1.5)
@AWSRetry.backoff(**backoff_params)
def describe_subnet_group(connection, subnet_group):
"""checks if instance exists"""
try:
subnet_group_filter = dict(Name='replication-subnet-group-id',
Values=[subnet_group])
return connection.describe_replication_subnet_groups(Filters=[subnet_group_filter])
except botocore.exceptions.ClientError:
return {'ReplicationSubnetGroups': []}
@AWSRetry.backoff(**backoff_params)
def replication_subnet_group_create(connection, **params):
""" creates the replication subnet group """
return connection.create_replication_subnet_group(**params)
@AWSRetry.backoff(**backoff_params)
def replication_subnet_group_modify(connection, **modify_params):
return connection.modify_replication_subnet_group(**modify_params)
@AWSRetry.backoff(**backoff_params)
def replication_subnet_group_delete(module, connection):
subnetid = module.params.get('identifier')
delete_parameters = dict(ReplicationSubnetGroupIdentifier=subnetid)
return connection.delete_replication_subnet_group(**delete_parameters)
def get_dms_client(module, aws_connect_params, client_region, ec2_url):
client_params = dict(
module=module,
conn_type='client',
resource='dms',
region=client_region,
endpoint=ec2_url,
**aws_connect_params
)
return boto3_conn(**client_params)
def replication_subnet_exists(subnet):
""" Returns boolean based on the existance of the endpoint
:param endpoint: dict containing the described endpoint
:return: bool
"""
return bool(len(subnet['ReplicationSubnetGroups']))
def create_module_params(module):
"""
Reads the module parameters and returns a dict
:return: dict
"""
instance_parameters = dict(
# ReplicationSubnetGroupIdentifier gets translated to lower case anyway by the API
ReplicationSubnetGroupIdentifier=module.params.get('identifier').lower(),
ReplicationSubnetGroupDescription=module.params.get('description'),
SubnetIds=module.params.get('subnet_ids'),
)
return instance_parameters
def compare_params(module, param_described):
"""
Compares the dict obtained from the describe function and
what we are reading from the values in the template We can
never compare passwords as boto3's method for describing
a DMS endpoint does not return the value for
the password for security reasons ( I assume )
"""
modparams = create_module_params(module)
changed = False
# need to sanitize values that get retured from the API
if 'VpcId' in param_described.keys():
param_described.pop('VpcId')
if 'SubnetGroupStatus' in param_described.keys():
param_described.pop('SubnetGroupStatus')
for paramname in modparams.keys():
if paramname in param_described.keys() and \
param_described.get(paramname) == modparams[paramname]:
pass
elif paramname == 'SubnetIds':
subnets = []
for subnet in param_described.get('Subnets'):
subnets.append(subnet.get('SubnetIdentifier'))
for modulesubnet in modparams['SubnetIds']:
if modulesubnet in subnets:
pass
else:
changed = True
return changed
def create_replication_subnet_group(module, connection):
try:
params = create_module_params(module)
return replication_subnet_group_create(connection, **params)
except botocore.exceptions.ClientError as e:
module.fail_json(msg="Failed to create DMS replication subnet group.",
exception=traceback.format_exc(),
**camel_dict_to_snake_dict(e.response))
except botocore.exceptions.BotoCoreError as e:
module.fail_json(msg="Failed to create DMS replication subnet group.",
exception=traceback.format_exc())
def modify_replication_subnet_group(module, connection):
try:
modify_params = create_module_params(module)
return replication_subnet_group_modify(connection, **modify_params)
except botocore.exceptions.ClientError as e:
module.fail_json(msg="Failed to Modify the DMS replication subnet group.",
exception=traceback.format_exc(),
**camel_dict_to_snake_dict(e.response))
except botocore.exceptions.BotoCoreError as e:
module.fail_json(msg="Failed to Modify the DMS replication subnet group.",
exception=traceback.format_exc())
def main():
argument_spec = dict(
state=dict(type='str', choices=['present', 'absent'], default='present'),
identifier=dict(type='str', required=True),
description=dict(type='str', required=True),
subnet_ids=dict(type='list', elements='str', required=True),
)
module = AnsibleAWSModule(
argument_spec=argument_spec,
supports_check_mode=True
)
exit_message = None
changed = False
if not HAS_BOTO3:
module.fail_json(msg='boto3 required for this module')
state = module.params.get('state')
aws_config_region, ec2_url, aws_connect_params = \
get_aws_connection_info(module, boto3=True)
dmsclient = get_dms_client(module, aws_connect_params, aws_config_region, ec2_url)
subnet_group = describe_subnet_group(dmsclient,
module.params.get('identifier'))
if state == 'present':
if replication_subnet_exists(subnet_group):
if compare_params(module, subnet_group["ReplicationSubnetGroups"][0]):
if not module.check_mode:
exit_message = modify_replication_subnet_group(module, dmsclient)
else:
exit_message = dmsclient
changed = True
else:
exit_message = "No changes to Subnet group"
else:
if not module.check_mode:
exit_message = create_replication_subnet_group(module, dmsclient)
changed = True
else:
exit_message = "Check mode enabled"
elif state == 'absent':
if replication_subnet_exists(subnet_group):
if not module.check_mode:
replication_subnet_group_delete(module, dmsclient)
changed = True
exit_message = "Replication subnet group Deleted"
else:
exit_message = dmsclient
changed = True
else:
changed = False
exit_message = "Replication subnet group does not exist"
module.exit_json(changed=changed, msg=exit_message)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,2 @@
cloud/aws
unsupported

View file

@ -0,0 +1,2 @@
resource_prefix: "test_dms_sg"
dms_role_role_name: dms-vpc-role

View file

@ -0,0 +1,12 @@
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "dms.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}

View file

@ -0,0 +1,175 @@
---
- name: set connection information for all tasks
set_fact:
aws_connection_info: &aws_connection_info
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
region: "{{ aws_region }}"
dms_sg_identifier: "{{ resource_prefix }}-dms"
no_log: yes
- block:
- name: ensure IAM role exists
iam_role:
<<: *aws_connection_info
name: "{{ dms_role_role_name }}"
assume_role_policy_document: "{{ lookup('file','dmsAssumeRolePolicyDocument.json') }}"
state: present
create_instance_profile: no
managed_policy:
- 'arn:aws:iam::aws:policy/service-role/AmazonDMSVPCManagementRole'
register: iam_role_output
ignore_errors: yes
- name: Create VPC for use in testing
ec2_vpc_net:
name: "{{ resource_prefix }}-vpc"
cidr_block: 10.22.32.0/23
tags:
Name: Ansible ec2_instance Testing VPC
tenancy: default
<<: *aws_connection_info
register: testing_vpc
- name: create subnet1
ec2_vpc_subnet:
state: present
vpc_id: "{{ testing_vpc.vpc.id }}"
cidr: 10.22.32.16/28
az: eu-west-1a
<<: *aws_connection_info
register: subnet1
- name: create subnet2
ec2_vpc_subnet:
state: present
vpc_id: "{{ testing_vpc.vpc.id }}"
cidr: 10.22.32.32/28
az: eu-west-1c
<<: *aws_connection_info
register: subnet2
- name: create replication subnet group
dms_replication_subnet_group:
state: present
identifier: "{{ dms_sg_identifier }}"
description: "Development Subnet Group"
subnet_ids: [ "{{ subnet1.subnet.id }}", "{{ subnet2.subnet.id }}"]
<<: *aws_connection_info
register: result
- assert:
that:
- result is changed
- result is not failed
- name: create subnet group no change
dms_replication_subnet_group:
state: present
identifier: "{{ dms_sg_identifier }}"
description: "Development Subnet Group"
subnet_ids: [ "{{ subnet1.subnet.id }}", "{{ subnet2.subnet.id }}"]
<<: *aws_connection_info
register: result
- assert:
that:
- result is not changed
- result is not failed
- name: update subnet group
dms_replication_subnet_group:
state: present
identifier: "{{ dms_sg_identifier }}"
description: "Development Subnet Group updated"
subnet_ids: [ "{{ subnet1.subnet.id }}", "{{ subnet2.subnet.id }}"]
<<: *aws_connection_info
register: result
- assert:
that:
- result is changed
- result is not failed
- name: update subnet group no change
dms_replication_subnet_group:
state: present
identifier: "{{ dms_sg_identifier }}"
description: "Development Subnet Group updated"
subnet_ids: [ "{{ subnet1.subnet.id }}", "{{ subnet2.subnet.id }}"]
<<: *aws_connection_info
register: result
- assert:
that:
- result is not changed
- result is not failed
always:
- name: delete subnet group no change
dms_replication_subnet_group:
state: absent
identifier: "{{ dms_sg_identifier }}"
description: "Development Subnet Group updated"
subnet_ids: [ "{{ subnet1.subnet.id }}", "{{ subnet2.subnet.id }}"]
<<: *aws_connection_info
register: result
- assert:
that:
- result is changed
- result is not failed
- name: delete subnet group no change
dms_replication_subnet_group:
state: absent
identifier: "{{ dms_sg_identifier }}"
description: "Development Subnet Group updated"
subnet_ids: [ "{{ subnet1.subnet.id }}", "{{ subnet2.subnet.id }}"]
<<: *aws_connection_info
register: result
- assert:
that:
- result is not changed
- result is not failed
- name: delete subnet1
ec2_vpc_subnet:
state: absent
vpc_id: "{{ testing_vpc.vpc.id }}"
cidr: 10.22.32.16/28
az: eu-west-1a
<<: *aws_connection_info
- name: delete subnet2
ec2_vpc_subnet:
state: absent
vpc_id: "{{ testing_vpc.vpc.id }}"
cidr: 10.22.32.32/28
az: eu-west-1c
<<: *aws_connection_info
- name: delete VPC for use in testing
ec2_vpc_net:
name: "{{ resource_prefix }}-vpc"
cidr_block: 10.22.32.0/23
tags:
Name: Ansible ec2_instance Testing VPC
tenancy: default
state: absent
<<: *aws_connection_info
- name: delete dms-vpc role
iam_role:
<<: *aws_connection_info
name: "{{ dms_role_role_name }}"
assume_role_policy_document: "{{ lookup('file','dmsAssumeRolePolicyDocument.json') }}"
state: absent
create_instance_profile: no
managed_policy:
- 'arn:aws:iam::aws:policy/service-role/AmazonDMSVPCManagementRole'
register: iam_role_output
ignore_errors: yes