Coverage for plugins/modules/purefb_fs.py: 80%

440 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# (c) 2017, 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 

11 

12ANSIBLE_METADATA = { 

13 "metadata_version": "1.1", 

14 "status": ["preview"], 

15 "supported_by": "community", 

16} 

17 

18 

19DOCUMENTATION = """ 

20--- 

21module: purefb_fs 

22version_added: "1.0.0" 

23short_description: Manage filesystemon Everpure FlashBlade` 

24description: 

25 - This module manages filesystems on Everpure FlashBlade. 

26author: Everpure Ansible Team (@sdodsley) <pure-ansible-team@everpuredata.com> 

27options: 

28 name: 

29 description: 

30 - Filesystem Name. 

31 required: true 

32 type: str 

33 state: 

34 description: 

35 - Create, delete or modifies a filesystem. 

36 required: false 

37 default: present 

38 type: str 

39 choices: [ "present", "absent" ] 

40 eradicate: 

41 description: 

42 - Define whether to eradicate the filesystem on delete or leave in trash. 

43 required: false 

44 type: bool 

45 default: false 

46 size: 

47 description: 

48 - Volume size in M, G, T or P units. See examples. 

49 - If size is not set at filesystem creation time the filesystem size becomes unlimited. 

50 type: str 

51 required: false 

52 nfsv3: 

53 description: 

54 - Define whether to NFSv3 protocol is enabled for the filesystem. 

55 required: false 

56 type: bool 

57 default: true 

58 nfsv4: 

59 description: 

60 - Define whether to NFSv4.1 protocol is enabled for the filesystem. 

61 required: false 

62 type: bool 

63 default: true 

64 nfs_rules: 

65 description: 

66 - Define the NFS client export rules for the filesystem, for example 

67 C(10.21.200.0/24(rw,no_root_squash)). 

68 - Deprecated. Use the M(everpure.flashblade.purefb_export) module to 

69 attach NFS export policies via the File System Exports endpoints. 

70 This parameter will be removed in 2.0.0. 

71 - Only honoured when explicitly set, and only for non-realm 

72 filesystems. It is ignored for filesystems in a realm. 

73 required: false 

74 type: str 

75 smb: 

76 description: 

77 - Define whether to SMB protocol is enabled for the filesystem. 

78 - Defaults to C(false) when the filesystem is created. On an existing 

79 filesystem the protocol is only changed when this option is set. 

80 required: false 

81 type: bool 

82 smb_aclmode: 

83 description: 

84 - Specify the ACL mode for the SMB protocol. 

85 - Deprecated from Purity//FB 3.1.1. Use I(access_control) instead. 

86 required: false 

87 type: str 

88 default: shared 

89 choices: [ "shared", "native" ] 

90 http: 

91 description: 

92 - Define whether to HTTP/HTTPS protocol is enabled for the filesystem. 

93 - Defaults to C(false) when the filesystem is created. On an existing 

94 filesystem the protocol is only changed when this option is set. 

95 required: false 

96 type: bool 

97 snapshot: 

98 description: 

99 - Define whether a snapshot directory is enabled for the filesystem. 

100 - Defaults to C(false) when the filesystem is created. On an existing 

101 filesystem the setting is only changed when this option is set. 

102 required: false 

103 type: bool 

104 writable: 

105 description: 

106 - Define if a filesystem is writable. 

107 required: false 

108 type: bool 

109 promote: 

110 description: 

111 - Promote/demote a filesystem. 

112 - Can only demote the file-system if it is in a replica-link relationship. 

113 required: false 

114 type: bool 

115 fastremove: 

116 description: 

117 - Define whether the fast remove directory is enabled for the filesystem. 

118 - Defaults to C(false) when the filesystem is created. On an existing 

119 filesystem the setting is only changed when this option is set. 

120 required: false 

121 type: bool 

122 hard_limit: 

123 description: 

124 - Define whether the capacity for a filesystem is a hard limit. 

125 - CAUTION This will cause the filesystem to go Read-Only if the 

126 capacity has already exceeded the logical size of the filesystem. 

127 - Defaults to C(false) when the filesystem is created. On an existing 

128 filesystem the setting is only changed when this option is set. 

129 required: false 

130 type: bool 

131 user_quota: 

132 description: 

133 - Default quota in M, G, T or P units for a user under this file system. 

134 required: false 

135 type: str 

136 group_quota: 

137 description: 

138 - Default quota in M, G, T or P units for a group under this file system. 

139 required: false 

140 type: str 

141 policy: 

142 description: 

143 - Filesystem policy to assign to or remove from a filesystem. 

144 required: false 

145 type: str 

146 policy_state: 

147 description: 

148 - Add or delete a policy from a filesystem 

149 required: false 

150 default: present 

151 type: str 

152 choices: [ "absent", "present" ] 

153 delete_link: 

154 description: 

155 - Define if the filesystem can be deleted even if it has a replica link 

156 required: false 

157 default: false 

158 type: bool 

159 discard_snaps: 

160 description: 

161 - Allow a filesystem to be demoted. 

162 required: false 

163 default: false 

164 type: bool 

165 access_control: 

166 description: 

167 - The access control style that is utilized for client actions such 

168 as setting file and directory ACLs. 

169 type: str 

170 default: shared 

171 choices: [ 'nfs', 'smb', 'shared', 'independent', 'mode-bits' ] 

172 safeguard_acls: 

173 description: 

174 - Safeguards ACLs on a filesystem. 

175 - Performs different roles depending on the filesystem protocol enabled. 

176 - See Purity//FB documentation for detailed description. 

177 - Defaults to C(true) when the filesystem is created. On an existing 

178 filesystem the setting is only changed when this option is set. 

179 type: bool 

180 export_policy: 

181 description: 

182 - Name of NFS export policy to assign to filesystem. 

183 - Deprecated. This writes the legacy C(nfs.export_policy) field 

184 on the filesystem, which Purity//FB marks as deprecated. Use the 

185 M(everpure.flashblade.purefb_export) module's C(export_policy) 

186 option to attach NFS export policies via the dedicated File 

187 System Exports endpoints. 

188 This parameter will be removed in 2.0.0. 

189 type: str 

190 version_added: "1.9.0" 

191 share_policy: 

192 description: 

193 - Name of SMB share policy to assign to filesystem 

194 - Only valid with REST 2.10 or higher 

195 - Remove policy with empty string 

196 - Deprecated. This writes the legacy C(smb.share_policy) field 

197 on the filesystem, which Purity//FB marks as deprecated. Use the 

198 M(everpure.flashblade.purefb_export) module's C(share_policy) 

199 option to attach SMB share policies via the dedicated File 

200 System Exports endpoints. 

201 This parameter will be removed in 2.0.0. 

202 type: str 

203 version_added: "1.12.0" 

204 client_policy: 

205 description: 

206 - Name of SMB client policy to assign to filesystem 

207 - Only valid with REST 2.10 or higher 

208 - Remove policy with empty string 

209 - Deprecated. This writes the legacy C(smb.client_policy) field 

210 on the filesystem, which Purity//FB marks as deprecated. Use the 

211 M(everpure.flashblade.purefb_export) module's C(client_policy) 

212 option to attach SMB client policies via the dedicated File 

213 System Exports endpoints. 

214 This parameter will be removed in 2.0.0. 

215 type: str 

216 version_added: "1.12.0" 

217 continuous_availability: 

218 description: 

219 - Defines if the file system will be continuously available during 

220 disruptive scenarios such as network disruption, blades failover, etc 

221 type: bool 

222 default: true 

223 version_added: "1.15.0" 

224 group_ownership: 

225 description: 

226 - The group ownership for new files and directories in a file system 

227 type: str 

228 choices: [ 'creator', 'parent-directory' ] 

229 default: creator 

230 version_added: "1.17.0" 

231 ignore_usage: 

232 description: 

233 - Allow update operations that lead to a hard_limit_enabled file 

234 system with usage over its limiting value 

235 type: bool 

236 default: false 

237 version_added: "1.22.0" 

238 cancel_in_progress: 

239 description: 

240 - Whether to cancel any existing storage class transitons that are in progress 

241 if the file system is requested to changed to another storage class 

242 type: bool 

243 default: false 

244 version_added: "1.22.0" 

245 storage_class: 

246 description: 

247 - Name of storage class in Fusion fleet file system is associated with 

248 type: str 

249 version_added: "1.22.0" 

250 context: 

251 description: 

252 - Name of fleet member on which to perform the operation. 

253 - This requires the array receiving the request is a member of a fleet 

254 and the context name to be a member of the same fleet. 

255 type: str 

256 default: "" 

257 version_added: "1.22.0" 

258 realm: 

259 description: 

260 - Name of the realm to associate the filesystem with. 

261 - Requires Purity//FB 4.6.1+ (REST API 2.19+). 

262 - Can only be set at filesystem creation time. 

263 - To move a filesystem to a different realm, the filesystem must be destroyed and recreated. 

264 - If the realm has a QoS policy, the filesystem will inherit it unless overridden. 

265 type: str 

266 version_added: "1.25.0" 

267extends_documentation_fragment: 

268 - everpure.flashblade.everpure.fb 

269""" 

