[cloud] Add encryption support to efs module (#32815)

* Add encryption support to efs module

* Update the exception handling in AWS EFS module
pull/34372/head
Rob 7 years ago committed by Ryan Brown
parent f0cf1b35d5
commit 2616f9d713

@ -23,6 +23,29 @@ author:
- "Ryan Sydnor (@ryansydnor)" - "Ryan Sydnor (@ryansydnor)"
- "Artem Kazakov (@akazakov)" - "Artem Kazakov (@akazakov)"
options: options:
encrypt:
description:
- A boolean value that, if true, creates an encrypted file system. This can not be modfied after the file
system is created.
required: false
default: false
choices: ['yes', 'no']
version_added: 2.5
kms_key_id:
description:
- The id of the AWS KMS CMK that will be used to protect the encrypted file system. This parameter is only
required if you want to use a non-default CMK. If this parameter is not specified, the default CMK for
Amazon EFS is used. The key id can be Key ID, Key ID ARN, Key Alias or Key Alias ARN.
required: false
version_added: 2.5
purge_tags:
description:
- If yes, existing tags will be purged from the resource to match exactly what is defined by I(tags) parameter. If the I(tags) parameter
is not set then tags will not be modified.
required: false
default: yes
choices: [ 'yes', 'no' ]
version_added: 2.5
state: state:
description: description:
- Allows to create, search and destroy Amazon EFS file system - Allows to create, search and destroy Amazon EFS file system
@ -74,6 +97,7 @@ options:
default: 0 default: 0
extends_documentation_fragment: extends_documentation_fragment:
- aws - aws
- ec2
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -193,15 +217,18 @@ tags:
from time import sleep from time import sleep
from time import time as timestamp from time import time as timestamp
import traceback
try: try:
from botocore.exceptions import ClientError from botocore.exceptions import ClientError, BotoCoreError
except ImportError as e: except ImportError as e:
pass # Taken care of by ec2.HAS_BOTO3 pass # Taken care of by ec2.HAS_BOTO3
from ansible.module_utils._text import to_native
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ec2 import (HAS_BOTO3, boto3_conn, camel_dict_to_snake_dict, from ansible.module_utils.ec2 import (HAS_BOTO3, boto3_conn, camel_dict_to_snake_dict,
ec2_argument_spec, get_aws_connection_info) ec2_argument_spec, get_aws_connection_info, ansible_dict_to_boto3_tag_list,
compare_aws_tags, boto3_tag_list_to_ansible_dict)
def _index_by_key(key, items): def _index_by_key(key, items):
@ -221,6 +248,8 @@ class EFSConnection(object):
self.connection = boto3_conn(module, conn_type='client', self.connection = boto3_conn(module, conn_type='client',
resource='efs', region=region, resource='efs', region=region,
**aws_connect_params) **aws_connect_params)
self.module = module
self.region = region self.region = region
self.wait = module.params.get('wait') self.wait = module.params.get('wait')
self.wait_timeout = module.params.get('wait_timeout') self.wait_timeout = module.params.get('wait_timeout')
@ -256,12 +285,8 @@ class EFSConnection(object):
""" """
Returns tag list for selected instance of EFS Returns tag list for selected instance of EFS
""" """
tags = iterate_all( tags = self.connection.describe_tags(**kwargs)['Tags']
'Tags', return tags
self.connection.describe_tags,
**kwargs
)
return dict((tag['Key'], tag['Value']) for tag in tags)
def get_mount_targets(self, **kwargs): def get_mount_targets(self, **kwargs):
""" """
@ -331,19 +356,34 @@ class EFSConnection(object):
return list(targets) return list(targets)
def create_file_system(self, name, performance_mode): def create_file_system(self, name, performance_mode, encrypt, kms_key_id):
""" """
Creates new filesystem with selected name Creates new filesystem with selected name
""" """
changed = False changed = False
state = self.get_file_system_state(name) state = self.get_file_system_state(name)
params = {}
params['CreationToken'] = name
params['PerformanceMode'] = performance_mode
if encrypt:
params['Encrypted'] = encrypt
if kms_key_id is not None:
params['KmsKeyId'] = kms_key_id
if state in [self.STATE_DELETING, self.STATE_DELETED]: if state in [self.STATE_DELETING, self.STATE_DELETED]:
wait_for( wait_for(
lambda: self.get_file_system_state(name), lambda: self.get_file_system_state(name),
self.STATE_DELETED self.STATE_DELETED
) )
self.connection.create_file_system(CreationToken=name, PerformanceMode=performance_mode) try:
changed = True self.connection.create_file_system(**params)
changed = True
except ClientError as e:
self.module.fail_json(msg="Unable to create file system: {0}".format(to_native(e)),
exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
except BotoCoreError as e:
self.module.fail_json(msg="Unable to create file system: {0}".format(to_native(e)),
exception=traceback.format_exc())
# we always wait for the state to be available when creating. # we always wait for the state to be available when creating.
# if we try to take any actions on the file system before it's available # if we try to take any actions on the file system before it's available
@ -356,7 +396,7 @@ class EFSConnection(object):
return changed return changed
def converge_file_system(self, name, tags, targets): def converge_file_system(self, name, tags, purge_tags, targets):
""" """
Change attributes (mount targets and tags) of filesystem by name Change attributes (mount targets and tags) of filesystem by name
""" """
@ -364,20 +404,36 @@ class EFSConnection(object):
fs_id = self.get_file_system_id(name) fs_id = self.get_file_system_id(name)
if tags is not None: if tags is not None:
tags_to_create, _, tags_to_delete = dict_diff(self.get_tags(FileSystemId=fs_id), tags) tags_need_modify, tags_to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(self.get_tags(FileSystemId=fs_id)), tags, purge_tags)
if tags_to_delete: if tags_to_delete:
self.connection.delete_tags( try:
FileSystemId=fs_id, self.connection.delete_tags(
TagKeys=[item[0] for item in tags_to_delete] FileSystemId=fs_id,
) TagKeys=tags_to_delete
)
except ClientError as e:
self.module.fail_json(msg="Unable to delete tags: {0}".format(to_native(e)),
exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
except BotoCoreError as e:
self.module.fail_json(msg="Unable to delete tags: {0}".format(to_native(e)),
exception=traceback.format_exc())
result = True result = True
if tags_to_create: if tags_need_modify:
self.connection.create_tags( try:
FileSystemId=fs_id, self.connection.create_tags(
Tags=[{'Key': item[0], 'Value': item[1]} for item in tags_to_create] FileSystemId=fs_id,
) Tags=ansible_dict_to_boto3_tag_list(tags_need_modify)
)
except ClientError as e:
self.module.fail_json(msg="Unable to create tags: {0}".format(to_native(e)),
exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
except BotoCoreError as e:
self.module.fail_json(msg="Unable to create tags: {0}".format(to_native(e)),
exception=traceback.format_exc())
result = True result = True
if targets is not None: if targets is not None:
@ -561,7 +617,10 @@ def main():
""" """
argument_spec = ec2_argument_spec() argument_spec = ec2_argument_spec()
argument_spec.update(dict( argument_spec.update(dict(
encrypt=dict(required=False, type="bool", default=False),
state=dict(required=False, type='str', choices=["present", "absent"], default="present"), state=dict(required=False, type='str', choices=["present", "absent"], default="present"),
kms_key_id=dict(required=False, type='str', default=None),
purge_tags=dict(default=True, type='bool'),
id=dict(required=False, type='str', default=None), id=dict(required=False, type='str', default=None),
name=dict(required=False, type='str', default=None), name=dict(required=False, type='str', default=None),
tags=dict(required=False, type="dict", default={}), tags=dict(required=False, type="dict", default={}),
@ -592,7 +651,10 @@ def main():
'general_purpose': 'generalPurpose', 'general_purpose': 'generalPurpose',
'max_io': 'maxIO' 'max_io': 'maxIO'
} }
encrypt = module.params.get('encrypt')
kms_key_id = module.params.get('kms_key_id')
performance_mode = performance_mode_translations[module.params.get('performance_mode')] performance_mode = performance_mode_translations[module.params.get('performance_mode')]
purge_tags = module.params.get('purge_tags')
changed = False changed = False
state = str(module.params.get('state')).lower() state = str(module.params.get('state')).lower()
@ -601,8 +663,8 @@ def main():
if not name: if not name:
module.fail_json(msg='Name parameter is required for create') module.fail_json(msg='Name parameter is required for create')
changed = connection.create_file_system(name, performance_mode) changed = connection.create_file_system(name, performance_mode, encrypt, kms_key_id)
changed = connection.converge_file_system(name=name, tags=tags, targets=targets) or changed changed = connection.converge_file_system(name=name, tags=tags, purge_tags=purge_tags, targets=targets) or changed
result = first_or_default(connection.get_file_systems(CreationToken=name)) result = first_or_default(connection.get_file_systems(CreationToken=name))
elif state == 'absent': elif state == 'absent':

Loading…
Cancel
Save