summaryrefslogtreecommitdiffstats
path: root/ansible_collections/purestorage/fusion/plugins/modules/fusion_sc.py
blob: 59fc0025ecf59e6d856878932d527f5434e359ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2022, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING.GPLv3 or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = r"""
---
module: fusion_sc
version_added: '1.0.0'
short_description:  Manage storage classes in Pure Storage Fusion
description:
- Manage a storage class in Pure Storage Fusion.
notes:
- Supports C(check_mode).
- It is not currently possible to update bw_limit or
  iops_limit after a storage class has been created.
author:
- Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
  name:
    description:
    - The name of the storage class.
    type: str
    required: true
  state:
    description:
    - Define whether the storage class should exist or not.
    default: present
    choices: [ present, absent ]
    type: str
  display_name:
    description:
    - The human name of the storage class.
    - If not provided, defaults to I(name).
    type: str
  size_limit:
    description:
    - Volume size limit in M, G, T or P units.
    - Must be between 1MB and 4PB.
    - If not provided at creation, this will default to 4PB.
    type: str
  bw_limit:
    description:
    - The bandwidth limit in M or G units.
      M will set MB/s.
      G will set GB/s.
    - Must be between 1MB/s and 512GB/s.
    - If not provided at creation, this will default to 512GB/s.
    type: str
  iops_limit:
    description:
    - The IOPs limit - use value or K or M.
      K will mean 1000.
      M will mean 1000000.
    - Must be between 100 and 100000000.
    - If not provided at creation, this will default to 100000000.
    type: str
  storage_service:
    description:
    - Storage service to which the storage class belongs.
    type: str
    required: true
extends_documentation_fragment:
- purestorage.fusion.purestorage.fusion
"""

EXAMPLES = r"""
- name: Create new storage class foo
  purestorage.fusion.fusion_sc:
    name: foo
    size_limit: 100G
    iops_limit: 100000
    bw_limit: 25M
    storage_service: service1
    display_name: "test class"
    issuer_id: key_name
    private_key_file: "az-admin-private-key.pem"

- name: Update storage class (only display_name change is supported)
  purestorage.fusion.fusion_sc:
    name: foo
    display_name: "main class"
    storage_service: service1
    issuer_id: key_name
    private_key_file: "az-admin-private-key.pem"

- name: Delete storage class
  purestorage.fusion.fusion_sc:
    name: foo
    storage_service: service1
    state: absent
    issuer_id: key_name
    private_key_file: "az-admin-private-key.pem"
"""

RETURN = r"""
"""

try:
    import fusion as purefusion
except ImportError:
    pass

from ansible.module_utils.basic import AnsibleModule
from ansible_collections.purestorage.fusion.plugins.module_utils.fusion import (
    fusion_argument_spec,
)

from ansible_collections.purestorage.fusion.plugins.module_utils.parsing import (
    parse_number_with_metric_suffix,
)
from ansible_collections.purestorage.fusion.plugins.module_utils.startup import (
    setup_fusion,
)
from ansible_collections.purestorage.fusion.plugins.module_utils.operations import (
    await_operation,
)


def get_sc(module, fusion):
    """Return Storage Class or None"""
    sc_api_instance = purefusion.StorageClassesApi(fusion)
    try:
        return sc_api_instance.get_storage_class(
            storage_class_name=module.params["name"],
            storage_service_name=module.params["storage_service"],
        )
    except purefusion.rest.ApiException:
        return None


def create_sc(module, fusion):
    """Create Storage Class"""

    sc_api_instance = purefusion.StorageClassesApi(fusion)

    if not module.params["size_limit"]:
        module.params["size_limit"] = "4P"
    if not module.params["iops_limit"]:
        module.params["iops_limit"] = "100000000"
    if not module.params["bw_limit"]:
        module.params["bw_limit"] = "512G"
    size_limit = parse_number_with_metric_suffix(module, module.params["size_limit"])
    iops_limit = int(
        parse_number_with_metric_suffix(
            module, module.params["iops_limit"], factor=1000
        )
    )
    bw_limit = parse_number_with_metric_suffix(module, module.params["bw_limit"])
    if bw_limit < 1048576 or bw_limit > 549755813888:  # 1MB/s to 512GB/s
        module.fail_json(msg="Bandwidth limit is not within the required range")
    if iops_limit < 100 or iops_limit > 100_000_000:
        module.fail_json(msg="IOPs limit is not within the required range")
    if size_limit < 1048576 or size_limit > 4503599627370496:  # 1MB to 4PB
        module.fail_json(msg="Size limit is not within the required range")

    changed = True
    id = None
    if not module.check_mode:
        if not module.params["display_name"]:
            display_name = module.params["name"]
        else:
            display_name = module.params["display_name"]
        s_class = purefusion.StorageClassPost(
            name=module.params["name"],
            size_limit=size_limit,
            iops_limit=iops_limit,
            bandwidth_limit=bw_limit,
            display_name=display_name,
        )
        op = sc_api_instance.create_storage_class(
            s_class, storage_service_name=module.params["storage_service"]
        )
        res_op = await_operation(fusion, op)
        id = res_op.result.resource.id

    module.exit_json(changed=changed, id=id)


def update_sc(module, fusion, s_class):
    """Update Storage Class settings"""
    changed = False
    sc_api_instance = purefusion.StorageClassesApi(fusion)

    if (
        module.params["display_name"]
        and module.params["display_name"] != s_class.display_name
    ):
        changed = True
        if not module.check_mode:
            sclass = purefusion.StorageClassPatch(
                display_name=purefusion.NullableString(module.params["display_name"])
            )
            op = sc_api_instance.update_storage_class(
                sclass,
                storage_service_name=module.params["storage_service"],
                storage_class_name=module.params["name"],
            )
            await_operation(fusion, op)

    module.exit_json(changed=changed, id=s_class.id)


def delete_sc(module, fusion):
    """Delete Storage Class"""
    sc_api_instance = purefusion.StorageClassesApi(fusion)
    changed = True
    if not module.check_mode:
        op = sc_api_instance.delete_storage_class(
            storage_class_name=module.params["name"],
            storage_service_name=module.params["storage_service"],
        )
        await_operation(fusion, op)

    module.exit_json(changed=changed)


def main():
    """Main code"""
    argument_spec = fusion_argument_spec()
    argument_spec.update(
        dict(
            name=dict(type="str", required=True),
            display_name=dict(type="str"),
            iops_limit=dict(type="str"),
            bw_limit=dict(type="str"),
            size_limit=dict(type="str"),
            storage_service=dict(type="str", required=True),
            state=dict(type="str", default="present", choices=["present", "absent"]),
        )
    )

    module = AnsibleModule(argument_spec, supports_check_mode=True)
    fusion = setup_fusion(module)

    state = module.params["state"]
    s_class = get_sc(module, fusion)

    if not s_class and state == "present":
        create_sc(module, fusion)
    elif s_class and state == "present":
        update_sc(module, fusion, s_class)
    elif s_class and state == "absent":
        delete_sc(module, fusion)
    else:
        module.exit_json(changed=False)

    module.exit_json(changed=False)


if __name__ == "__main__":
    main()