270 

271EXAMPLES = """ 

272- name: Create new filesystem named foo 

273 everpure.flashblade.purefb_fs: 

274 name: foo 

275 size: 1T 

276 state: present 

277 fb_url: 10.10.10.2 

278 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 

279 

280- name: Create new filesystem in realm 

281 everpure.flashblade.purefb_fs: 

282 name: prod-fs 

283 size: 5T 

284 realm: production-realm 

285 state: present 

286 fb_url: 10.10.10.2 

287 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 

288 # Filesystem will be created as 'production-realm::prod-fs' 

289 

290- name: Modify filesystem that belongs to a realm 

291 everpure.flashblade.purefb_fs: 

292 name: production-realm::prod-fs 

293 size: 10T 

294 nfsv4: false 

295 state: present 

296 fb_url: 10.10.10.2 

297 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 

298 # Note: Use full realm::filesystem name for modifications 

299 # Realm association cannot be changed after creation 

300 

301- name: Delete filesystem named foo 

302 everpure.flashblade.purefb_fs: 

303 name: foo 

304 state: absent 

305 fb_url: 10.10.10.2 

306 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 

307 

308- name: Recover filesystem named foo 

309 everpure.flashblade.purefb_fs: 

310 name: foo 

311 state: present 

312 fb_url: 10.10.10.2 

313 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 

314 

315- name: the iss that ven thou hth ansible Eradicate filesystem named foo 

316 everpure.flashblade.purefb_fs: 

317 name: foo 

318 state: absent 

319 eradicate: true 

320 fb_url: 10.10.10.2 

321 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 

322 

323- name: Promote filesystem named foo ready for failover 

324 everpure.flashblade.purefb_fs: 

325 name: foo 

326 promote: true 

327 fb_url: 10.10.10.2 

328 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 

329 

330- name: Demote filesystem named foo after failover 

331 everpure.flashblade.purefb_fs: 

332 name: foo 

333 promote: false 

334 fb_url: 10.10.10.2 

335 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 

336 

337- name: Modify attributes of an existing filesystem named foo 

338 everpure.flashblade.purefb_fs: 

339 name: foo 

340 size: 2T 

341 nfsv3: false 

342 nfsv4: true 

343 user_quota: 10K 

344 group_quota: 25M 

345 snapshot: true 

346 fastremove: true 

347 hard_limit: true 

348 smb: true 

349 state: present 

350 fb_url: 10.10.10.2 

351 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 

352 

353- name: Attach export_policy to filesystem foo (deprecated - prefer purefb_export) 

354 everpure.flashblade.purefb_fs: 

355 name: foo 

356 export_policy: nfs_pol1 

357 state: present 

358 fb_url: 10.10.10.2 

359 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 

360 

361- name: Create filesystem foo (modern workflow - attach policies via purefb_export) 

362 everpure.flashblade.purefb_fs: 

363 name: foo 

364 size: 1T 

365 smb: true 

366 state: present 

367 fb_url: 10.10.10.2 

368 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 

369 

370- name: Attach NFS export policy to filesystem foo via purefb_export 

371 everpure.flashblade.purefb_export: 

372 name: foo_nfs 

373 filesystem: foo 

374 type: NFS 

375 export_policy: nfs_pol1 

376 state: present 

377 fb_url: 10.10.10.2 

378 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 

379 

380- name: Attach SMB share and client policies to filesystem foo via purefb_export 

381 everpure.flashblade.purefb_export: 

382 name: foo_smb 

383 filesystem: foo 

384 type: SMB 

385 share_policy: smb_share_pol1 

386 client_policy: smb_client_pol1 

387 state: present 

388 fb_url: 10.10.10.2 

389 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 

390""" 

391 

392RETURN = """ 

393""" 

394 

395HAS_PYPURECLIENT = True 

396try: 

397 from pypureclient.flashblade import ( 

398 FileSystemPatch, 

399 NfsPatch, 

400 Reference, 

401 Smb, 

402 FileSystemPost, 

403 Nfs, 

404 SmbPost, 

405 Http, 

406 MultiProtocolPost, 

407 MultiProtocol, 

408 StorageClassInfo, 

409 ) 

410except ImportError: 

411 HAS_PYPURECLIENT = False 

412 

413from ansible.module_utils.basic import AnsibleModule, human_to_bytes 

414from ansible_collections.everpure.flashblade.plugins.module_utils.purefb import ( 

415 get_system, 

416 purefb_argument_spec, 

417) 

418from ansible_collections.everpure.flashblade.plugins.module_utils.version import ( 

419 LooseVersion, 

420) 

421from ansible_collections.everpure.flashblade.plugins.module_utils.common import ( 

422 get_error_message, 

423 get_filesystem, 

424 get_rest_api_version, 

425) 

426 

427EXPORT_POLICY_API_VERSION = "2.3" 

428SMB_POLICY_API_VERSION = "2.10" 

429CA_API_VERSION = "2.12" 

430GOWNER_API_VERSION = "2.13" 

431CONTEXT_API_VERSION = "2.17" 

432REALM_API_VERSION = "2.19" 

433 

434 

435def _item_count(res): 

436 """Return the number of items in a successful SDK response. 

437 

438 A membership GET returns 200 with an empty item list when nothing 

439 matches, so the status code alone does not say whether a member exists. 

440 """ 

441 if getattr(res, "status_code", None) != 200: 

442 return 0 

443 count = getattr(res, "total_item_count", None) 

444 if isinstance(count, int): 

445 return count 

446 try: 

447 return len(list(res.items)) 

448 except TypeError: 

449 return 0 

450 

451 

452def create_fs(module, blade): 

453 """Create Filesystem""" 

454 changed = True 

455 api_version = get_rest_api_version(blade) 

456 if not module.check_mode: 

457 # Boolean flags default to None so that modify_fs only touches them 

458 # when the caller sets them. At creation time None means the array 

459 # default (safeguard_acls on, every other flag off). 

