1#!/usr/bin/python 2# -*- coding: utf-8 -*- 3 4# (c) 2017, Simon Dodsley (simon@purestorage.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 11ANSIBLE_METADATA = {'metadata_version': '1.1', 12 'status': ['preview'], 13 'supported_by': 'community'} 14 15 16DOCUMENTATION = ''' 17--- 18module: purefb_fs 19version_added: "2.6" 20short_description: Manage filesystemon Pure Storage FlashBlade` 21description: 22 - This module manages filesystems on Pure Storage FlashBlade. 23author: Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com> 24options: 25 name: 26 description: 27 - Filesystem Name. 28 required: true 29 type: str 30 state: 31 description: 32 - Create, delete or modifies a filesystem. 33 required: false 34 default: present 35 type: str 36 choices: [ "present", "absent" ] 37 eradicate: 38 description: 39 - Define whether to eradicate the filesystem on delete or leave in trash. 40 required: false 41 type: bool 42 default: false 43 size: 44 description: 45 - Volume size in M, G, T or P units. See examples. 46 type: str 47 required: false 48 default: 32G 49 nfsv3: 50 description: 51 - Define whether to NFSv3 protocol is enabled for the filesystem. 52 required: false 53 type: bool 54 default: true 55 version_added: 2.9 56 nfsv4: 57 description: 58 - Define whether to NFSv4.1 protocol is enabled for the filesystem. 59 required: false 60 type: bool 61 default: true 62 version_added: 2.9 63 nfs: 64 description: 65 - (Deprecate) Define whether to NFSv3 protocol is enabled for the filesystem. 66 - This option will be deprecated in 2.10, use I(nfsv3) instead. 67 required: false 68 type: bool 69 default: true 70 nfs_rules: 71 description: 72 - Define the NFS rules in operation. 73 required: false 74 default: '*(rw,no_root_squash)' 75 type: str 76 smb: 77 description: 78 - Define whether to SMB protocol is enabled for the filesystem. 79 required: false 80 type: bool 81 default: false 82 http: 83 description: 84 - Define whether to HTTP/HTTPS protocol is enabled for the filesystem. 85 required: false 86 type: bool 87 default: false 88 snapshot: 89 description: 90 - Define whether a snapshot directory is enabled for the filesystem. 91 required: false 92 type: bool 93 default: false 94 fastremove: 95 description: 96 - Define whether the fast remove directory is enabled for the filesystem. 97 required: false 98 type: bool 99 default: false 100 hard_limit: 101 description: 102 - Define whether the capacity for a filesystem is a hard limit. 103 - CAUTION This will cause the filesystem to go Read-Only if the 104 capacity has already exceeded the logical size of the filesystem. 105 required: false 106 type: bool 107 default: false 108 version_added: 2.8 109 user_quota: 110 description: 111 - Default quota in M, G, T or P units for a user under this file system. 112 required: false 113 type: str 114 version_added: 2.9 115 group_quota: 116 description: 117 - Default quota in M, G, T or P units for a group under this file system. 118 required: false 119 type: str 120 version_added: 2.9 121extends_documentation_fragment: 122 - purestorage.fb 123''' 124 125EXAMPLES = ''' 126- name: Create new filesystem named foo 127 purefb_fs: 128 name: foo 129 size: 1T 130 state: present 131 fb_url: 10.10.10.2 132 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 133 134- name: Delete filesystem named foo 135 purefb_fs: 136 name: foo 137 state: absent 138 fb_url: 10.10.10.2 139 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 140 141- name: Recover filesystem named foo 142 purefb_fs: 143 name: foo 144 state: present 145 fb_url: 10.10.10.2 146 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 147 148- name: Eradicate filesystem named foo 149 purefb_fs: 150 name: foo 151 state: absent 152 eradicate: true 153 fb_url: 10.10.10.2 154 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641 155 156- name: Modify attributes of an existing filesystem named foo 157 purefb_fs: 158 name: foo 159 size: 2T 160 nfsv3 : false 161 nfsv4 : true 162 user_quota: 10K 163 group_quota: 25M 164 nfs_rules: '*(ro)' 165 snapshot: true 166 fastremove: true 167 hard_limit: true 168 smb: true 169 state: present 170 fb_url: 10.10.10.2 171 api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641''' 172 173RETURN = ''' 174''' 175 176HAS_PURITY_FB = True 177try: 178 from purity_fb import FileSystem, ProtocolRule, NfsRule 179except ImportError: 180 HAS_PURITY_FB = False 181 182from ansible.module_utils.basic import AnsibleModule, human_to_bytes 183from ansible.module_utils.pure import get_blade, purefb_argument_spec 184 185 186HARD_LIMIT_API_VERSION = '1.4' 187NFSV4_API_VERSION = '1.6' 188 189 190def get_fs(module, blade): 191 """Return Filesystem or None""" 192 fsys = [] 193 fsys.append(module.params['name']) 194 try: 195 res = blade.file_systems.list_file_systems(names=fsys) 196 return res.items[0] 197 except Exception: 198 return None 199 200 201def create_fs(module, blade): 202 """Create Filesystem""" 203 changed = True 204 if not module.check_mode: 205 try: 206 207 if not module.params['size']: 208 module.params['size'] = '32G' 209 210 size = human_to_bytes(module.params['size']) 211 nfsv3 = module.params['nfs'] if module.params['nfsv3'] is None else module.params['nfsv3'] 212 213 if module.params['user_quota']: 214 user_quota = human_to_bytes(module.params['user_quota']) 215 else: 216 user_quota = None 217 if module.params['group_quota']: 218 group_quota = human_to_bytes(module.params['group_quota']) 219 else: 220 group_quota = None 221 222 api_version = blade.api_version.list_versions().versions 223 if HARD_LIMIT_API_VERSION in api_version: 224 if NFSV4_API_VERSION in api_version: 225 fs_obj = FileSystem(name=module.params['name'], 226 provisioned=size, 227 fast_remove_directory_enabled=module.params['fastremove'], 228 hard_limit_enabled=module.params['hard_limit'], 229 snapshot_directory_enabled=module.params['snapshot'], 230 nfs=NfsRule(v3_enabled=nfsv3, 231 v4_1_enabled=module.params['nfsv4'], 232 rules=module.params['nfs_rules']), 233 smb=ProtocolRule(enabled=module.params['smb']), 234 http=ProtocolRule(enabled=module.params['http']), 235 default_user_quota=user_quota, 236 default_group_quota=group_quota 237 ) 238 else: 239 fs_obj = FileSystem(name=module.params['name'], 240 provisioned=size, 241 fast_remove_directory_enabled=module.params['fastremove'], 242 hard_limit_enabled=module.params['hard_limit'], 243 snapshot_directory_enabled=module.params['snapshot'], 244 nfs=NfsRule(enabled=nfsv3, rules=module.params['nfs_rules']), 245 smb=ProtocolRule(enabled=module.params['smb']), 246 http=ProtocolRule(enabled=module.params['http']) 247 ) 248 else: 249 fs_obj = FileSystem(name=module.params['name'], 250 provisioned=size, 251 fast_remove_directory_enabled=module.params['fastremove'], 252 snapshot_directory_enabled=module.params['snapshot'], 253 nfs=NfsRule(enabled=module.params['nfs'], rules=module.params['nfs_rules']), 254 smb=ProtocolRule(enabled=module.params['smb']), 255 http=ProtocolRule(enabled=module.params['http']) 256 ) 257 blade.file_systems.create_file_systems(fs_obj) 258 except Exception: 259 module.fail_json(msg="Failed to create filesystem {0}.".format(module.params['name'])) 260 module.exit_json(changed=changed) 261 262 263def modify_fs(module, blade): 264 """Modify Filesystem""" 265 changed = True 266 if not module.check_mode: 267 mod_fs = False 268 nfsv3 = module.params['nfs'] if module.params['nfsv3'] is None else module.params['nfsv3'] 269 attr = {} 270 if module.params['user_quota']: 271 user_quota = human_to_bytes(module.params['user_quota']) 272 if module.params['group_quota']: 273 group_quota = human_to_bytes(module.params['group_quota']) 274 fsys = get_fs(module, blade) 275 if fsys.destroyed: 276 attr['destroyed'] = False 277 mod_fs = True 278 if module.params['size']: 279 if human_to_bytes(module.params['size']) != fsys.provisioned: 280 attr['provisioned'] = human_to_bytes(module.params['size']) 281 mod_fs = True 282 api_version = blade.api_version.list_versions().versions 283 if NFSV4_API_VERSION in api_version: 284 if nfsv3 and not fsys.nfs.v3_enabled: 285 attr['nfs'] = NfsRule(v3_enabled=nfsv3) 286 mod_fs = True 287 if not nfsv3 and fsys.nfs.v3_enabled: 288 attr['nfs'] = NfsRule(v3_enabled=nfsv3) 289 mod_fs = True 290 if module.params['nfsv4'] and not fsys.nfs.v4_1_enabled: 291 attr['nfs'] = NfsRule(v4_1_enabled=module.params['nfsv4']) 292 mod_fs = True 293 if not module.params['nfsv4'] and fsys.nfs.v4_1_enabled: 294 attr['nfs'] = NfsRule(v4_1_enabled=module.params['nfsv4']) 295 mod_fs = True 296 if nfsv3 or module.params['nfsv4'] and fsys.nfs.v3_enabled or fsys.nfs.v4_1_enabled: 297 if fsys.nfs.rules != module.params['nfs_rules']: 298 attr['nfs'] = NfsRule(rules=module.params['nfs_rules']) 299 mod_fs = True 300 if module.params['user_quota'] and user_quota != fsys.default_user_quota: 301 attr['default_user_quota'] = user_quota 302 mod_fs = True 303 if module.params['group_quota'] and group_quota != fsys.default_group_quota: 304 attr['default_group_quota'] = group_quota 305 mod_fs = True 306 else: 307 if nfsv3 and not fsys.nfs.enabled: 308 attr['nfs'] = NfsRule(enabled=nfsv3) 309 mod_fs = True 310 if not nfsv3 and fsys.nfs.enabled: 311 attr['nfs'] = NfsRule(enabled=nfsv3) 312 mod_fs = True 313 if nfsv3 and fsys.nfs.enabled: 314 if fsys.nfs.rules != module.params['nfs_rules']: 315 attr['nfs'] = NfsRule(rules=module.params['nfs_rules']) 316 mod_fs = True 317 if module.params['smb'] and not fsys.smb.enabled: 318 attr['smb'] = ProtocolRule(enabled=module.params['smb']) 319 mod_fs = True 320 if not module.params['smb'] and fsys.smb.enabled: 321 attr['smb'] = ProtocolRule(enabled=module.params['smb']) 322 mod_fs = True 323 if module.params['http'] and not fsys.http.enabled: 324 attr['http'] = ProtocolRule(enabled=module.params['http']) 325 mod_fs = True 326 if not module.params['http'] and fsys.http.enabled: 327 attr['http'] = ProtocolRule(enabled=module.params['http']) 328 mod_fs = True 329 if module.params['snapshot'] and not fsys.snapshot_directory_enabled: 330 attr['snapshot_directory_enabled'] = module.params['snapshot'] 331 mod_fs = True 332 if not module.params['snapshot'] and fsys.snapshot_directory_enabled: 333 attr['snapshot_directory_enabled'] = module.params['snapshot'] 334 mod_fs = True 335 if module.params['fastremove'] and not fsys.fast_remove_directory_enabled: 336 attr['fast_remove_directory_enabled'] = module.params['fastremove'] 337 mod_fs = True 338 if not module.params['fastremove'] and fsys.fast_remove_directory_enabled: 339 attr['fast_remove_directory_enabled'] = module.params['fastremove'] 340 mod_fs = True 341 api_version = blade.api_version.list_versions().versions 342 if HARD_LIMIT_API_VERSION in api_version: 343 if not module.params['hard_limit'] and fsys.hard_limit_enabled: 344 attr['hard_limit_enabled'] = module.params['hard_limit'] 345 mod_fs = True 346 if module.params['hard_limit'] and not fsys.hard_limit_enabled: 347 attr['hard_limit_enabled'] = module.params['hard_limit'] 348 mod_fs = True 349 if mod_fs: 350 n_attr = FileSystem(**attr) 351 try: 352 blade.file_systems.update_file_systems(name=module.params['name'], attributes=n_attr) 353 except Exception: 354 module.fail_json(msg="Failed to update filesystem {0}.".format(module.params['name'])) 355 else: 356 changed = False 357 module.exit_json(changed=changed) 358 359 360def delete_fs(module, blade): 361 """ Delete Filesystem""" 362 changed = True 363 if not module.check_mode: 364 try: 365 api_version = blade.api_version.list_versions().versions 366 if NFSV4_API_VERSION in api_version: 367 blade.file_systems.update_file_systems(name=module.params['name'], 368 attributes=FileSystem(nfs=NfsRule(v3_enabled=False, 369 v4_1_enabled=False), 370 smb=ProtocolRule(enabled=False), 371 http=ProtocolRule(enabled=False), 372 destroyed=True) 373 ) 374 else: 375 blade.file_systems.update_file_systems(name=module.params['name'], 376 attributes=FileSystem(nfs=NfsRule(enabled=False), 377 smb=ProtocolRule(enabled=False), 378 http=ProtocolRule(enabled=False), 379 destroyed=True) 380 ) 381 382 if module.params['eradicate']: 383 try: 384 blade.file_systems.delete_file_systems(module.params['name']) 385 except Exception: 386 module.fail_json(msg="Failed to delete filesystem {0}.".format(module.params['name'])) 387 except Exception: 388 module.fail_json(msg="Failed to update filesystem {0} prior to deletion.".format(module.params['name'])) 389 module.exit_json(changed=changed) 390 391 392def eradicate_fs(module, blade): 393 """ Eradicate Filesystem""" 394 changed = True 395 if not module.check_mode: 396 try: 397 blade.file_systems.delete_file_systems(module.params['name']) 398 except Exception: 399 module.fail_json(msg="Failed to eradicate filesystem {0}.".format(module.params['name'])) 400 module.exit_json(changed=changed) 401 402 403def main(): 404 argument_spec = purefb_argument_spec() 405 argument_spec.update( 406 dict( 407 name=dict(required=True), 408 eradicate=dict(default='false', type='bool'), 409 nfs=dict(removed_in_version='2.10', default='true', type='bool'), 410 nfsv3=dict(default='true', type='bool'), 411 nfsv4=dict(default='true', type='bool'), 412 nfs_rules=dict(default='*(rw,no_root_squash)'), 413 smb=dict(default='false', type='bool'), 414 http=dict(default='false', type='bool'), 415 snapshot=dict(default='false', type='bool'), 416 fastremove=dict(default='false', type='bool'), 417 hard_limit=dict(default='false', type='bool'), 418 user_quota=dict(type='str'), 419 group_quota=dict(type='str'), 420 state=dict(default='present', choices=['present', 'absent']), 421 size=dict() 422 ) 423 ) 424 425 mutually_exclusive = [['nfs', 'nfsv3']] 426 427 module = AnsibleModule(argument_spec, 428 mutually_exclusive=mutually_exclusive, 429 supports_check_mode=True) 430 431 if not HAS_PURITY_FB: 432 module.fail_json(msg='purity_fb sdk is required for this module') 433 434 state = module.params['state'] 435 blade = get_blade(module) 436 fsys = get_fs(module, blade) 437 438 if state == 'present' and not fsys: 439 create_fs(module, blade) 440 elif state == 'present' and fsys: 441 modify_fs(module, blade) 442 elif state == 'absent' and fsys and not fsys.destroyed: 443 delete_fs(module, blade) 444 elif state == 'absent' and fsys and fsys.destroyed and module.params['eradicate']: 445 eradicate_fs(module, blade) 446 elif state == 'absent' and not fsys: 447 module.exit_json(changed=False) 448 449 450if __name__ == '__main__': 451 main() 452