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

* Add encryption support to efs module

* Update the exception handling in AWS EFS module
This commit is contained in:
Rob 2017-12-22 05:51:46 +11:00 committed by Ryan Brown
parent f0cf1b35d5
commit 2616f9d713

View file

@ -23,6 +23,29 @@ author:
- "Ryan Sydnor (@ryansydnor)"
- "Artem Kazakov (@akazakov)"
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:
description:
- Allows to create, search and destroy Amazon EFS file system
@ -74,6 +97,7 @@ options:
default: 0
extends_documentation_fragment:
- aws
- ec2
'''
EXAMPLES = '''
@ -193,15 +217,18 @@ tags:
from time import sleep
from time import time as timestamp
import traceback
try:
from botocore.exceptions import ClientError
from botocore.exceptions import ClientError, BotoCoreError
except ImportError as e:
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.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):
@ -221,6 +248,8 @@ class EFSConnection(object):
self.connection = boto3_conn(module, conn_type='client',
resource='efs', region=region,
**aws_connect_params)
self.module = module
self.region = region
self.wait = module.params.get('wait')
self.wait_timeout = module.params.get('wait_timeout')
@ -256,12 +285,8 @@ class EFSConnection(object):
"""
Returns tag list for selected instance of EFS
"""
tags = iterate_all(
'Tags',
self.connection.describe_tags,
**kwargs
)
return dict((tag['Key'], tag['Value']) for tag in tags)
tags = self.connection.describe_tags(**kwargs)['Tags']
return tags
def get_mount_targets(self, **kwargs):
"""
@ -331,19 +356,34 @@ class EFSConnection(object):
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
"""
changed = False
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]:
wait_for(
lambda: self.get_file_system_state(name),
self.STATE_DELETED
)
self.connection.create_file_system(CreationToken=name, PerformanceMode=performance_mode)
changed = True
try:
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.
# if we try to take any actions on the file system before it's available
@ -356,7 +396,7 @@ class EFSConnection(object):
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
"""
@ -364,20 +404,36 @@ class EFSConnection(object):
fs_id = self.get_file_system_id(name)
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:
self.connection.delete_tags(
FileSystemId=fs_id,
TagKeys=[item[0] for item in tags_to_delete]
)
try:
self.connection.delete_tags(
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
if tags_to_create:
self.connection.create_tags(
FileSystemId=fs_id,
Tags=[{'Key': item[0], 'Value': item[1]} for item in tags_to_create]
)
if tags_need_modify:
try:
self.connection.create_tags(
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
if targets is not None:
@ -561,7 +617,10 @@ def main():
"""
argument_spec = ec2_argument_spec()
argument_spec.update(dict(
encrypt=dict(required=False, type="bool", default=False),
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),
name=dict(required=False, type='str', default=None),
tags=dict(required=False, type="dict", default={}),
@ -592,7 +651,10 @@ def main():
'general_purpose': 'generalPurpose',
'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')]
purge_tags = module.params.get('purge_tags')
changed = False
state = str(module.params.get('state')).lower()
@ -601,8 +663,8 @@ def main():
if not name:
module.fail_json(msg='Name parameter is required for create')
changed = connection.create_file_system(name, performance_mode)
changed = connection.converge_file_system(name=name, tags=tags, targets=targets) or changed
changed = connection.create_file_system(name, performance_mode, encrypt, kms_key_id)
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))
elif state == 'absent':