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