From d508d5820a6016259a1ce683ee819c3c1d0b957e Mon Sep 17 00:00:00 2001 From: Simon Dodsley Date: Sat, 10 Nov 2018 04:08:28 -0500 Subject: [PATCH] Update Pure Storage FlashArray volume module (#45225) --- .../storage/purestorage/purefa_volume.py | 128 +++++++++++++----- 1 file changed, 95 insertions(+), 33 deletions(-) diff --git a/lib/ansible/modules/storage/purestorage/purefa_volume.py b/lib/ansible/modules/storage/purestorage/purefa_volume.py index 052d2e1a0c4..545f6bff353 100644 --- a/lib/ansible/modules/storage/purestorage/purefa_volume.py +++ b/lib/ansible/modules/storage/purestorage/purefa_volume.py @@ -46,15 +46,22 @@ options: size: description: - Volume size in M, G, T or P units. + qos: + description: + - Bandwidth limit for volume in M or G units. + M will set MB/s + G will set GB/s + version_added: '2.8' extends_documentation_fragment: - purestorage.fa ''' EXAMPLES = r''' -- name: Create new volume named foo +- name: Create new volume named foo with a QoS limit purefa_volume: name: foo size: 1T + qos: 58M fa_url: 10.10.10.2 api_token: e31060a7-21fc-e277-6240-25983c6c4592 state: present @@ -96,12 +103,6 @@ EXAMPLES = r''' RETURN = r''' ''' -try: - from purestorage import purestorage - HAS_PURESTORAGE = True -except ImportError: - HAS_PURESTORAGE = False - from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.pure import get_system, purefa_argument_spec @@ -138,6 +139,17 @@ def get_volume(module, array): return None +def get_destroyed_volume(module, array): + """Return Destroyed Volume or None""" + try: + if array.get_volume(module.params['name'], pending=True)['time_remaining'] != '': + return True + else: + return False + except: + return False + + def get_target(module, array): """Return Volume or None""" try: @@ -148,13 +160,24 @@ def get_target(module, array): def create_volume(module, array): """Create Volume""" - size = module.params['size'] - changed = True - if not module.check_mode: + changed = False + if module.params['qos']: + if 549755813888 >= int(human_to_bytes(module.params['qos'])) >= 1048576: + try: + array.create_volume(module.params['name'], module.params['size'], + bandwidth_limit=module.params['qos']) + changed = True + except: + module.fail_json(msg='Volume {0} creation failed.'.format(module.params['name'])) + else: + module.fail_json(msg='QoS value {0} out of range.'.format(module.params['qos'])) + else: try: - array.create_volume(module.params['name'], size) + array.create_volume(module.params['name'], module.params['size']) + changed = True except: - changed = False + module.fail_json(msg='Volume {0} creation failed.'.format(module.params['name'])) + module.exit_json(changed=changed) @@ -165,35 +188,59 @@ def copy_from_volume(module, array): tgt = get_target(module, array) if tgt is None: - changed = True - if not module.check_mode: + try: array.copy_volume(module.params['name'], module.params['target']) + changed = True + except: + module.fail_json(msg='Copy volume {0} to volume {1} failed.'.format(module.params['name'], + module.params['target'])) elif tgt is not None and module.params['overwrite']: - changed = True - if not module.check_mode: + try: array.copy_volume(module.params['name'], module.params['target'], overwrite=module.params['overwrite']) + changed = True + except: + module.fail_json(msg='Copy volume {0} to volume {1} failed.'.format(module.params['name'], + module.params['target'])) module.exit_json(changed=changed) def update_volume(module, array): - """Update Volume""" - changed = True + """Update Volume size and/or QoS""" + changed = False vol = array.get_volume(module.params['name']) - if human_to_bytes(module.params['size']) > vol['size']: - if not module.check_mode: - array.extend_volume(module.params['name'], module.params['size']) - else: - changed = False + vol_qos = array.get_volume(module.params['name'], qos=True) + if vol_qos['bandwidth_limit'] is None: + vol_qos['bandwidth_limit'] = 0 + if module.params['size']: + if human_to_bytes(module.params['size']) != vol['size']: + if human_to_bytes(module.params['size']) > vol['size']: + try: + array.extend_volume(module.params['name'], module.params['size']) + changed = True + except: + module.fail_json(msg='Volume {0} resize failed.'.format(module.params['name'])) + if module.params['qos']: + if human_to_bytes(module.params['qos']) != vol_qos['bandwidth_limit']: + if 549755813888 >= int(human_to_bytes(module.params['qos'])) >= 1048576: + try: + array.set_volume(module.params['name'], + bandwidth_limit=module.params['qos']) + changed = True + except: + module.fail_json(msg='Volume {0} QoS change failed.'.format(module.params['name'])) + else: + module.fail_json(msg='QoS value {0} out of range. Check documentation.'.format(module.params['qos'])) + module.exit_json(changed=changed) def delete_volume(module, array): """ Delete Volume""" - changed = True + changed = False if not module.check_mode: try: array.destroy_volume(module.params['name']) @@ -201,10 +248,22 @@ def delete_volume(module, array): try: array.eradicate_volume(module.params['name']) except: - changed = False + module.fail_json(msg='Eradicate volume {0} failed.'.format(module.params['name'])) + changed = True except: - changed = False - module.exit_json(changed=True) + module.fail_json(msg='Delete volume {0} failed.'.format(module.params['name'])) + module.exit_json(changed=changed) + + +def eradicate_volume(module, array): + """ Eradicate Deleted Volume""" + changed = False + try: + array.eradicate_volume(module.params['name']) + changed = True + except: + module.fail_json(msg='Eradication of volume {0} failed'.format(module.params['name'])) + module.exit_json(changed=changed) def main(): @@ -215,27 +274,28 @@ def main(): overwrite=dict(type='bool', default=False), eradicate=dict(type='bool', default=False), state=dict(type='str', default='present', choices=['absent', 'present']), + qos=dict(type='str'), size=dict(type='str'), )) - mutually_exclusive = [['size', 'target']] + mutually_exclusive = [['size', 'target'], ['qos', 'target']] module = AnsibleModule(argument_spec, mutually_exclusive=mutually_exclusive, - supports_check_mode=True) - - if not HAS_PURESTORAGE: - module.fail_json(msg='purestorage sdk is required for this module in volume') + supports_check_mode=False) size = module.params['size'] + qos = module.params['qos'] state = module.params['state'] array = get_system(module) volume = get_volume(module, array) + if not volume: + destroyed = get_destroyed_volume(module, array) target = get_target(module, array) if state == 'present' and not volume and size: create_volume(module, array) - elif state == 'present' and volume and size: + elif state == 'present' and volume and (size or qos): update_volume(module, array) elif state == 'present' and volume and target: copy_from_volume(module, array) @@ -243,6 +303,8 @@ def main(): copy_from_volume(module, array) elif state == 'absent' and volume: delete_volume(module, array) + elif state == 'absent' and destroyed: + eradicate_volume(module, array) elif state == 'present' and not volume or not size: module.exit_json(changed=False) elif state == 'absent' and not volume: