Coverage for plugins/modules/purefb_realm.py: 88%
129 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-10-30 17:06 -0400
« prev ^ index » next coverage.py v7.14.1, created at 2026-10-30 17:06 -0400
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
4# Copyright: (c) 2026, Simon Dodsley (simon@everpuredata.com)
5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
7from __future__ import absolute_import, division, print_function
9__metaclass__ = type
11ANSIBLE_METADATA = {
12 "metadata_version": "1.1",
13 "status": ["preview"],
14 "supported_by": "community",
15}
17DOCUMENTATION = r"""
18---
19module: purefb_realm
20version_added: '1.25.0'
21short_description: Manage realms on Everpure FlashBlades
22description:
23- Create, delete or modify realms on Everpure FlashBlades.
24author:
25- Everpure Ansible Team (@sdodsley) <pure-ansible-team@everpuredata.com>
26options:
27 name:
28 description:
29 - The name of the realm.
30 - This has to be unique and not equal to any existing realm or pod.
31 type: str
32 required: true
33 without_default_access_list:
34 description:
35 - When creating a new realm, ensure it is created without any default resource accesses.
36 - Only used when creating a new realm.
37 - Purity//FB currently requires every realm to be created without the
38 default access list, so the array rejects C(false). The default is
39 therefore C(true); C(false) is passed through for Purity//FB versions
40 that accept it.
41 type: bool
42 default: true
43 version_added: '1.27.0'
44 state:
45 description:
46 - Define whether the realm should exist or not.
47 type: str
48 default: present
49 choices: [ absent, present ]
50 eradicate:
51 description:
52 - Define whether to eradicate the realm on delete or leave in trash.
53 type : bool
54 default: false
55 qos_policy:
56 description:
57 - QoS policy to apply to the realm
58 type: str
59 rename:
60 description:
61 - Value to rename the specified realm to
62 - This has to be unique and not equal to any existing realm or pods.
63 type: str
64extends_documentation_fragment:
65- everpure.flashblade.everpure.fb
66"""
68EXAMPLES = r"""
69- name: Create new realm
70 everpure.flashblade.purefb_realm:
71 name: foo
72 qos_policy: realm1_qos
73 fb_url: 10.10.10.2
74 api_token: T-9f276a18-50ab-446e-8a0c-666a3529a1b6
76- name: Destroy realm
77 everpure.flashblade.purefb_realm:
78 name: foo
79 fb_url: 10.10.10.2
80 api_token: T-9f276a18-50ab-446e-8a0c-666a3529a1b6
81 state: absent
83- name: Recover deleted realm
84 everpure.flashblade.purefb_realm:
85 name: foo
86 fb_url: 10.10.10.2
87 api_token: T-9f276a18-50ab-446e-8a0c-666a3529a1b6
89- name: Destroy and Eradicate realm
90 everpure.flashblade.purefb_realm:
91 name: foo
92 eradicate: true
93 fb_url: 10.10.10.2
94 api_token: T-9f276a18-50ab-446e-8a0c-666a3529a1b6
95 state: absent
97- name: Rename realm foo to bar
98 everpure.flashblade.purefb_realm:
99 name: foo
100 rename: bar
101 fb_url: 10.10.10.2
102 api_token: T-9f276a18-50ab-446e-8a0c-666a3529a1b6
103"""
105RETURN = r"""
106"""
108HAS_PURESTORAGE = True
109try:
110 from pypureclient.flashblade import RealmPatch
111except ImportError:
112 HAS_PURESTORAGE = False
114from ansible.module_utils.basic import AnsibleModule
115from ansible_collections.everpure.flashblade.plugins.module_utils.purefb import (
116 get_system,
117 purefb_argument_spec,
118)
119from ansible_collections.everpure.flashblade.plugins.module_utils.version import (
120 LooseVersion,
121)
122from ansible_collections.everpure.flashblade.plugins.module_utils.common import (
123 get_error_message,
124 get_rest_api_version,
125)
127MINIMUM_API_VERSION = "2.19"
130def get_pending_realm(module, blade):
131 """Get Deleted realm"""
132 res = blade.get_realms(destroyed=True, names=[module.params["name"]])
133 if res.status_code == 200:
134 return True
135 return None
138def get_policy(module, blade):
139 """Get QoS Policy"""
140 res = blade.get_qos_policies(names=[module.params["qos_policy"]])
141 if res.status_code == 200:
142 return True
143 return None
146def get_realm(module, blade):
147 """Get Realm"""
148 return _realm_exists(blade, module.params["name"])
151def _realm_exists(blade, name):
152 """Return True if a live (not destroyed) realm called name exists."""
153 res = blade.get_realms(destroyed=False, names=[name])
154 if res.status_code == 200:
155 return True
156 return None
159def rename_realm(module, blade):
160 changed = True
161 if not module.check_mode:
162 res = blade.patch_realms(
163 names=[module.params["name"]],
164 realm=RealmPatch(name=module.params["rename"]),
165 )
166 if res.status_code != 200:
167 module.fail_json(
168 msg="Rename to {0} failed. Error: {1}".format(
169 module.params["rename"], get_error_message(res)
170 )
171 )
172 module.exit_json(changed=changed)
175def make_realm(module, blade):
176 """Create Realm"""
177 changed = True
178 if module.params["qos_policy"] and not get_policy(module, blade):
179 module.fail_json(
180 msg="QoS policy {0} does not exist.".format(module.params["qos_policy"])
181 )
182 if not module.check_mode:
183 res = blade.post_realms(
184 names=[module.params["name"]],
185 without_default_access_list=module.params["without_default_access_list"],
186 )
187 if res.status_code != 200:
188 hint = ""
189 if not module.params["without_default_access_list"]:
190 hint = (
191 " This Purity//FB version requires realms to be created "
192 "without the default access list; set "
193 "without_default_access_list to true."
194 )
195 module.fail_json(
196 msg="Creation of realm {0} failed. Error: {1}{2}".format(
197 module.params["name"], get_error_message(res), hint
198 )
199 )
200 if module.params["qos_policy"]:
201 res = blade.post_qos_policies_members(
202 policy_names=[module.params["qos_policy"]],
203 member_names=[module.params["name"]],
204 member_types=["realms"],
205 )
206 if res.status_code != 200:
207 module.fail_json(
208 msg="QoS policy assignment failed for realm {0}. Error: {1}".format(
209 module.params["name"], get_error_message(res)
210 )
211 )
212 module.exit_json(changed=changed)
215def update_realm(module, blade):
216 """Update Realm QoS Policy"""
217 changed = False
218 # Get current QoS policy for the realm. A realm without a policy may
219 # come back as an error response, which has no items.
220 current_policy = None
221 res = blade.get_qos_policies_members(
222 member_types=["realms"], member_names=[module.params["name"]]
223 )
224 if res.status_code == 200:
225 first_member = next(iter(res.items), None)
226 current_policy = getattr(getattr(first_member, "policy", None), "name", None)
227 if module.params["qos_policy"] and current_policy != module.params["qos_policy"]:
228 if not get_policy(module, blade):
229 module.fail_json(
230 msg="QoS policy {0} does not exist.".format(module.params["qos_policy"])
231 )
232 changed = True
233 if not module.check_mode:
234 if current_policy:
235 res = blade.delete_qos_policies_members(
236 policy_names=[current_policy],
237 member_names=[module.params["name"]],
238 member_types=["realms"],
239 )
240 if res.status_code != 200:
241 module.fail_json(
242 msg="Existing QoS policy removal failed for realm {0}. Error: {1}".format(
243 module.params["name"], get_error_message(res)
244 )
245 )
246 res = blade.post_qos_policies_members(
247 policy_names=[module.params["qos_policy"]],
248 member_names=[module.params["name"]],
249 member_types=["realms"],
250 )
251 if res.status_code != 200:
252 module.fail_json(
253 msg="QoS policy assignment failed for realm {0}. Error: {1}".format(
254 module.params["name"], get_error_message(res)
255 )
256 )
257 module.exit_json(changed=changed)
260def recover_realm(module, blade):
261 """Recover Realm"""
262 changed = True
263 if not module.check_mode:
264 res = blade.patch_realms(
265 names=[module.params["name"]], realm=RealmPatch(destroyed=False)
266 )
267 if res.status_code != 200:
268 module.fail_json(
269 msg="Recovery of realm {0} failed. Error: {1}".format(
270 module.params["name"], get_error_message(res)
271 )
272 )
274 module.exit_json(changed=changed)
277def eradicate_realm(module, blade):
278 """Eradicate Realm"""
279 changed = True
280 if not module.check_mode:
281 res = blade.delete_realms(
282 names=[module.params["name"]],
283 )
284 if res.status_code != 200:
285 module.fail_json(
286 msg="Eradicating realm {0} failed. Error: {1}".format(
287 module.params["name"], get_error_message(res)
288 )
289 )
290 module.exit_json(changed=changed)
293def delete_realm(module, blade):
294 """Delete Realm"""
295 changed = True
296 if not module.check_mode:
297 res = blade.patch_realms(
298 names=[module.params["name"]],
299 realm=RealmPatch(destroyed=True),
300 )
301 if res.status_code != 200:
302 module.fail_json(
303 msg="Deleting realm {0} failed. Error: {1}".format(
304 module.params["name"], get_error_message(res)
305 )
306 )
307 if module.params["eradicate"]:
308 eradicate_realm(module, blade)
310 module.exit_json(changed=changed)
313def main():
314 argument_spec = purefb_argument_spec()
315 argument_spec.update(
316 dict(
317 name=dict(type="str", required=True),
318 without_default_access_list=dict(type="bool", default=True),
319 state=dict(type="str", default="present", choices=["absent", "present"]),
320 qos_policy=dict(type="str"),
321 eradicate=dict(type="bool", default=False),
322 rename=dict(type="str"),
323 )
324 )
326 module = AnsibleModule(argument_spec, supports_check_mode=True)
328 state = module.params["state"]
329 blade = get_system(module)
330 api_version = get_rest_api_version(blade)
331 if LooseVersion(MINIMUM_API_VERSION) > LooseVersion(api_version):
332 module.fail_json(
333 msg="Realms are not supported. Purity//FB 4.6.1, or higher, is required."
334 )
335 realm = get_realm(module, blade)
336 xrealm = get_pending_realm(module, blade)
338 if xrealm and state == "present":
339 recover_realm(module, blade)
340 elif realm and state == "absent":
341 delete_realm(module, blade)
342 elif xrealm and state == "absent" and module.params["eradicate"]:
343 eradicate_realm(module, blade)
344 elif not realm and not xrealm and state == "present":
345 if module.params["rename"] and _realm_exists(blade, module.params["rename"]):
346 # The rename already happened on an earlier run.
347 module.exit_json(changed=False)
348 make_realm(module, blade)
349 elif state == "present" and realm and module.params["rename"] and not xrealm:
350 rename_realm(module, blade)
351 elif realm and state == "present":
352 update_realm(module, blade)
353 elif realm is None and state == "absent":
354 module.exit_json(changed=False)
356 module.exit_json(changed=False)
359if __name__ == "__main__":
360 main()