460 safeguard_acls = module.params["safeguard_acls"] 

461 if safeguard_acls is None: 

462 safeguard_acls = True 

463 # Determine realm from either realm parameter or name prefix (realm::fs) 

464 realm_name = None 

465 if module.params.get("realm"): 

466 realm_name = module.params["realm"] 

467 elif "::" in module.params["name"]: 

468 # Extract realm from name (e.g., "production::prod-fs" -> "production") 

469 realm_name = module.params["name"].split("::")[0] 

470 

471 # Validate realm if present 

472 if realm_name: 

473 if LooseVersion(REALM_API_VERSION) > LooseVersion(api_version): 

474 module.fail_json( 

475 msg="Realm support requires Purity//FB 4.6.1+ (REST API 2.19+)" 

476 ) 

477 # Check realm exists 

478 realm_check = blade.get_realms(destroyed=False, names=[realm_name]) 

479 if realm_check.status_code != 200: 

480 module.fail_json(msg="Realm '{0}' does not exist".format(realm_name)) 

481 

482 if module.params["size"]: 

483 size = human_to_bytes(module.params["size"]) 

484 else: 

485 size = 0 

486 

487 if module.params["user_quota"]: 

488 user_quota = human_to_bytes(module.params["user_quota"]) 

489 else: 

490 user_quota = None 

491 if module.params["group_quota"]: 

492 group_quota = human_to_bytes(module.params["group_quota"]) 

493 else: 

494 group_quota = None 

495 

496 if module.params["access_control"] == "nfs" and not ( 

497 module.params["nfsv3"] or module.params["nfsv4"] 

498 ): 

499 module.fail_json( 

500 msg="Cannot set access_control to nfs when NFS is not enabled." 

501 ) 

502 if ( 

503 module.params["access_control"] in ["smb", "independent"] 

504 and not module.params["smb"] 

505 ): 

506 module.fail_json( 

507 msg="Cannot set access_control to smb or independent when SMB is not enabled." 

508 ) 

509 if safeguard_acls and ( 

510 module.params["access_control"] in ["mode-bits", "independent"] 

511 ): 

512 module.fail_json( 

513 msg="ACL Safeguarding cannot be enabled if access_control is mode-bits or independent." 

514 ) 

515 # Determine if this is a realm filesystem 

516 realm_name = None 

517 if module.params.get("realm"): 

518 realm_name = module.params["realm"] 

519 elif "::" in module.params["name"]: 

520 realm_name = module.params["name"].split("::")[0] 

521 

522 # nfs_rules is deprecated in favour of export_policy. It is still 

523 # honoured for non-realm filesystems for backwards compatibility, but 

524 # only when explicitly supplied. 

525 nfs_kwargs = { 

526 "v3_enabled": module.params["nfsv3"], 

527 "v4_1_enabled": module.params["nfsv4"], 

528 } 

529 if module.params["nfs_rules"] is not None: 

530 module.deprecate( 

531 "nfs_rules is deprecated. Use the purefb_export module to attach " 

532 "NFS export policies via the File System Exports endpoints.", 

533 version="2.0.0", 

534 collection_name="everpure.flashblade", 

535 ) 

536 if realm_name: 

537 module.warn( 

538 "nfs_rules is not supported for realm filesystems and " 

539 "will be ignored." 

540 ) 

541 else: 

542 nfs_kwargs["rules"] = module.params["nfs_rules"] 

543 if module.params["export_policy"] is not None: 

544 module.deprecate( 

545 "export_policy is deprecated. Use the purefb_export " 

546 "module's export_policy option to attach NFS export " 

547 "policies via the dedicated File System Exports " 

548 "endpoints.", 

549 version="2.0.0", 

550 collection_name="everpure.flashblade", 

551 ) 

552 if module.params["share_policy"] is not None: 

553 module.deprecate( 

554 "share_policy is deprecated. Use the purefb_export " 

555 "module's share_policy option to attach SMB share " 

556 "policies via the dedicated File System Exports " 

557 "endpoints.", 

558 version="2.0.0", 

559 collection_name="everpure.flashblade", 

560 ) 

561 if module.params["client_policy"] is not None: 

562 module.deprecate( 

563 "client_policy is deprecated. Use the purefb_export " 

564 "module's client_policy option to attach SMB client " 

565 "policies via the dedicated File System Exports " 

566 "endpoints.", 

567 version="2.0.0", 

568 collection_name="everpure.flashblade", 

569 ) 

570 

571 # Build FileSystemPost object 

572 fs_obj = FileSystemPost( 

573 provisioned=size, 

574 fast_remove_directory_enabled=bool(module.params["fastremove"]), 

575 hard_limit_enabled=bool(module.params["hard_limit"]), 

576 snapshot_directory_enabled=bool(module.params["snapshot"]), 

577 nfs=Nfs(**nfs_kwargs), 

578 smb=SmbPost(enabled=bool(module.params["smb"])), 

579 http=Http(enabled=bool(module.params["http"])), 

580 multi_protocol=MultiProtocolPost( 

581 safeguard_acls=safeguard_acls, 

582 access_control_style=module.params["access_control"], 

583 ), 

584 default_user_quota=user_quota, 

585 default_group_quota=group_quota, 

586 ) 

587 # Construct filesystem name - if realm provided, prepend realm:: 

588 fs_name = module.params["name"] 

589 if realm_name and "::" not in fs_name: 

590 fs_name = "{0}::{1}".format(realm_name, fs_name) 

591 

592 # Build post_file_systems call with optional parameters 

593 post_kwargs = { 

594 "names": [fs_name], 

595 "file_system": fs_obj, 

596 } 

597 

598 # Add context if API supports it 

599 if ( 

600 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

601 and module.params["context"] 

602 ): 

603 post_kwargs["context_names"] = [module.params["context"]] 

604 

605 # Add default_exports=[""] for realm filesystems (empty string) 

606 if realm_name: 

607 post_kwargs["default_exports"] = ["''"] 

608 

609 res = blade.post_file_systems(**post_kwargs) 

610 if res.status_code != 200: 

611 module.fail_json( 

612 msg="Failed to create filesystem {0}. Error: {1}".format( 

613 fs_name, get_error_message(res) 

614 ) 

615 ) 

616 if module.params["policy"]: 

617 if ( 

618 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

619 and module.params["context"] 

620 ): 

621 res = blade.get_policies( 

622 names=[module.params["policy"]], 

623 context_names=[module.params["context"]], 

624 ) 

625 else: 

626 res = blade.get_policies(names=[module.params["policy"]]) 

627 if res.status_code != 200: 

628 _delete_fs(module, blade) 

629 module.fail_json( 

630 msg="Policy {0} doesn't exist.".format(module.params["policy"]) 

631 ) 

632 if ( 

633 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

634 and module.params["context"] 

635 ): 

636 res = blade.post_policies_file_systems( 

637 policy_names=[module.params["policy"]], 

638 member_names=[fs_name], 

639 context_names=[module.params["context"]], 

640 ) 

641 else: 

642 res = blade.post_policies_file_systems( 

643 policy_names=[module.params["policy"]], 

644 member_names=[fs_name], 

645 ) 

646 if res.status_code != 200: 

647 _delete_fs(module, blade) 

648 module.fail_json( 

649 msg="Failed to apply policy {0} when creating filesystem {1}. Error: {2}".format( 

650 module.params["policy"], 

651 fs_name, 

652 get_error_message(res), 

653 ) 

654 ) 

655 if ( 

656 LooseVersion(EXPORT_POLICY_API_VERSION) <= LooseVersion(api_version) 

657 and module.params["export_policy"] 

658 and (module.params["nfsv3"] or module.params["nfsv4"]) 

659 ): 

