EFS - add support for new Provisioned Throughput (#43253)

* efs.py: Add support for EFS provisioned throughput

* efs_facts.py: Add support for EFS provisioned throughput

* efs_facts integration tests updated with provision throughput

* efs_facts: Tests refactoring - add failure and success playbook according to botocore version.

* efs_facts: More tests and new option descriptions adjustment

* efs_facts tests renamed to efs
This commit is contained in:
Julien PRIGENT 2018-09-19 00:10:56 +01:00 committed by Will Thames
commit 6059246093
7 changed files with 252 additions and 7 deletions

View file

@ -70,6 +70,18 @@ options:
- ip_address - Optional. A valid IPv4 address within the address range of the specified subnet.
- security_groups - Optional. List of security group IDs, of the form 'sg-xxxxxxxx'. These must be for the same VPC as subnet specified
This data may be modified for existing EFS using state 'present' and new list of mount targets."
throughput_mode:
description:
- The throughput_mode for the file system to be created.
- Requires botocore >= 1.10.57
choices: ['bursting', 'provisioned']
version_added: 2.8
provisioned_throughput_in_mibps:
description:
- If the throughput_mode is provisioned, select the amount of throughput to provisioned in Mibps.
- Requires botocore >= 1.10.57
type: float
version_added: 2.8
wait:
description:
- "In case of 'present' state should wait for EFS 'available' life cycle state (of course, if current state not 'deleting' or 'deleted')
@ -80,6 +92,7 @@ options:
description:
- How long the module should wait (in seconds) for desired state before returning. Zero means wait as long as necessary.
default: 0
extends_documentation_fragment:
- aws
- ec2
@ -350,7 +363,36 @@ class EFSConnection(object):
return list(targets)
def create_file_system(self, name, performance_mode, encrypt, kms_key_id):
def supports_provisioned_mode(self):
"""
Ensure boto3 includes provisioned throughput mode feature
"""
return hasattr(self.connection, 'update_file_system')
def get_throughput_mode(self, **kwargs):
"""
Returns throughput mode for selected EFS instance
"""
info = first_or_default(iterate_all(
'FileSystems',
self.connection.describe_file_systems,
**kwargs
))
return info and info['ThroughputMode'] or None
def get_provisioned_throughput_in_mibps(self, **kwargs):
"""
Returns throughput mode for selected EFS instance
"""
info = first_or_default(iterate_all(
'FileSystems',
self.connection.describe_file_systems,
**kwargs
))
return info.get('ProvisionedThroughputInMibps', None)
def create_file_system(self, name, performance_mode, encrypt, kms_key_id, throughput_mode, provisioned_throughput_in_mibps):
"""
Creates new filesystem with selected name
"""
@ -363,6 +405,16 @@ class EFSConnection(object):
params['Encrypted'] = encrypt
if kms_key_id is not None:
params['KmsKeyId'] = kms_key_id
if throughput_mode:
if self.supports_provisioned_mode():
params['ThroughputMode'] = throughput_mode
else:
self.module.fail_json(msg="throughput_mode parameter requires botocore >= 1.10.57")
if provisioned_throughput_in_mibps:
if self.supports_provisioned_mode():
params['ProvisionedThroughputInMibps'] = provisioned_throughput_in_mibps
else:
self.module.fail_json(msg="provisioned_throughput_in_mibps parameter requires botocore >= 1.10.57")
if state in [self.STATE_DELETING, self.STATE_DELETED]:
wait_for(
@ -390,7 +442,39 @@ class EFSConnection(object):
return changed
def converge_file_system(self, name, tags, purge_tags, targets):
def update_file_system(self, name, throughput_mode, provisioned_throughput_in_mibps):
"""
Update filesystem with new throughput settings
"""
changed = False
state = self.get_file_system_state(name)
if state in [self.STATE_AVAILABLE, self.STATE_CREATING]:
fs_id = self.get_file_system_id(name)
current_mode = self.get_throughput_mode(FileSystemId=fs_id)
current_throughput = self.get_provisioned_throughput_in_mibps(FileSystemId=fs_id)
params = dict()
if throughput_mode and throughput_mode != current_mode:
params['ThroughputMode'] = throughput_mode
if provisioned_throughput_in_mibps and provisioned_throughput_in_mibps != current_throughput:
params['ProvisionedThroughputInMibps'] = provisioned_throughput_in_mibps
if len(params) > 0:
wait_for(
lambda: self.get_file_system_state(name),
self.STATE_AVAILABLE,
self.wait_timeout
)
try:
self.connection.update_file_system(FileSystemId=fs_id, **params)
changed = True
except ClientError as e:
self.module.fail_json(msg="Unable to update 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 update file system: {0}".format(to_native(e)),
exception=traceback.format_exc())
return changed
def converge_file_system(self, name, tags, purge_tags, targets, throughput_mode, provisioned_throughput_in_mibps):
"""
Change attributes (mount targets and tags) of filesystem by name
"""
@ -620,12 +704,13 @@ def main():
tags=dict(required=False, type="dict", default={}),
targets=dict(required=False, type="list", default=[]),
performance_mode=dict(required=False, type='str', choices=["general_purpose", "max_io"], default="general_purpose"),
throughput_mode=dict(required=False, type='str', choices=["bursting", "provisioned"], default=None),
provisioned_throughput_in_mibps=dict(required=False, type=float),
wait=dict(required=False, type="bool", default=False),
wait_timeout=dict(required=False, type="int", default=0)
))
module = AnsibleModule(argument_spec=argument_spec)
if not HAS_BOTO3:
module.fail_json(msg='boto3 required for this module')
@ -649,16 +734,20 @@ def main():
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
throughput_mode = module.params.get('throughput_mode')
provisioned_throughput_in_mibps = module.params.get('provisioned_throughput_in_mibps')
state = str(module.params.get('state')).lower()
changed = False
if state == 'present':
if not name:
module.fail_json(msg='Name parameter is required for create')
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
changed = connection.create_file_system(name, performance_mode, encrypt, kms_key_id, throughput_mode, provisioned_throughput_in_mibps)
if connection.supports_provisioned_mode():
changed = connection.update_file_system(name, throughput_mode, provisioned_throughput_in_mibps) or changed
changed = connection.converge_file_system(name=name, tags=tags, purge_tags=purge_tags, targets=targets,
throughput_mode=throughput_mode, provisioned_throughput_in_mibps=provisioned_throughput_in_mibps) or changed
result = first_or_default(connection.get_file_systems(CreationToken=name))
elif state == 'absent':

View file

@ -141,6 +141,16 @@ performance_mode:
returned: always
type: str
sample: "generalPurpose"
throughput_mode:
description: mode of throughput for the file system
returned: when botocore >= 1.10.57
type: str
sample: "bursting"
provisioned_throughput_in_mibps:
description: throughput provisioned in Mibps
returned: when botocore >= 1.10.57 and throughput_mode is set to "provisioned"
type: float
sample: 15.0
tags:
description: tags on the efs instance
returned: always