1#!/usr/local/bin/python3.8 2# -*- coding: utf-8 -*- 3 4# Copyright: (c) 2019, Sandeep Kasargod (sandeep@vexata.com) 5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 7from __future__ import absolute_import, division, print_function 8__metaclass__ = type 9 10 11DOCUMENTATION = r''' 12--- 13module: vexata_volume 14short_description: Manage volumes on Vexata VX100 storage arrays 15description: 16 - Create, deletes or extend volumes on a Vexata VX100 array. 17author: 18- Sandeep Kasargod (@vexata) 19options: 20 name: 21 description: 22 - Volume name. 23 required: true 24 type: str 25 state: 26 description: 27 - Creates/Modifies volume when present or removes when absent. 28 default: present 29 choices: [ present, absent ] 30 type: str 31 size: 32 description: 33 - Volume size in M, G, T units. M=2^20, G=2^30, T=2^40 bytes. 34 type: str 35extends_documentation_fragment: 36- community.general.vexata.vx100 37 38''' 39 40EXAMPLES = r''' 41- name: Create new 2 TiB volume named foo 42 community.general.vexata_volume: 43 name: foo 44 size: 2T 45 state: present 46 array: vx100_ultra.test.com 47 user: admin 48 password: secret 49 50- name: Expand volume named foo to 4 TiB 51 community.general.vexata_volume: 52 name: foo 53 size: 4T 54 state: present 55 array: vx100_ultra.test.com 56 user: admin 57 password: secret 58 59- name: Delete volume named foo 60 community.general.vexata_volume: 61 name: foo 62 state: absent 63 array: vx100_ultra.test.com 64 user: admin 65 password: secret 66''' 67 68RETURN = r''' 69''' 70 71from ansible.module_utils.basic import AnsibleModule 72from ansible_collections.community.general.plugins.module_utils.vexata import ( 73 argument_spec, get_array, required_together, size_to_MiB) 74 75 76def get_volume(module, array): 77 """Retrieve a named volume if it exists, None if absent.""" 78 name = module.params['name'] 79 try: 80 vols = array.list_volumes() 81 vol = filter(lambda v: v['name'] == name, vols) 82 if len(vol) == 1: 83 return vol[0] 84 else: 85 return None 86 except Exception: 87 module.fail_json(msg='Error while attempting to retrieve volumes.') 88 89 90def validate_size(module, err_msg): 91 size = module.params.get('size', False) 92 if not size: 93 module.fail_json(msg=err_msg) 94 size = size_to_MiB(size) 95 if size <= 0: 96 module.fail_json(msg='Invalid volume size, must be <integer>[MGT].') 97 return size 98 99 100def create_volume(module, array): 101 """"Create a new volume.""" 102 changed = False 103 size = validate_size(module, err_msg='Size is required to create volume.') 104 if module.check_mode: 105 module.exit_json(changed=changed) 106 107 try: 108 vol = array.create_volume( 109 module.params['name'], 110 'Ansible volume', 111 size) 112 if vol: 113 module.log(msg='Created volume {0}'.format(vol['id'])) 114 changed = True 115 else: 116 module.fail_json(msg='Volume create failed.') 117 except Exception: 118 pass 119 module.exit_json(changed=changed) 120 121 122def update_volume(module, array, volume): 123 """Expand the volume size.""" 124 changed = False 125 size = validate_size(module, err_msg='Size is required to update volume') 126 prev_size = volume['volSize'] 127 if size <= prev_size: 128 module.log(msg='Volume expanded size needs to be larger ' 129 'than current size.') 130 if module.check_mode: 131 module.exit_json(changed=changed) 132 133 try: 134 vol = array.grow_volume( 135 volume['name'], 136 volume['description'], 137 volume['id'], 138 size) 139 if vol: 140 changed = True 141 except Exception: 142 pass 143 144 module.exit_json(changed=changed) 145 146 147def delete_volume(module, array, volume): 148 changed = False 149 vol_name = volume['name'] 150 if module.check_mode: 151 module.exit_json(changed=changed) 152 153 try: 154 ok = array.delete_volume( 155 volume['id']) 156 if ok: 157 module.log(msg='Volume {0} deleted.'.format(vol_name)) 158 changed = True 159 else: 160 raise Exception 161 except Exception: 162 pass 163 module.exit_json(changed=changed) 164 165 166def main(): 167 arg_spec = argument_spec() 168 arg_spec.update( 169 dict( 170 name=dict(type='str', required=True), 171 state=dict(default='present', choices=['present', 'absent']), 172 size=dict(type='str') 173 ) 174 ) 175 176 module = AnsibleModule(arg_spec, 177 supports_check_mode=True, 178 required_together=required_together()) 179 180 state = module.params['state'] 181 array = get_array(module) 182 volume = get_volume(module, array) 183 184 if state == 'present': 185 if not volume: 186 create_volume(module, array) 187 else: 188 update_volume(module, array, volume) 189 elif state == 'absent' and volume: 190 delete_volume(module, array, volume) 191 else: 192 module.exit_json(changed=False) 193 194 195if __name__ == '__main__': 196 main() 197