660 export_attr = FileSystemPatch( 

661 nfs=NfsPatch( 

662 export_policy=Reference(name=module.params["export_policy"]) 

663 ) 

664 ) 

665 if ( 

666 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

667 and module.params["context"] 

668 ): 

669 res = blade.patch_file_systems( 

670 names=[fs_name], 

671 file_system=export_attr, 

672 context_names=[module.params["context"]], 

673 ) 

674 else: 

675 res = blade.patch_file_systems(names=[fs_name], file_system=export_attr) 

676 if res.status_code != 200: 

677 module.fail_json( 

678 msg="Filesystem {0} created, but failed to assign export " 

679 "policy {1}. Error: {2}".format( 

680 fs_name, 

681 module.params["export_policy"], 

682 get_error_message(res), 

683 ) 

684 ) 

685 if ( 

686 LooseVersion(SMB_POLICY_API_VERSION) <= LooseVersion(api_version) 

687 and module.params["smb"] 

688 ): 

689 if module.params["client_policy"]: 

690 export_attr = FileSystemPatch( 

691 smb=Smb( 

692 client_policy=Reference(name=module.params["client_policy"]) 

693 ) 

694 ) 

695 if ( 

696 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

697 and module.params["context"] 

698 ): 

699 res = blade.patch_file_systems( 

700 names=[fs_name], 

701 file_system=export_attr, 

702 context_names=[module.params["context"]], 

703 ) 

704 else: 

705 res = blade.patch_file_systems( 

706 names=[fs_name], file_system=export_attr 

707 ) 

708 if res.status_code != 200: 

709 module.fail_json( 

710 msg="Filesystem {0} created, but failed to assign client " 

711 "policy {1}. Error: {2}".format( 

712 fs_name, 

713 module.params["client_policy"], 

714 get_error_message(res), 

715 ) 

716 ) 

717 if module.params["share_policy"]: 

718 export_attr = FileSystemPatch( 

719 smb=Smb(share_policy=Reference(name=module.params["share_policy"])) 

720 ) 

721 if ( 

722 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

723 and module.params["context"] 

724 ): 

725 res = blade.patch_file_systems( 

726 names=[fs_name], 

727 file_system=export_attr, 

728 context_names=[module.params["context"]], 

729 ) 

730 else: 

731 res = blade.patch_file_systems( 

732 names=[fs_name], 

733 file_system=export_attr, 

734 ) 

735 if res.status_code != 200: 

736 module.fail_json( 

737 msg="Filesystem {0} created, but failed to assign share " 

738 "policy {1}. Error: {2}".format( 

739 fs_name, 

740 module.params["share_policy"], 

741 get_error_message(res), 

742 ) 

743 ) 

744 if LooseVersion(CA_API_VERSION) <= LooseVersion(api_version): 

745 ca_attr = FileSystemPatch( 

746 smb=Smb( 

747 continuous_availability_enabled=module.params[ 

748 "continuous_availability" 

749 ] 

750 ) 

751 ) 

752 if ( 

753 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

754 and module.params["context"] 

755 ): 

756 res = blade.patch_file_systems( 

757 names=[fs_name], 

758 file_system=ca_attr, 

759 context_names=[module.params["context"]], 

760 ) 

761 else: 

762 res = blade.patch_file_systems(names=[fs_name], file_system=ca_attr) 

763 if res.status_code != 200: 

764 module.fail_json( 

765 msg="Filesystem {0} created, but failed to set continuous availability. " 

766 "Error: {1}".format( 

767 fs_name, 

768 get_error_message(res), 

769 ) 

770 ) 

771 # group_ownership and storage_class are not SMB attributes, so they 

772 # are applied whether or not SMB is enabled. 

773 if ( 

774 LooseVersion(GOWNER_API_VERSION) <= LooseVersion(api_version) 

775 and module.params["group_ownership"] 

776 ): 

777 go_attr = FileSystemPatch(group_ownership=module.params["group_ownership"]) 

778 if ( 

779 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

780 and module.params["context"] 

781 ): 

782 res = blade.patch_file_systems( 

783 names=[fs_name], 

784 file_system=go_attr, 

785 context_names=[module.params["context"]], 

786 ) 

787 else: 

788 res = blade.patch_file_systems(names=[fs_name], file_system=go_attr) 

789 if res.status_code != 200: 

790 module.fail_json( 

791 msg="Filesystem {0} created, but failed to set group ownership. " 

792 "Error: {1}".format( 

793 fs_name, 

794 get_error_message(res), 

795 ) 

796 ) 

797 if ( 

798 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

799 and module.params["storage_class"] 

800 ): 

801 sc_patch = { 

802 "names": [fs_name], 

803 "file_system": FileSystemPatch( 

804 storage_class=StorageClassInfo(name=module.params["storage_class"]) 

805 ), 

806 "cancel_in_progress_storage_class_transition": False, 

807 } 

808 if module.params["context"]: 

809 sc_patch["context_names"] = [module.params["context"]] 

810 res = blade.patch_file_systems(**sc_patch) 

811 if res.status_code != 200: 

812 module.fail_json( 

813 msg="Filesystem {0} created, but failed to set storage class. " 

814 "Error: {1}".format( 

815 fs_name, 

816 get_error_message(res), 

817 ) 

818 ) 

819 

820 module.exit_json(changed=changed) 

821 

822 

823def modify_fs(module, blade): 

824 """Modify Filesystem""" 

825 changed = False 

826 change_client = False 

827 change_export = False 

828 change_share = False 

829 change_ca = False 

830 change_go = False 

831 change_sc = False 

832 change_rules = False 

833 mod_fs = False 

834 # Determine if this is a realm filesystem 

835 realm_name = None 

836 if module.params.get("realm"): 

837 realm_name = module.params["realm"] 

838 elif "::" in module.params["name"]: 

839 realm_name = module.params["name"].split("::")[0] 

840 # Construct filesystem name - if realm provided, prepend realm:: 

841 fs_name = module.params["name"] 

842 if realm_name and "::" not in fs_name: 

843 fs_name = "{0}::{1}".format(realm_name, fs_name) 

844 api_version = get_rest_api_version(blade) 

845 if module.params["policy"] and module.params["policy_state"] == "present": 

846 if ( 

847 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

848 and module.params["context"] 

849 ): 

850 res = blade.get_policies( 

851 names=[module.params["policy"]], 

852 context_names=[module.params["context"]], 

853 ) 

854 else: 

855 res = blade.get_policies(names=[module.params["policy"]]) 

856 if res.status_code != 200: 

857 module.fail_json( 

858 msg="Policy {0} doesn't exist.".format(module.params["policy"]) 

859 ) 

860 if ( 

861 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

862 and module.params["context"] 

863 ): 

864 res = blade.get_policies_file_systems( 

865 policy_names=[module.params["policy"]], 

866 member_names=[fs_name], 

867 context_names=[module.params["context"]], 

868 ) 

869 else: 

870 res = blade.get_policies_file_systems( 

871 policy_names=[module.params["policy"]], 

872 member_names=[fs_name], 

873 ) 

874 if not _item_count(res): 

875 if ( 

876 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

877 and module.params["context"] 

878 ): 

879 res = blade.post_policies_file_systems( 

880 policy_names=[module.params["policy"]], 

881 member_names=[fs_name], 

882 context_names=[module.params["context"]], 

883 ) 

884 else: 

885 res = blade.post_policies_file_systems( 

886 policy_names=[module.params["policy"]], 

887 member_names=[fs_name], 

888 ) 

