Skip to content

Commit

Permalink
Migrate elasticache_subnet_group to boto3
Browse files Browse the repository at this point in the history
  • Loading branch information
tremble committed Sep 17, 2021
1 parent e125e89 commit 3cb67e4
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 69 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/723-elasticache_subnet_group-boto3.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- elasticache_subnet_group - module migrated to boto3 AWS SDK (https://github.com/ansible-collections/community.aws/pull/723).
196 changes: 127 additions & 69 deletions plugins/modules/elasticache_subnet_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,35 @@
version_added: 1.0.0
short_description: manage ElastiCache subnet groups
description:
- Creates, modifies, and deletes ElastiCache subnet groups. This module has a dependency on python-boto >= 2.5.
- Creates, modifies, and deletes ElastiCache subnet groups.
options:
state:
description:
- Specifies whether the subnet should be present or absent.
required: true
choices: [ 'present' , 'absent' ]
default: 'present'
type: str
name:
description:
- Database subnet group identifier.
- This value is automatically converted to lowercase.
required: true
type: str
description:
description:
- ElastiCache subnet group description. Only set when a new group is added.
- ElastiCache subnet group description.
- When not provided defaults to I(name) on subnet group creation.
type: str
subnets:
description:
- List of subnet IDs that make up the ElastiCache subnet group.
type: list
elements: str
author: "Tim Mahoney (@timmahoney)"
author:
- "Tim Mahoney (@timmahoney)"
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
requirements:
- boto >= 2.49.0
- amazon.aws.aws
- amazon.aws.ec2
'''

EXAMPLES = r'''
Expand All @@ -59,86 +60,143 @@
'''

try:
import boto
from boto.elasticache import connect_to_region
from boto.exception import BotoServerError
import botocore
except ImportError:
pass # Handled by HAS_BOTO
pass # Handled by AnsibleAWSModule

from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict

from ansible.module_utils._text import to_native
from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import HAS_BOTO
from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info
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


def get_subnet_group(name):
try:
groups = client.describe_cache_subnet_groups(
aws_retry=True,
CacheSubnetGroupName=name,
)['CacheSubnetGroups']
except is_boto3_error_code('CacheSubnetGroupNotFoundFault'):
return None
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to describe subnet group")

if not groups:
return None

if len(groups) > 1:
module.fail_aws(
msg="Found multiple matches for subnet group",
cache_subnet_groups=camel_dict_to_snake_dict(groups),
)

subnet_group = camel_dict_to_snake_dict(groups[0])

subnet_group['name'] = subnet_group['cache_subnet_group_name']
subnet_group['description'] = subnet_group['cache_subnet_group_description']

subnet_ids = list(s['subnet_identifier'] for s in subnet_group['subnets'])
subnet_group['subnet_ids'] = subnet_ids

return subnet_group


def create_subnet_group(name, description, subnets):
try:
if not description:
description = name
if not subnets:
subnets = []
client.create_cache_subnet_group(
aws_retry=True,
CacheSubnetGroupName=name,
CacheSubnetGroupDescription=description,
SubnetIds=subnets,
)
return True
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to create subnet group")


def update_subnet_group(subnet_group, name, description, subnets):
update_params = dict()
if description and subnet_group['description'] != description:
update_params['CacheSubnetGroupDescription'] = description
if subnets:
old_subnets = set(subnet_group['subnet_ids'])
new_subnets = set(subnets)
if old_subnets != new_subnets:
update_params['SubnetIds'] = list(subnets)

if not update_params:
return False

try:
client.modify_cache_subnet_group(
aws_retry=True,
CacheSubnetGroupName=name,
**update_params,
)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Failed to update subnet group")

return True


def delete_subnet_group(name):
try:
client.delete_cache_subnet_group(
aws_retry=True,
CacheSubnetGroupName=name,
)
return True
except is_boto3_error_code('CacheSubnetGroupNotFoundFault'):
# AWS is "eventually consistent", cope with the race conditions where
# deletion hadn't completed when we ran describe
return False
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to delete subnet group")


def main():
argument_spec = dict(
state=dict(required=True, choices=['present', 'absent']),
state=dict(default='present', choices=['present', 'absent']),
name=dict(required=True),
description=dict(required=False),
subnets=dict(required=False, type='list', elements='str'),
)
module = AnsibleAWSModule(argument_spec=argument_spec, check_boto3=False)

if not HAS_BOTO:
module.fail_json(msg='boto required for this module')
global module
global client

state = module.params.get('state')
group_name = module.params.get('name').lower()
group_description = module.params.get('description')
group_subnets = module.params.get('subnets') or {}
module = AnsibleAWSModule(argument_spec=argument_spec)

if state == 'present':
for required in ['name', 'description', 'subnets']:
if not module.params.get(required):
module.fail_json(msg=str("Parameter %s required for state='present'" % required))
else:
for not_allowed in ['description', 'subnets']:
if module.params.get(not_allowed):
module.fail_json(msg=str("Parameter %s not allowed for state='absent'" % not_allowed))

# Retrieve any AWS settings from the environment.
region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module)
state = module.params.get('state')
name = module.params.get('name').lower()
description = module.params.get('description')
subnets = module.params.get('subnets')

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."))
client = module.client('elasticache', retry_decorator=AWSRetry.jittered_backoff())

"""Get an elasticache connection"""
try:
conn = connect_to_region(region_name=region, **aws_connect_kwargs)
except boto.exception.NoAuthHandlerFound as e:
module.fail_json(msg=to_native(e))
subnet_group = get_subnet_group(name)
changed = False

try:
changed = False
exists = False

try:
matching_groups = conn.describe_cache_subnet_groups(group_name, max_records=100)
exists = len(matching_groups) > 0
except BotoServerError as e:
if e.error_code != 'CacheSubnetGroupNotFoundFault':
module.fail_json(msg=e.error_message)

if state == 'absent':
if exists:
conn.delete_cache_subnet_group(group_name)
changed = True
else:
if not exists:
new_group = conn.create_cache_subnet_group(group_name, cache_subnet_group_description=group_description, subnet_ids=group_subnets)
changed = True
else:
changed_group = conn.modify_cache_subnet_group(group_name, cache_subnet_group_description=group_description, subnet_ids=group_subnets)
changed = True

except BotoServerError as e:
if e.error_message != 'No modifications were requested.':
module.fail_json(msg=e.error_message)
if state == 'present':
if not subnet_group:
result = create_subnet_group(name, description, subnets)
changed |= result
else:
changed = False
result = update_subnet_group(subnet_group, name, description, subnets)
changed |= result
subnet_group = get_subnet_group(name)
else:
if subnet_group:
result = delete_subnet_group(name)
changed |= result
subnet_group = None

module.exit_json(changed=changed)
module.exit_json(changed=changed, cache_subnet_group=subnet_group)


if __name__ == '__main__':
Expand Down

0 comments on commit 3cb67e4

Please sign in to comment.