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

1#!/usr/bin/python 

2# -*- coding: utf-8 -*- 

3 

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) 

6 

7from __future__ import absolute_import, division, print_function 

8 

9__metaclass__ = type 

10 

11ANSIBLE_METADATA = { 

12 "metadata_version": "1.1", 

13 "status": ["preview"], 

14 "supported_by": "community", 

15} 

16 

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""" 

67 

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 

75 

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 

82 

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 

88 

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 

96 

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""" 

104 

105RETURN = r""" 

106""" 

107 

108HAS_PURESTORAGE = True 

109try: 

110 from pypureclient.flashblade import RealmPatch 

111except ImportError: 

112 HAS_PURESTORAGE = False 

113 

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) 

126 

127MINIMUM_API_VERSION = "2.19" 

128 

129 

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 

136 

137 

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 

144 

145 

146def get_realm(module, blade): 

147 """Get Realm""" 

148 return _realm_exists(blade, module.params["name"]) 

149 

150 

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 

157 

158 

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) 

173 

174 

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) 

213 

214 

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) 

258 

259 

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 ) 

273 

274 module.exit_json(changed=changed) 

275 

276 

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) 

291 

292 

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) 

309 

310 module.exit_json(changed=changed) 

311 

312 

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 ) 

325 

326 module = AnsibleModule(argument_spec, supports_check_mode=True) 

327 

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) 

337 

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) 

355 

356 module.exit_json(changed=False) 

357 

358 

359if __name__ == "__main__": 

360 main()