889 mod_fs = True 

890 if res.status_code != 200: 

891 module.fail_json( 

892 msg="Failed to add filesystem {0} to policy {1}. Error: {2}".format( 

893 fs_name, 

894 module.params["policy"], 

895 get_error_message(res), 

896 ) 

897 ) 

898 if module.params["policy"] and module.params["policy_state"] == "absent": 

899 if ( 

900 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

901 and module.params["context"] 

902 ): 

903 res = blade.get_policies( 

904 names=[module.params["policy"]], 

905 context_names=[module.params["context"]], 

906 ) 

907 else: 

908 res = blade.get_policies(names=[module.params["policy"]]) 

909 if res.status_code == 200: 

910 if ( 

911 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

912 and module.params["context"] 

913 ): 

914 res = blade.get_policies_file_systems( 

915 policy_names=[module.params["policy"]], 

916 member_names=[fs_name], 

917 context_names=[module.params["context"]], 

918 ) 

919 else: 

920 res = blade.get_policies_file_systems( 

921 policy_names=[module.params["policy"]], 

922 member_names=[fs_name], 

923 ) 

924 # A 200 with no items means the policy is not attached, so a 

925 # second policy_state=absent run must be a no-op. 

926 if _item_count(res): 

927 if ( 

928 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

929 and module.params["context"] 

930 ): 

931 res = blade.delete_policies_file_systems( 

932 policy_names=[module.params["policy"]], 

933 member_names=[fs_name], 

934 context_names=[module.params["context"]], 

935 ) 

936 else: 

937 res = blade.delete_policies_file_systems( 

938 policy_names=[module.params["policy"]], 

939 member_names=[fs_name], 

940 ) 

941 mod_fs = True 

942 if res.status_code != 200: 

943 module.fail_json( 

944 msg="Failed to remove filesystem {0} from policy {1}. Error: {2}".format( 

945 fs_name, 

946 module.params["policy"], 

947 get_error_message(res), 

948 ) 

949 ) 

950 if module.params["user_quota"]: 

951 user_quota = human_to_bytes(module.params["user_quota"]) 

952 if module.params["group_quota"]: 

953 group_quota = human_to_bytes(module.params["group_quota"]) 

954 fsys = get_filesystem(module, blade) 

955 new_fsys = { 

956 "destroyed": fsys.destroyed, 

957 "provisioned": fsys.provisioned, 

958 "nfsv3": fsys.nfs.v3_enabled, 

959 "nfsv4": fsys.nfs.v4_1_enabled, 

960 "default_user_quota": fsys.default_user_quota, 

961 "default_group_quota": fsys.default_group_quota, 

962 "group_ownership": fsys.group_ownership, 

963 "smb": fsys.smb.enabled, 

964 "http": fsys.http.enabled, 

965 "snapshot": fsys.snapshot_directory_enabled, 

966 "fastremove": fsys.fast_remove_directory_enabled, 

967 "hardlimit": fsys.hard_limit_enabled, 

968 "safeguard_acls": fsys.multi_protocol.safeguard_acls, 

969 "acs": fsys.multi_protocol.access_control_style, 

970 "writable": fsys.writable, 

971 "promotion_status": fsys.promotion_status, 

972 "requested_promotion_state": fsys.requested_promotion_state, 

973 "storage_class": getattr(getattr(fsys, "storage_class", None), "name", None), 

974 } 

975 if fsys.destroyed: 

976 new_fsys["destroyed"] = False 

977 mod_fs = True 

978 if module.params["size"]: 

979 if human_to_bytes(module.params["size"]) != fsys.provisioned: 

980 new_fsys["provisioned"] = human_to_bytes(module.params["size"]) 

981 mod_fs = True 

982 if module.params["nfsv3"] != fsys.nfs.v3_enabled: 

983 new_fsys["nfsv3"] = module.params["nfsv3"] 

984 mod_fs = True 

985 if module.params["nfsv4"] != fsys.nfs.v4_1_enabled: 

986 new_fsys["nfsv4"] = module.params["nfsv4"] 

987 mod_fs = True 

988 if module.params["user_quota"] and user_quota != fsys.default_user_quota: 

989 new_fsys["default_user_quota"] = user_quota 

990 mod_fs = True 

991 if module.params["group_quota"] and group_quota != fsys.default_group_quota: 

992 new_fsys["default_group_quota"] = group_quota 

993 mod_fs = True 

994 # Boolean flags are only compared when the caller set them, and then in 

995 # both directions, so an explicit false turns the setting off. 

996 bool_flags = [ 

997 ("smb", "smb", fsys.smb.enabled), 

998 ("http", "http", fsys.http.enabled), 

999 ("snapshot", "snapshot", fsys.snapshot_directory_enabled), 

1000 ("fastremove", "fastremove", fsys.fast_remove_directory_enabled), 

1001 ("hard_limit", "hardlimit", fsys.hard_limit_enabled), 

1002 ("safeguard_acls", "safeguard_acls", fsys.multi_protocol.safeguard_acls), 

1003 ] 

1004 for param, key, current in bool_flags: 

1005 if module.params[param] is not None and module.params[param] != current: 

1006 new_fsys[key] = module.params[param] 

1007 mod_fs = True 

1008 if module.params["access_control"] != fsys.multi_protocol.access_control_style: 

1009 new_fsys["acs"] = module.params["access_control"] 

1010 mod_fs = True 

1011 if module.params["writable"] is not None: 

1012 if not module.params["writable"] and fsys.writable: 

1013 new_fsys["writable"] = module.params["writable"] 

1014 mod_fs = True 

1015 if ( 

1016 module.params["writable"] 

1017 and not fsys.writable 

1018 and fsys.promotion_status == "promoted" 

1019 ): 

1020 new_fsys["writable"] = module.params["writable"] 

1021 mod_fs = True 

1022 if module.params["promote"] is not None: 

1023 if module.params["promote"] and fsys.promotion_status != "promoted": 

1024 new_fsys["requested_promotion_state"] = "promoted" 

1025 mod_fs = True 

1026 if not module.params["promote"] and fsys.promotion_status == "promoted": 

1027 # Demotion only allowed on filesystems in a replica-link 

1028 if ( 

1029 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

1030 and module.params["context"] 

1031 ): 

1032 res = blade.get_file_system_replica_links( 

1033 local_file_system_names=[fs_name], 

1034 context_names=[module.params["context"]], 

1035 ) 

1036 else: 

1037 res = blade.get_file_system_replica_links( 

1038 local_file_system_names=[fs_name] 

1039 ) 

1040 if res.status_code != 200: 

1041 module.fail_json( 

1042 msg="Filesystem {0} not demoted. Not in a replica-link".format( 

1043 fs_name 

1044 ) 

1045 ) 

1046 new_fsys["requested_promotion_state"] = "demoted" 

1047 mod_fs = True 

1048 if mod_fs: 

1049 changed = True 

1050 if not module.check_mode: 

1051 if ( 

1052 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

1053 and module.params["context"] 

1054 ): 

1055 if new_fsys["destroyed"] != fsys.destroyed: 

1056 delres = blade.patch_file_systems( 

1057 names=[fs_name], 

1058 context_names=[module.params["context"]], 

1059 file_system=FileSystemPatch(destroyed=new_fsys["destroyed"]), 

1060 ) 

1061 if delres.status_code != 200: 

1062 module.fail_json( 

1063 msg="Failed to update filesystem {0} deleted status. Error {1}".format( 

1064 fs_name, get_error_message(res) 

1065 ) 

1066 ) 

