New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
new replication subnet group module #56075
Changes from 9 commits
bd47e64
8c56c11
776ec08
1097632
1554bef
3fdc4ba
3c8d8b1
ecdb616
f5326aa
9f86257
7e6be4e
031655d
0cb0fa9
0f852f0
05cee75
099917d
1a6b95a
c6a8e99
6b6f500
35c655c
27fcd0f
d0f2da4
d998791
661f7be
f49a677
c1ebc8d
110b8ba
ef0851d
85fa65e
6948e04
eefc90b
4b99a2a
21d4e23
cf78759
f88dedb
5b4cd22
7a32bd8
49ecfdb
0ee673a
88be323
30ccc8e
8968d41
674a57c
b3ab83b
7f41cc4
84f5666
22d7e7e
f9b56a5
2d4cbe0
4a2fa46
0d2a120
75788ec
ec2db1a
e98e987
826b99d
fd65f03
8e2bff4
3170e8b
107d9ef
5ef2c53
666dfdc
3b08e75
8ce09a0
4928373
6315598
fa7aedc
322cfa4
940d58e
6182f36
db42cf5
d55823b
f097dca
4bf1347
183ba93
6359310
7636f36
ca7ff2a
216260c
0e0735f
50e9955
75046f8
118cf3e
4b39748
a4f0861
f88b660
409c46b
d5a272c
4b00141
d59eb9e
a910d19
730456b
7e997fd
98246f6
867e357
32620b7
c8e179f
a3c3fd9
2a187f3
6c1dbbe
06c050e
ba8846a
1eb5fb9
dfab364
11c63d6
c6b40f4
2897cf4
27aca73
6c1a255
18f22de
63e33f7
b593548
576593e
5a7bce1
470371d
b8c170a
3f4a22d
4742897
f1b5836
386cef1
52a89b2
708bda0
94c8685
b2622f6
7a615a9
8c29c78
bd061fd
34e9d67
ea4842c
b37ae35
e598eee
d4b29e7
8d82df5
b712b01
abca3f1
2a90cbd
6b24043
ded7949
d56c975
77f3e84
6496084
66bfa27
493cf81
d8a5efa
8e1dd58
3b4b2e5
a4144e1
e135661
4dee569
afc678e
7f5b1e9
77f9974
a68ac72
388f5d0
a608ca0
e64083e
ac22cd3
8495e3d
41cc198
d7dc958
b275ded
53ec9c8
cb9be4d
6900378
d8c1f67
3e8ca02
4065692
459776e
f824a13
f9108e2
e4239d9
4f89c1d
69b2d7e
8fe9618
cea7151
831d3c7
96d2dd3
71ec184
16fb3ff
22d2c62
4680ed4
584a32e
8bb3274
57e4284
eb9009c
391a104
bb50fc3
54aa6f3
2a9b9d6
124400f
64b30b1
0d842ff
5005c35
cebb363
26d38dd
3095df0
1da47bf
7f0bf0a
22b9525
8f4f375
7b9d7e6
3129fc0
f9b43a0
fa6d328
8168c96
2068062
ab96d22
fc94d79
8cee127
3b16036
4adb7cf
6bb21c3
9c5b721
50b1a66
7834da4
6ebfe41
d88d71e
f65df91
dad6250
9a563f8
f96529d
db6407d
bc50a52
6c74e29
4f25435
f76556e
30210e7
fca2a4c
6e66ea9
27dcf8a
86354ff
3b9478a
484c023
a7837ed
2f523ad
37df89b
2aaa4f9
832e665
f480ae0
e64b484
b4d7bd3
0894fc6
bea05e8
a3a2929
c8a07b9
b4c516c
024b40e
0dde1a5
b25ae02
2c023f1
6e1ea79
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,248 @@ | ||
#!/usr/bin/python | ||
# This file is part of Ansible | ||
# | ||
# Ansible is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU General Public License as published by | ||
# the Free Software Foundation, either version 3 of the License, or | ||
# (at your option) any later version. | ||
# | ||
# Ansible is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
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'] | ||
resmo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
subnetgroupidentifier: | ||
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". | ||
subnetgroupdescription: | ||
description: | ||
- The description for the subnet group. | ||
subnetids: | ||
description: | ||
- A list containing the subnet ids for the replication subnet group, | ||
needs to be at least 2 items in the list | ||
author: | ||
- "Rui Moreira (@ruimoreira)" | ||
extends_documentation_fragment: | ||
- aws | ||
- ec2 | ||
''' | ||
|
||
EXAMPLES = ''' | ||
- dms_replication_subnet_group: | ||
state: present | ||
subnetgroupidentifier: "dev-sngroup" | ||
subnetgroupdescription: "Development Subnet Group asdasdas" | ||
subnetids: ['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(connection): | ||
subnetid = module.params.get('subnetgroupidentifier') | ||
delete_parameters = dict(ReplicationSubnetGroupIdentifier=subnetid) | ||
return connection.delete_replication_subnet_group(**delete_parameters) | ||
|
||
|
||
def get_dms_client(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(): | ||
""" | ||
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('subnetgroupidentifier').lower(), | ||
ReplicationSubnetGroupDescription=module.params.get('subnetgroupdescription'), | ||
SubnetIds=module.params.get('subnetids'), | ||
) | ||
|
||
return instance_parameters | ||
|
||
|
||
def compare_params(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() | ||
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(connection): | ||
try: | ||
params = create_module_params() | ||
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(connection): | ||
try: | ||
modify_params = create_module_params() | ||
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 delete_replication_subnet_group(connection): | ||
return True | ||
|
||
|
||
def main(): | ||
argument_spec = dict( | ||
state=dict(choices=['present', 'absent'], default='present'), | ||
subnetgroupidentifier=dict(required=True), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not a blocker but I find these long params very hard to read and because the module is named There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @resmo this has been addressed |
||
subnetgroupdescription=dict(required=True), | ||
subnetids=dict(type='list', required=True), | ||
) | ||
global module | ||
module = AnsibleAWSModule( | ||
argument_spec=argument_spec, | ||
required_if=[], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can be removed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here |
||
supports_check_mode=False | ||
) | ||
exit_message = None | ||
changed = False | ||
if not HAS_BOTO3: | ||
module.fail_json(msg='boto3 required for this module') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there is a helper "missing dependency" error output. please see exsiting modules There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you please point me in the right direction here ? |
||
|
||
state = module.params.get('state') | ||
aws_config_region, ec2_url, aws_connect_params = \ | ||
get_aws_connection_info(module, boto3=True) | ||
dmsclient = get_dms_client(aws_connect_params, aws_config_region, ec2_url) | ||
subnet_group = describe_subnet_group(dmsclient, | ||
module.params.get('subnetgroupidentifier')) | ||
if state == 'present': | ||
if replication_subnet_exists(subnet_group): | ||
if compare_params(subnet_group["ReplicationSubnetGroups"][0]): | ||
changed = True | ||
exit_message = modify_replication_subnet_group(dmsclient) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not implement check mode? if not module.check_mode:
exit_message = modify_replication_subnet_group(dmsclient)
else:
exit_message = " a phrase that makes sense in check mode" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also addressed |
||
else: | ||
exit_message = "No changes to Subnet group" | ||
else: | ||
exit_message = create_replication_subnet_group(dmsclient) | ||
changed = True | ||
elif state == 'absent': | ||
if replication_subnet_exists(subnet_group): | ||
changed = True | ||
replication_subnet_group_delete(dmsclient) | ||
exit_message = "Replication subnet group Deleted" | ||
|
||
else: | ||
changed = False | ||
exit_message = "Replication subnet group does not exist" | ||
|
||
module.exit_json(changed=changed, msg=exit_message) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
cloud/aws | ||
unsupported |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
--- | ||
|
||
- 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 }}" | ||
resource_prefix: "test_dms_sg" | ||
dms_sg_identifier: "{{ resource_prefix }}-dms" | ||
no_log: no | ||
|
||
- block: | ||
- 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 | ||
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 | ||
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 | ||
register: subnet2 | ||
|
||
- name: create replication subnet subnet group | ||
dms_replication_subnet_group: | ||
state: present | ||
subnetgroupidentifier: "dev-sngroup" | ||
subnetgroupdescription: "Development Subnet Group asdasdas" | ||
subnetids: [ "{{ subnet1.subnet.id }}", "{{ subnet2.subnet.id }}"] | ||
register: result | ||
|
||
- assert: | ||
that: | ||
- result is changed | ||
- result is not failed | ||
|
||
- name: create subnet group no change | ||
dms_replication_subnet_group: | ||
state: present | ||
subnetgroupidentifier: "{{ dms_sg_identifier }}" | ||
subnetgroupdescription: "Development Subnet Group" | ||
subnetids: [ "{{ 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 | ||
subnetgroupidentifier: "{{ dms_sg_identifier }}" | ||
subnetgroupdescription: "Development Subnet Group updated" | ||
subnetids: [ "{{ 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 | ||
subnetgroupidentifier: "{{ dms_sg_identifier }}" | ||
subnetgroupdescription: "Development Subnet Group updated" | ||
subnetids: [ "{{ 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 | ||
subnetgroupidentifier: "{{ dms_sg_identifier }}" | ||
subnetgroupdescription: "Development Subnet Group updated" | ||
subnetids: [ "{{ 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 | ||
subnetgroupidentifier: "{{ dms_sg_identifier }}" | ||
subnetgroupdescription: "Development Subnet Group updated" | ||
subnetids: [ "{{ 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 | ||
|
||
- name: delete subnet2 | ||
ec2_vpc_subnet: | ||
state: absent | ||
vpc_id: "{{ testing_vpc.vpc.id }}" | ||
cidr: 10.22.32.32/28 | ||
az: eu-west-1c | ||
|
||
- 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use short notation of the GPL header
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same