1067 res = blade.patch_file_systems( 

1068 names=[fs_name], 

1069 context_names=[module.params["context"]], 

1070 file_system=FileSystemPatch( 

1071 default_group_quota=new_fsys["default_group_quota"], 

1072 default_user_quota=new_fsys["default_user_quota"], 

1073 fast_remove_directory_enabled=new_fsys["fastremove"], 

1074 hard_limit_enabled=new_fsys["hardlimit"], 

1075 snapshot_directory_enabled=new_fsys["snapshot"], 

1076 http=Http(enabled=new_fsys["http"]), 

1077 multi_protocol=MultiProtocol( 

1078 access_control_style=new_fsys["acs"], 

1079 safeguard_acls=new_fsys["safeguard_acls"], 

1080 ), 

1081 nfs=NfsPatch( 

1082 v3_enabled=new_fsys["nfsv3"], 

1083 v4_1_enabled=new_fsys["nfsv4"], 

1084 ), 

1085 provisioned=new_fsys["provisioned"], 

1086 requested_promotion_state=new_fsys["requested_promotion_state"], 

1087 smb=Smb(enabled=new_fsys["smb"]), 

1088 writable=new_fsys["writable"], 

1089 ), 

1090 discard_non_snapshotted_data=module.params["discard_snaps"], 

1091 ignore_usage=module.params["ignore_usage"], 

1092 ) 

1093 else: 

1094 if new_fsys["destroyed"] != fsys.destroyed: 

1095 delres = blade.patch_file_systems( 

1096 names=[fs_name], 

1097 file_system=FileSystemPatch(destroyed=new_fsys["destroyed"]), 

1098 ) 

1099 if delres.status_code != 200: 

1100 module.fail_json( 

1101 msg="Failed to update filesystem {0} deleted status. Error {1}".format( 

1102 fs_name, get_error_message(res) 

1103 ) 

1104 ) 

1105 res = blade.patch_file_systems( 

1106 names=[fs_name], 

1107 file_system=FileSystemPatch( 

1108 default_group_quota=new_fsys["default_group_quota"], 

1109 default_user_quota=new_fsys["default_user_quota"], 

1110 fast_remove_directory_enabled=new_fsys["fastremove"], 

1111 hard_limit_enabled=new_fsys["hardlimit"], 

1112 snapshot_directory_enabled=new_fsys["snapshot"], 

1113 http=Http(enabled=new_fsys["http"]), 

1114 multi_protocol=MultiProtocol( 

1115 access_control_style=new_fsys["acs"], 

1116 safeguard_acls=new_fsys["safeguard_acls"], 

1117 ), 

1118 nfs=NfsPatch( 

1119 v3_enabled=new_fsys["nfsv3"], 

1120 v4_1_enabled=new_fsys["nfsv4"], 

1121 ), 

1122 provisioned=new_fsys["provisioned"], 

1123 requested_promotion_state=new_fsys["requested_promotion_state"], 

1124 smb=Smb(enabled=new_fsys["smb"]), 

1125 writable=new_fsys["writable"], 

1126 ), 

1127 discard_non_snapshotted_data=module.params["discard_snaps"], 

1128 ignore_usage=module.params["ignore_usage"], 

1129 ) 

1130 if res.status_code != 200: 

1131 module.fail_json( 

1132 msg="Failed to update filesystem {0}. Error {1}".format( 

1133 fs_name, get_error_message(res) 

1134 ) 

1135 ) 

1136 if ( 

1137 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

1138 and module.params["context"] 

1139 ): 

1140 current_fs = list( 

1141 blade.get_file_systems( 

1142 context_names=[module.params["context"]], 

1143 filter="name='" + fs_name + "'", 

1144 ).items 

1145 )[0] 

1146 else: 

1147 current_fs = list( 

1148 blade.get_file_systems(filter="name='" + fs_name + "'").items 

1149 )[0] 

1150 if ( 

1151 LooseVersion(EXPORT_POLICY_API_VERSION) <= LooseVersion(api_version) 

1152 and module.params["export_policy"] 

1153 and (current_fs.nfs.v3_enabled or current_fs.nfs.v4_1_enabled) 

1154 ): 

1155 change_export = False 

1156 if ( 

1157 current_fs.nfs.export_policy.name 

1158 and current_fs.nfs.export_policy.name != module.params["export_policy"] 

1159 ): 

1160 change_export = True 

1161 if not current_fs.nfs.export_policy.name and module.params["export_policy"]: 

1162 change_export = True 

1163 if change_export and not module.check_mode: 

1164 export_attr = FileSystemPatch( 

1165 nfs=NfsPatch( 

1166 export_policy=Reference(name=module.params["export_policy"]) 

1167 ) 

1168 ) 

1169 if ( 

1170 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

1171 and module.params["context"] 

1172 ): 

1173 res = blade.patch_file_systems( 

1174 names=[fs_name], 

1175 file_system=export_attr, 

1176 context_names=[module.params["context"]], 

1177 ) 

1178 else: 

1179 res = blade.patch_file_systems(names=[fs_name], file_system=export_attr) 

1180 if res.status_code != 200: 

1181 module.fail_json( 

1182 msg="Failed to modify export policy {1} for " 

1183 "filesystem {0}. Error: {2}".format( 

1184 fs_name, 

1185 module.params["export_policy"], 

1186 get_error_message(res), 

1187 ) 

1188 ) 

1189 if module.params["export_policy"] is not None: 

1190 module.deprecate( 

1191 "export_policy is deprecated. Use the purefb_export " 

1192 "module's export_policy option to attach NFS export " 

1193 "policies via the dedicated File System Exports " 

1194 "endpoints.", 

1195 version="2.0.0", 

1196 collection_name="everpure.flashblade", 

1197 ) 

1198 if module.params["share_policy"] is not None: 

1199 module.deprecate( 

1200 "share_policy is deprecated. Use the purefb_export " 

1201 "module's share_policy option to attach SMB share " 

1202 "policies via the dedicated File System Exports " 

1203 "endpoints.", 

1204 version="2.0.0", 

1205 collection_name="everpure.flashblade", 

1206 ) 

1207 if module.params["client_policy"] is not None: 

1208 module.deprecate( 

1209 "client_policy is deprecated. Use the purefb_export " 

1210 "module's client_policy option to attach SMB client " 

1211 "policies via the dedicated File System Exports " 

1212 "endpoints.", 

1213 version="2.0.0", 

1214 collection_name="everpure.flashblade", 

1215 ) 

1216 if module.params["nfs_rules"] is not None: 

1217 module.deprecate( 

1218 "nfs_rules is deprecated. Use the purefb_export module to attach " 

1219 "NFS export policies via the File System Exports endpoints.", 

1220 version="2.0.0", 

1221 collection_name="everpure.flashblade", 

1222 ) 

1223 if realm_name: 

1224 module.warn( 

1225 "nfs_rules is not supported for realm filesystems and " 

1226 "will be ignored." 

1227 ) 

1228 elif getattr(current_fs.nfs, "rules", None) != module.params["nfs_rules"]: 

1229 change_rules = True 

1230 if not module.check_mode: 

1231 rules_attr = FileSystemPatch( 

1232 nfs=NfsPatch(rules=module.params["nfs_rules"]) 

1233 ) 

1234 if ( 

1235 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

1236 and module.params["context"] 

1237 ): 

1238 res = blade.patch_file_systems( 

1239 names=[fs_name], 

1240 file_system=rules_attr, 

1241 context_names=[module.params["context"]], 

1242 ) 

1243 else: 

1244 res = blade.patch_file_systems( 

1245 names=[fs_name], file_system=rules_attr 

1246 ) 

1247 if res.status_code != 200: 

1248 module.fail_json( 

1249 msg="Failed to modify nfs_rules for " 

1250 "filesystem {0}. Error: {1}".format( 

1251 fs_name, 

1252 get_error_message(res), 

1253 ) 

1254 ) 

1255 if ( 

1256 LooseVersion(SMB_POLICY_API_VERSION) <= LooseVersion(api_version) 

1257 and module.params["client_policy"] 

1258 and current_fs.smb.enabled 

1259 ): 

1260 if ( 

1261 current_fs.smb.client_policy.name 

1262 and current_fs.smb.client_policy.name != module.params["client_policy"] 

1263 ): 

1264 change_client = True 

1265 if not current_fs.smb.client_policy.name and module.params["client_policy"]: 

1266 change_client = True 

1267 if change_client and not module.check_mode: 

1268 client_attr = FileSystemPatch( 

1269 smb=Smb(client_policy=Reference(name=module.params["client_policy"])) 

1270 ) 

1271 if ( 

1272 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

1273 and module.params["context"] 

1274 ): 

1275 res = blade.patch_file_systems( 

1276 names=[fs_name], 

1277 file_system=client_attr, 

1278 context_names=[module.params["context"]], 

1279 ) 

1280 else: 

1281 res = blade.patch_file_systems(names=[fs_name], file_system=client_attr) 

1282 if res.status_code != 200: 

1283 module.fail_json( 

1284 msg="Failed to modify client policy {1} for " 

1285 "filesystem {0}. Error: {2}".format( 

1286 fs_name, 

1287 module.params["client_policy"], 

1288 get_error_message(res), 

1289 ) 

1290 ) 

1291 if ( 

1292 LooseVersion(SMB_POLICY_API_VERSION) <= LooseVersion(api_version) 

1293 and module.params["share_policy"] 

1294 and current_fs.smb.enabled 

1295 ): 

1296 if ( 

1297 current_fs.smb.share_policy.name 

1298 and current_fs.smb.share_policy.name != module.params["share_policy"] 

1299 ): 

1300 change_share = True 

1301 if not current_fs.smb.share_policy.name and module.params["share_policy"]: 

1302 change_share = True 

1303 if change_share and not module.check_mode: 

1304 share_attr = FileSystemPatch( 

1305 smb=Smb(share_policy=Reference(name=module.params["share_policy"])) 

1306 ) 

1307 if ( 

1308 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

1309 and module.params["context"] 

1310 ): 

1311 res = blade.patch_file_systems( 

1312 names=[fs_name], 

1313 file_system=share_attr, 

1314 context_names=[module.params["context"]], 

1315 ) 

1316 else: 

1317 res = blade.patch_file_systems(names=[fs_name], file_system=share_attr) 

1318 if res.status_code != 200: 

1319 module.fail_json( 

1320 msg="Failed to modify share policy {1} for " 

1321 "filesystem {0}. Error: {2}".format( 

1322 fs_name, 

1323 module.params["share_policy"], 

1324 get_error_message(res), 

1325 ) 

1326 ) 

1327 if ( 

1328 LooseVersion(CA_API_VERSION) <= LooseVersion(api_version) 

1329 and current_fs.smb.enabled 

1330 ): 

1331 if ( 

1332 module.params["continuous_availability"] 

1333 != current_fs.smb.continuous_availability_enabled 

1334 ): 

1335 change_ca = True 

1336 if not module.check_mode and change_ca: 

1337 ca_attr = FileSystemPatch( 

1338 smb=Smb( 

1339 continuous_availability_enabled=module.params[ 

1340 "continuous_availability" 

1341 ] 

1342 ) 

1343 ) 

1344 if ( 

1345 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

1346 and module.params["context"] 

1347 ): 

1348 res = blade.patch_file_systems( 

1349 names=[fs_name], 

1350 file_system=ca_attr, 

1351 context_names=[module.params["context"]], 

1352 ) 

1353 else: 

1354 res = blade.patch_file_systems(names=[fs_name], file_system=ca_attr) 

1355 if res.status_code != 200: 

1356 module.fail_json( 

1357 msg="Failed to modify continuous availability for " 

1358 "filesystem {0}. Error: {1}".format( 

1359 fs_name, 

1360 get_error_message(res), 

1361 ) 

1362 ) 

1363 if LooseVersion(GOWNER_API_VERSION) <= LooseVersion(api_version): 

1364 if module.params["group_ownership"] != current_fs.group_ownership: 

1365 change_go = True 

1366 if not module.check_mode and change_go: 

1367 go_attr = FileSystemPatch(group_ownership=module.params["group_ownership"]) 

1368 if ( 

1369 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

1370 and module.params["context"] 

1371 ): 

1372 res = blade.patch_file_systems( 

1373 names=[fs_name], 

1374 file_system=go_attr, 

1375 context_names=[module.params["context"]], 

1376 ) 

1377 else: 

1378 res = blade.patch_file_systems(names=[fs_name], file_system=go_attr) 

1379 if res.status_code != 200: 

1380 module.fail_json( 

1381 msg="Failed to modify group ownership for " 

1382 "filesystem {0}. Error: {1}".format( 

1383 fs_name, 

1384 get_error_message(res), 

1385 ) 

1386 ) 

1387 if ( 

1388 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

1389 and module.params["storage_class"] 

1390 ): 

1391 if module.params["storage_class"] != current_fs.storage_class: 

1392 change_sc = True 

1393 sc_patch = { 

1394 "names": [fs_name], 

1395 "file_system": FileSystemPatch( 

1396 storage_class=StorageClassInfo(name=module.params["storage_class"]) 

1397 ), 

1398 "cancel_in_progress_storage_class_transition": module.params[ 

1399 "cancel_in_progress" 

1400 ], 

1401 } 

1402 if module.params["context"]: 

1403 sc_patch["context_names"] = [module.params["context"]] 

1404 res = blade.patch_file_systems(**sc_patch) 

1405 

1406 module.exit_json( 

1407 changed=( 

1408 changed 

1409 or change_export 

1410 or change_share 

1411 or change_ca 

1412 or change_go 

1413 or change_sc 

1414 or change_client 

1415 or change_rules 

1416 ) 

1417 ) 

1418 

1419 

1420def _delete_fs(module, blade): 

1421 """In module Delete Filesystem""" 

1422 # Determine if this is a realm filesystem 

1423 realm_name = None 

1424 if module.params.get("realm"): 

1425 realm_name = module.params["realm"] 

1426 elif "::" in module.params["name"]: 

1427 realm_name = module.params["name"].split("::")[0] 

1428 # Construct filesystem name - if realm provided, prepend realm:: 

1429 fs_name = module.params["name"] 

1430 if realm_name and "::" not in fs_name: 

1431 fs_name = "{0}::{1}".format(realm_name, fs_name) 

1432 res = blade.patch_file_systems( 

1433 names=[fs_name], 

1434 file_system=FileSystemPatch( 

1435 nfs=NfsPatch(v3_enabled=False, v4_1_enabled=False), 

1436 smb=Smb(enabled=False), 

1437 http=Http(enabled=False), 

1438 multi_protocol=MultiProtocol(access_control_style="shared"), 

1439 destroyed=True, 

1440 ), 

1441 ) 

1442 if res.status_code != 200: 

1443 module.fail_json( 

1444 msg="Failed to delete filesystem {0}. Error: {1}".format( 

1445 fs_name, get_error_message(res) 

1446 ) 

1447 ) 

1448 

1449 res = blade.delete_file_systems(names=[fs_name]) 

1450 if res.status_code != 200: 

1451 module.fail_json( 

1452 msg="Failed to eradicate deleted filesystem {0}. Error: {1}".format( 

1453 fs_name, get_error_message(res) 

1454 ) 

1455 ) 

1456 

1457 

1458def delete_fs(module, blade): 

1459 """Delete Filesystem""" 

1460 # Determine if this is a realm filesystem 

1461 realm_name = None 

1462 if module.params.get("realm"): 

1463 realm_name = module.params["realm"] 

1464 elif "::" in module.params["name"]: 

1465 realm_name = module.params["name"].split("::")[0] 

1466 # Construct filesystem name - if realm provided, prepend realm:: 

1467 fs_name = module.params["name"] 

1468 if realm_name and "::" not in fs_name: 

1469 fs_name = "{0}::{1}".format(realm_name, fs_name) 

1470 changed = True 

1471 if not module.check_mode: 

1472 res = blade.patch_file_systems( 

1473 names=[fs_name], 

1474 file_system=FileSystemPatch( 

1475 nfs=NfsPatch(v3_enabled=False, v4_1_enabled=False), 

1476 smb=Smb(enabled=False), 

1477 http=Http(enabled=False), 

1478 destroyed=True, 

1479 ), 

1480 delete_link_on_eradication=module.params["delete_link"], 

1481 ) 

1482 if res.status_code != 200: 

1483 module.fail_json( 

1484 msg="Failed to delete filesystem {0}. Error: {1}".format( 

1485 fs_name, get_error_message(res) 

1486 ) 

1487 ) 

1488 if module.params["eradicate"]: 

1489 res = blade.delete_file_systems(names=[fs_name]) 

1490 if res.status_code != 200: 

1491 module.fail_json( 

1492 msg="Failed to eradicate filesystem {0}. Error: {1}".format( 

1493 fs_name, get_error_message(res) 

1494 ) 

1495 ) 

1496 module.exit_json(changed=changed) 

1497 

1498 

1499def eradicate_fs(module, blade): 

1500 """Eradicate Filesystem""" 

1501 # Determine if this is a realm filesystem 

1502 realm_name = None 

1503 if module.params.get("realm"): 

1504 realm_name = module.params["realm"] 

1505 elif "::" in module.params["name"]: 

1506 realm_name = module.params["name"].split("::")[0] 

1507 # Construct filesystem name - if realm provided, prepend realm:: 

1508 fs_name = module.params["name"] 

1509 if realm_name and "::" not in fs_name: 

1510 fs_name = "{0}::{1}".format(realm_name, fs_name) 

1511 changed = True 

1512 if not module.check_mode: 

1513 res = blade.delete_file_systems(names=[fs_name]) 

1514 if res.status_code != 200: 

1515 module.fail_json( 

1516 msg="Failed to eradicate filesystem {0}. Error: {1}".format( 

1517 fs_name, get_error_message(res) 

1518 ) 

1519 ) 

1520 module.exit_json(changed=changed) 

1521 

1522 

1523def main(): 

1524 argument_spec = purefb_argument_spec() 

1525 argument_spec.update( 

1526 dict( 

1527 name=dict(type="str", required=True), 

1528 eradicate=dict(default="false", type="bool"), 

1529 nfsv3=dict(default="true", type="bool"), 

1530 nfsv4=dict(default="true", type="bool"), 

1531 nfs_rules=dict(type="str"), 

1532 smb=dict(type="bool"), 

1533 http=dict(type="bool"), 

1534 snapshot=dict(type="bool"), 

1535 writable=dict(type="bool"), 

1536 promote=dict(type="bool"), 

1537 fastremove=dict(type="bool"), 

1538 hard_limit=dict(type="bool"), 

1539 user_quota=dict(type="str"), 

1540 policy=dict(type="str"), 

1541 group_quota=dict(type="str"), 

1542 smb_aclmode=dict( 

1543 type="str", default="shared", choices=["shared", "native"] 

1544 ), 

1545 group_ownership=dict( 

1546 choices=["creator", "parent-directory"], default="creator" 

1547 ), 

1548 policy_state=dict(default="present", choices=["present", "absent"]), 

1549 state=dict(default="present", choices=["present", "absent"]), 

1550 delete_link=dict(default=False, type="bool"), 

1551 discard_snaps=dict(default=False, type="bool"), 

1552 safeguard_acls=dict(type="bool"), 

1553 access_control=dict( 

1554 type="str", 

1555 default="shared", 

1556 choices=["nfs", "smb", "shared", "independent", "mode-bits"], 

1557 ), 

1558 size=dict(type="str"), 

1559 export_policy=dict(type="str"), 

1560 share_policy=dict(type="str"), 

1561 client_policy=dict(type="str"), 

1562 continuous_availability=dict(type="bool", default="true"), 

1563 ignore_usage=dict(type="bool", default=False), 

1564 cancel_in_progress=dict(type="bool", default=False), 

1565 context=dict(type="str", default=""), 

1566 storage_class=dict(type="str"), 

1567 realm=dict(type="str"), 

1568 ) 

1569 ) 

1570 

1571 module = AnsibleModule(argument_spec, supports_check_mode=True) 

1572 

1573 state = module.params["state"] 

1574 blade = get_system(module) 

1575 api_version = get_rest_api_version(blade) 

1576 if ( 

1577 LooseVersion(CONTEXT_API_VERSION) <= LooseVersion(api_version) 

1578 and not module.params["context"] 

1579 ): 

1580 # Only default the context to the local array name when this array is a 

1581 # member of a fleet. A standalone array is "not in a fleet" and rejects 

1582 # fleet context, so leave context unset - no context_names is then sent. 

1583 fleet_res = blade.get_fleets() 

1584 if fleet_res.status_code == 200 and list(fleet_res.items): 

1585 module.params["context"] = list(blade.get_arrays().items)[0].name 

1586 

1587 # Check if filesystem exists 

1588 # If realm is provided and filesystem name doesn't include realm prefix, 

1589 # also check for realm::filesystem format 

1590 fsys = get_filesystem(module, blade) 

1591 if not fsys and module.params.get("realm") and "::" not in module.params["name"]: 

1592 # Try looking for realm::filesystem format 

1593 original_name = module.params["name"] 

1594 qualified_name = "{0}::{1}".format(module.params["realm"], original_name) 

1595 module.params["name"] = qualified_name 

1596 fsys = get_filesystem(module, blade) 

1597 # If not found with qualified name, restore original name for creation 

1598 if not fsys: 

1599 module.params["name"] = original_name 

1600 

1601 if module.params["eradicate"] and state == "present": 

1602 module.warn("Eradicate flag ignored without state=absent") 

1603 

1604 if module.params["smb_aclmode"] == "native": 

1605 module.fail_json( 

1606 msg="Native SMB ACL mode is no longer supported. " 

1607 "Use the access_control parameter." 

1608 ) 

1609 if state == "present" and not fsys: 

1610 create_fs(module, blade) 

1611 elif state == "present" and fsys: 

1612 modify_fs(module, blade) 

1613 elif state == "absent" and fsys and not fsys.destroyed: 

1614 delete_fs(module, blade) 

1615 elif state == "absent" and fsys and fsys.destroyed and module.params["eradicate"]: 

1616 eradicate_fs(module, blade) 

1617 elif state == "absent" and not fsys: 

1618 module.exit_json(changed=False) 

1619 module.exit_json(changed=False) 

1620 

1621 

1622if __name__ == "__main__": 

1623 main()