Migrated to purestorage.flashblade

This commit is contained in:
Ansible Core Team 2020-03-09 09:40:37 +00:00 committed by Matt Martz
parent d9920706d7
commit fe0f4750e1
13 changed files with 0 additions and 3104 deletions

View file

@ -1,216 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: purefb_bucket
version_added: "2.8"
short_description: Manage Object Store Buckets on a Pure Storage FlashBlade.
description:
- This module managess object store (s3) buckets on Pure Storage FlashBlade.
author: Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
name:
description:
- Bucket Name.
required: true
type: str
account:
description:
- Object Store Account for Bucket.
required: true
type: str
state:
description:
- Create, delete or modifies a bucket.
required: false
default: present
type: str
choices: [ "present", "absent" ]
eradicate:
description:
- Define whether to eradicate the bucket on delete or leave in trash.
required: false
type: bool
default: false
extends_documentation_fragment:
- purestorage.fb
'''
EXAMPLES = '''
- name: Create new bucket named foo in account bar
purefb_bucket:
name: foo
account: bar
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
- name: Delete bucket named foo in account bar
purefb_bucket:
name: foo
account: bar
state: absent
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
- name: Recover deleted bucket named foo in account bar
purefb_bucket:
name: foo
account: bar
state: present
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
- name: Eradicate bucket named foo in account bar
purefb_bucket:
name: foo
account: bar
state: absent
eradicate: true
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
'''
RETURN = '''
'''
HAS_PURITY_FB = True
try:
from purity_fb import Bucket, Reference
except ImportError:
HAS_PURITY_FB = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pure import get_blade, purefb_argument_spec
MIN_REQUIRED_API_VERSION = '1.5'
def get_s3acc(module, blade):
"""Return Object Store Account or None"""
s3acc = None
accts = blade.object_store_accounts.list_object_store_accounts()
for acct in range(0, len(accts.items)):
if accts.items[acct].name == module.params['account']:
s3acc = accts.items[acct]
return s3acc
def get_bucket(module, blade):
"""Return Bucket or None"""
s3bucket = None
buckets = blade.buckets.list_buckets()
for bucket in range(0, len(buckets.items)):
if buckets.items[bucket].name == module.params['name']:
s3bucket = buckets.items[bucket]
return s3bucket
def create_bucket(module, blade):
"""Create bucket"""
changed = False
try:
attr = Bucket()
attr.account = Reference(name=module.params['account'])
blade.buckets.create_buckets(names=[module.params['name']], account=attr)
changed = True
except Exception:
module.fail_json(msg='Object Store Bucket {0}: Creation failed'.format(module.params['name']))
module.exit_json(changed=changed)
def delete_bucket(module, blade):
""" Delete Bucket"""
changed = False
try:
blade.buckets.update_buckets(names=[module.params['name']],
destroyed=Bucket(destroyed=True))
changed = True
if module.params['eradicate']:
try:
blade.buckets.delete_buckets(names=[module.params['name']])
changed = True
except Exception:
module.fail_json(msg='Object Store Bucket {0}: Eradication failed'.format(module.params['name']))
except Exception:
module.fail_json(msg='Object Store Bucket {0}: Deletion failed'.format(module.params['name']))
module.exit_json(changed=changed)
def recover_bucket(module, blade):
""" Recover Bucket"""
changed = False
try:
blade.buckets.update_buckets(names=[module.params['name']],
destroyed=Bucket(destroyed=False))
changed = True
except Exception:
module.fail_json(msg='Object Store Bucket {0}: Recovery failed'.format(module.params['name']))
module.exit_json(changed=changed)
def eradicate_bucket(module, blade):
""" Eradicate Bucket"""
changed = False
try:
blade.buckets.delete_buckets(names=[module.params['name']])
changed = True
except Exception:
module.fail_json(msg='Object Store Bucket {0}: Eradication failed'.format(module.params['name']))
module.exit_json(changed=changed)
def main():
argument_spec = purefb_argument_spec()
argument_spec.update(
dict(
name=dict(required=True),
account=dict(required=True),
eradicate=dict(default='false', type='bool'),
state=dict(default='present', choices=['present', 'absent']),
)
)
module = AnsibleModule(argument_spec)
if not HAS_PURITY_FB:
module.fail_json(msg='purity_fb sdk is required for this module')
state = module.params['state']
blade = get_blade(module)
api_version = blade.api_version.list_versions().versions
if MIN_REQUIRED_API_VERSION not in api_version:
module.fail_json(msg="Purity//FB must be upgraded to support this module.")
bucket = get_bucket(module, blade)
if not get_s3acc(module, blade):
module.fail_json(msg="Object Store Account {0} does not exist.".format(module.params['account']))
if state == 'present' and not bucket:
create_bucket(module, blade)
elif state == 'present' and bucket and bucket.destroyed:
recover_bucket(module, blade)
elif state == 'absent' and bucket and not bucket.destroyed:
delete_bucket(module, blade)
elif state == 'absent' and bucket and bucket.destroyed and module.params['eradicate']:
eradicate_bucket(module, blade)
elif state == 'absent' and not bucket:
module.exit_json(changed=False)
module.exit_json(changed=False)
if __name__ == '__main__':
main()

View file

@ -1,347 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2018, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: purefb_ds
version_added: '2.8'
short_description: Configure FlashBlade Directory Service
description:
- Create or erase directory services configurations. There is no facility
to SSL certificates at this time. Use the FlashBlade GUI for this
additional configuration work.
- To modify an existing directory service configuration you must first delete
an existing configuration and then recreate with new settings.
author:
- Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
state:
description:
- Create or delete directory service configuration
default: present
type: str
choices: [ absent, present ]
dstype:
description:
- The type of directory service to work on
choices: [ management, nfs, smb ]
type: str
enable:
description:
- Whether to enable or disable directory service support.
default: false
type: bool
uri:
description:
- A list of up to 30 URIs of the directory servers. Each URI must include
the scheme ldap:// or ldaps:// (for LDAP over SSL), a hostname, and a
domain name or IP address. For example, ldap://ad.company.com configures
the directory service with the hostname "ad" in the domain "company.com"
while specifying the unencrypted LDAP protocol.
type: list
base_dn:
description:
- Sets the base of the Distinguished Name (DN) of the directory service
groups. The base should consist of only Domain Components (DCs). The
base_dn will populate with a default value when a URI is entered by
parsing domain components from the URI. The base DN should specify DC=
for each domain component and multiple DCs should be separated by commas.
required: true
type: str
bind_password:
description:
- Sets the password of the bind_user user name account.
type: str
bind_user:
description:
- Sets the user name that can be used to bind to and query the directory.
- For Active Directory, enter the username - often referred to as
sAMAccountName or User Logon Name - of the account that is used to
perform directory lookups.
- For OpenLDAP, enter the full DN of the user.
type: str
nis_servers:
description:
- A list of up to 30 IP addresses or FQDNs for NIS servers.
- This cannot be used in conjunction with LDAP configurations.
type: list
version_added: 2.9
nis_domain:
description:
- The NIS domain to search
- This cannot be used in conjunction with LDAP configurations.
type: str
version_added: 2.9
join_ou:
description:
- The optional organizational unit (OU) where the machine account
for the directory service will be created.
type: str
version_added: 2.9
extends_documentation_fragment:
- purestorage.fb
'''
EXAMPLES = r'''
- name: Delete existing management directory service
purefb_ds:
dstype: management
state: absent
fb_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
- name: Create NFS directory service (disabled)
purefb_ds:
dstype: nfs
uri: "ldaps://lab.purestorage.com"
base_dn: "DC=lab,DC=purestorage,DC=com"
bind_user: Administrator
bind_password: password
fb_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
- name: Enable existing SMB directory service
purefb_ds:
dstypr: smb
enable: true
fb_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
- name: Disable existing management directory service
purefb_ds:
dstype: management
enable: false
fb_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
- name: Create NFS directory service (enabled)
purefb_ds:
dstype: nfs
enable: true
uri: "ldaps://lab.purestorage.com"
base_dn: "DC=lab,DC=purestorage,DC=com"
bind_user: Administrator
bind_password: password
fb_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
'''
RETURN = r'''
'''
NIS_API_VERSION = '1.7'
HAS_PURITY_FB = True
try:
from purity_fb import DirectoryService
except ImportError:
HAS_PURITY_FB = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pure import get_blade, purefb_argument_spec
def update_ds(module, blade):
"""Update Directory Service"""
# This module is a place-holder until we figure out a way to
# update the config on the fly rather than deleting and resetting
changed = False
module.exit_json(changed=changed)
def enable_ds(module, blade):
"""Enable Directory Service"""
changed = True
if not module.check_mode:
try:
blade.directory_services.update_directory_services(names=[module.params['dstype']],
directory_service=DirectoryService(enabled=True))
changed = True
except Exception:
module.fail_json(msg='Enable {0} Directory Service failed: Check Configuration'.format(module.params['dstype']))
module.exit_json(changed=changed)
def disable_ds(module, blade):
"""Disable Directory Service"""
changed = True
if not module.check_mode:
try:
blade.directory_services.update_directory_services(names=[module.params['dstype']],
directory_service=DirectoryService(enabled=False))
except Exception:
module.fail_json(msg='Disable {0} Directory Service failed'.format(module.params['dstype']))
module.exit_json(changed=changed)
def delete_ds(module, blade):
"""Delete Directory Service"""
changed = True
if not module.check_mode:
dirserv = blade.directory_services.list_directory_services(names=[module.params['dstype']])
try:
if module.params['dstype'] == 'management':
if dirserv.items[0].uris:
dir_service = DirectoryService(uris=[''],
base_dn="",
bind_user="",
bind_password="",
enabled=False)
else:
changed = False
elif module.params['dstype'] == 'smb':
if dirserv.items[0].uris:
smb_attrs = {'join_ou': ''}
dir_service = DirectoryService(uris=[''],
base_dn='',
bind_user='',
bind_password='',
smb=smb_attrs,
enabled=False)
else:
changed = False
elif module.params['dstype'] == 'nfs':
if dirserv.items[0].uris:
dir_service = DirectoryService(uris=[''],
base_dn='',
bind_user='',
bind_password='',
enabled=False)
elif dirserv.items[0].nfs.nis_domains:
nfs_attrs = {'nis_domains': [],
'nis_servers': []}
dir_service = DirectoryService(nfs=nfs_attrs,
enabled=False)
else:
changed = False
if changed:
blade.directory_services.update_directory_services(names=[module.params['dstype']],
directory_service=dir_service)
except Exception:
module.fail_json(msg='Delete {0} Directory Service failed'.format(module.params['dstype']))
module.exit_json(changed=changed)
def create_ds(module, blade):
"""Create Directory Service"""
changed = True
if not module.check_mode:
try:
if module.params['dstype'] == 'management':
if module.params['uri']:
dir_service = DirectoryService(uris=module.params['uri'][0:30],
base_dn=module.params['base_dn'],
bind_user=module.params['bind_user'],
bind_password=module.params['bind_password'],
enabled=module.params['enable'])
else:
module.fail_json(msg="URI and associated params must be specified to create dstype {0}".format(module.params['dstype']))
elif module.params['dstype'] == 'smb':
if module.params['uri']:
smb_attrs = {'join_ou': module.params['join_ou']}
dir_service = DirectoryService(uris=module.params['uri'][0:30],
base_dn=module.params['base_dn'],
bind_user=module.params['bind_user'],
bind_password=module.params['bind_password'],
smb=smb_attrs,
enabled=module.params['enable'])
else:
module.fail_json(msg="URI and associated params must be specified to create dstype {0}".format(module.params['dstype']))
elif module.params['dstype'] == 'nfs':
if module.params['nis_domain']:
nfs_attrs = {'nis_domains': [module.params['nis_domain']],
'nis_servers': module.params['nis_servers'][0:30]}
dir_service = DirectoryService(nfs=nfs_attrs,
enabled=module.params['enable'])
else:
dir_service = DirectoryService(uris=module.params['uri'][0:30],
base_dn=module.params['base_dn'],
bind_user=module.params['bind_user'],
bind_password=module.params['bind_password'],
enabled=module.params['enable'])
blade.directory_services.update_directory_services(names=[module.params['dstype']],
directory_service=dir_service)
except Exception:
module.fail_json(msg='Create {0} Directory Service failed: Check configuration'.format(module.params['dstype']))
module.exit_json(changed=changed)
def main():
argument_spec = purefb_argument_spec()
argument_spec.update(dict(
uri=dict(type='list'),
dstype=dict(required=True, type='str', choices=['management', 'nfs', 'smb']),
state=dict(type='str', default='present', choices=['absent', 'present']),
enable=dict(type='bool', default=False),
bind_password=dict(type='str', no_log=True),
bind_user=dict(type='str'),
base_dn=dict(type='str'),
join_ou=dict(type='str'),
nis_domain=dict(type='str'),
nis_servers=dict(type='list'),
))
required_together = [['uri', 'bind_password', 'bind_user', 'base_dn'],
['nis_servers', 'nis_domain'],
['join_ou', 'uri']]
mutually_exclusive = [['uri', 'nis_domain']]
module = AnsibleModule(argument_spec,
required_together=required_together,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True)
if not HAS_PURITY_FB:
module.fail_json(msg='purity_fb sdk is required for this module')
state = module.params['state']
blade = get_blade(module)
api_version = blade.api_version.list_versions().versions
ds_configured = False
dirserv = blade.directory_services.list_directory_services(names=[module.params['dstype']])
ds_enabled = dirserv.items[0].enabled
if dirserv.items[0].base_dn is not None:
ds_configured = True
if (module.params['nis_domain'] or module.params['join_ou']) and (NIS_API_VERSION not in api_version):
module.fail_json(msg="NFS or SMB directory service attributes are not supported in your FlashBlade Purity version.")
ldap_uri = False
set_ldap = False
for uri in range(0, len(dirserv.items[0].uris)):
if "ldap" in dirserv.items[0].uris[uri].lower():
ldap_uri = True
if module.params['uri']:
for uri in range(0, len(module.params['uri'])):
if "ldap" in module.params['uri'][uri].lower():
set_ldap = True
if not module.params['uri'] and ldap_uri or \
module.params['uri'] and set_ldap:
if module.params['nis_servers'] or module.params['nis_domain']:
module.fail_json(msg="NIS configuration not supported in an LDAP environment")
if state == 'absent':
delete_ds(module, blade)
elif ds_configured and module.params['enable'] and ds_enabled:
update_ds(module, blade)
elif ds_configured and not module.params['enable'] and ds_enabled:
disable_ds(module, blade)
elif ds_configured and module.params['enable'] and not ds_enabled:
enable_ds(module, blade)
# Now we have enabled the DS lets make sure there aren't any new updates...
update_ds(module, blade)
elif not ds_configured and state == 'present':
create_ds(module, blade)
else:
module.exit_json(changed=False)
if __name__ == '__main__':
main()

View file

@ -1,176 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2018, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: purefb_dsrole
version_added: '2.8'
short_description: Configure FlashBlade Management Directory Service Roles
description:
- Set or erase directory services role configurations.
author:
- Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
state:
description:
- Create or delete directory service role
default: present
type: str
choices: [ absent, present ]
role:
description:
- The directory service role to work on
choices: [ array_admin, ops_admin, readonly, storage_admin ]
type: str
group_base:
description:
- Specifies where the configured group is located in the directory
tree. This field consists of Organizational Units (OUs) that combine
with the base DN attribute and the configured group CNs to complete
the full Distinguished Name of the groups. The group base should
specify OU= for each OU and multiple OUs should be separated by commas.
The order of OUs is important and should get larger in scope from left
to right.
- Each OU should not exceed 64 characters in length.
type: str
group:
description:
- Sets the common Name (CN) of the configured directory service group
containing users for the FlashBlade. This name should be just the
Common Name of the group without the CN= specifier.
- Common Names should not exceed 64 characters in length.
type: str
extends_documentation_fragment:
- purestorage.fb
'''
EXAMPLES = r'''
- name: Delete existing array_admin directory service role
purefb_dsrole:
role: array_admin
state: absent
fb_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
- name: Create array_admin directory service role
purefb_dsrole:
role: array_admin
group_base: "OU=PureGroups,OU=SANManagers"
group: pureadmins
fb_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
- name: Update ops_admin directory service role
purefb_dsrole:
role: ops_admin
group_base: "OU=PureGroups"
group: opsgroup
fb_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
'''
RETURN = r'''
'''
HAS_PURITY_FB = True
try:
from purity_fb import DirectoryServiceRole
except ImportError:
HAS_PURITY_FB = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pure import get_blade, purefb_argument_spec
def update_role(module, blade):
"""Update Directory Service Role"""
changed = False
role = blade.directory_services.list_directory_services_roles(names=[module.params['role']])
if role.items[0].group_base != module.params['group_base'] or role.items[0].group != module.params['group']:
try:
role = DirectoryServiceRole(group_base=module.params['group_base'],
group=module.params['group'])
blade.directory_services.update_directory_services_roles(names=[module.params['role']],
directory_service_role=role)
changed = True
except Exception:
module.fail_json(msg='Update Directory Service Role {0} failed'.format(module.params['role']))
module.exit_json(changed=changed)
def delete_role(module, blade):
"""Delete Directory Service Role"""
changed = False
try:
role = DirectoryServiceRole(group_base='',
group='')
blade.directory_services.update_directory_services_roles(names=[module.params['role']],
directory_service_role=role)
changed = True
except Exception:
module.fail_json(msg='Delete Directory Service Role {0} failed'.format(module.params['role']))
module.exit_json(changed=changed)
def create_role(module, blade):
"""Create Directory Service Role"""
changed = False
try:
role = DirectoryServiceRole(group_base=module.params['group_base'],
group=module.params['group'])
blade.directory_services.update_directory_services_roles(names=[module.params['role']],
directory_service_role=role)
changed = True
except Exception:
module.fail_json(msg='Create Directory Service Role {0} failed: Check configuration'.format(module.params['role']))
module.exit_json(changed=changed)
def main():
argument_spec = purefb_argument_spec()
argument_spec.update(dict(
role=dict(required=True, type='str', choices=['array_admin', 'ops_admin', 'readonly', 'storage_admin']),
state=dict(type='str', default='present', choices=['absent', 'present']),
group_base=dict(type='str'),
group=dict(type='str'),
))
required_together = [['group', 'group_base']]
module = AnsibleModule(argument_spec,
required_together=required_together,
supports_check_mode=False)
if not HAS_PURITY_FB:
module.fail_json(msg='purity_fb sdk is required for this module')
state = module.params['state']
blade = get_blade(module)
role_configured = False
role = blade.directory_services.list_directory_services_roles(names=[module.params['role']])
if role.items[0].group is not None:
role_configured = True
if state == 'absent' and role_configured:
delete_role(module, blade)
elif role_configured and state == 'present':
update_role(module, blade)
elif not role_configured and state == 'present':
create_role(module, blade)
else:
module.exit_json(changed=False)
if __name__ == '__main__':
main()

View file

@ -1,438 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: purefb_fs
version_added: "2.6"
short_description: Manage filesystemon Pure Storage FlashBlade`
description:
- This module manages filesystems on Pure Storage FlashBlade.
author: Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
name:
description:
- Filesystem Name.
required: true
type: str
state:
description:
- Create, delete or modifies a filesystem.
required: false
default: present
type: str
choices: [ "present", "absent" ]
eradicate:
description:
- Define whether to eradicate the filesystem on delete or leave in trash.
required: false
type: bool
default: false
size:
description:
- Volume size in M, G, T or P units. See examples.
type: str
required: false
default: 32G
nfsv3:
description:
- Define whether to NFSv3 protocol is enabled for the filesystem.
required: false
type: bool
default: true
version_added: 2.9
nfsv4:
description:
- Define whether to NFSv4.1 protocol is enabled for the filesystem.
required: false
type: bool
default: true
version_added: 2.9
nfs_rules:
description:
- Define the NFS rules in operation.
required: false
default: '*(rw,no_root_squash)'
type: str
smb:
description:
- Define whether to SMB protocol is enabled for the filesystem.
required: false
type: bool
default: false
http:
description:
- Define whether to HTTP/HTTPS protocol is enabled for the filesystem.
required: false
type: bool
default: false
snapshot:
description:
- Define whether a snapshot directory is enabled for the filesystem.
required: false
type: bool
default: false
fastremove:
description:
- Define whether the fast remove directory is enabled for the filesystem.
required: false
type: bool
default: false
hard_limit:
description:
- Define whether the capacity for a filesystem is a hard limit.
- CAUTION This will cause the filesystem to go Read-Only if the
capacity has already exceeded the logical size of the filesystem.
required: false
type: bool
default: false
version_added: 2.8
user_quota:
description:
- Default quota in M, G, T or P units for a user under this file system.
required: false
type: str
version_added: 2.9
group_quota:
description:
- Default quota in M, G, T or P units for a group under this file system.
required: false
type: str
version_added: 2.9
extends_documentation_fragment:
- purestorage.fb
'''
EXAMPLES = '''
- name: Create new filesystem named foo
purefb_fs:
name: foo
size: 1T
state: present
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
- name: Delete filesystem named foo
purefb_fs:
name: foo
state: absent
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
- name: Recover filesystem named foo
purefb_fs:
name: foo
state: present
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
- name: Eradicate filesystem named foo
purefb_fs:
name: foo
state: absent
eradicate: true
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
- name: Modify attributes of an existing filesystem named foo
purefb_fs:
name: foo
size: 2T
nfsv3 : false
nfsv4 : true
user_quota: 10K
group_quota: 25M
nfs_rules: '*(ro)'
snapshot: true
fastremove: true
hard_limit: true
smb: true
state: present
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641'''
RETURN = '''
'''
HAS_PURITY_FB = True
try:
from purity_fb import FileSystem, ProtocolRule, NfsRule
except ImportError:
HAS_PURITY_FB = False
from ansible.module_utils.basic import AnsibleModule, human_to_bytes
from ansible.module_utils.pure import get_blade, purefb_argument_spec
HARD_LIMIT_API_VERSION = '1.4'
NFSV4_API_VERSION = '1.6'
def get_fs(module, blade):
"""Return Filesystem or None"""
fsys = []
fsys.append(module.params['name'])
try:
res = blade.file_systems.list_file_systems(names=fsys)
return res.items[0]
except Exception:
return None
def create_fs(module, blade):
"""Create Filesystem"""
changed = True
if not module.check_mode:
try:
if not module.params['size']:
module.params['size'] = '32G'
size = human_to_bytes(module.params['size'])
if module.params['user_quota']:
user_quota = human_to_bytes(module.params['user_quota'])
else:
user_quota = None
if module.params['group_quota']:
group_quota = human_to_bytes(module.params['group_quota'])
else:
group_quota = None
api_version = blade.api_version.list_versions().versions
if HARD_LIMIT_API_VERSION in api_version:
if NFSV4_API_VERSION in api_version:
fs_obj = FileSystem(name=module.params['name'],
provisioned=size,
fast_remove_directory_enabled=module.params['fastremove'],
hard_limit_enabled=module.params['hard_limit'],
snapshot_directory_enabled=module.params['snapshot'],
nfs=NfsRule(v3_enabled=module.params['nfsv3'],
v4_1_enabled=module.params['nfsv4'],
rules=module.params['nfs_rules']),
smb=ProtocolRule(enabled=module.params['smb']),
http=ProtocolRule(enabled=module.params['http']),
default_user_quota=user_quota,
default_group_quota=group_quota
)
else:
fs_obj = FileSystem(name=module.params['name'],
provisioned=size,
fast_remove_directory_enabled=module.params['fastremove'],
hard_limit_enabled=module.params['hard_limit'],
snapshot_directory_enabled=module.params['snapshot'],
nfs=NfsRule(enabled=module.params['nfsv3'], rules=module.params['nfs_rules']),
smb=ProtocolRule(enabled=module.params['smb']),
http=ProtocolRule(enabled=module.params['http'])
)
else:
fs_obj = FileSystem(name=module.params['name'],
provisioned=size,
fast_remove_directory_enabled=module.params['fastremove'],
snapshot_directory_enabled=module.params['snapshot'],
nfs=NfsRule(enabled=module.params['nfsv3'], rules=module.params['nfs_rules']),
smb=ProtocolRule(enabled=module.params['smb']),
http=ProtocolRule(enabled=module.params['http'])
)
blade.file_systems.create_file_systems(fs_obj)
except Exception:
module.fail_json(msg="Failed to create filesystem {0}.".format(module.params['name']))
module.exit_json(changed=changed)
def modify_fs(module, blade):
"""Modify Filesystem"""
changed = True
if not module.check_mode:
mod_fs = False
attr = {}
if module.params['user_quota']:
user_quota = human_to_bytes(module.params['user_quota'])
if module.params['group_quota']:
group_quota = human_to_bytes(module.params['group_quota'])
fsys = get_fs(module, blade)
if fsys.destroyed:
attr['destroyed'] = False
mod_fs = True
if module.params['size']:
if human_to_bytes(module.params['size']) != fsys.provisioned:
attr['provisioned'] = human_to_bytes(module.params['size'])
mod_fs = True
api_version = blade.api_version.list_versions().versions
if NFSV4_API_VERSION in api_version:
if module.params['nfsv3'] and not fsys.nfs.v3_enabled:
attr['nfs'] = NfsRule(v3_enabled=module.params['nfsv3'])
mod_fs = True
if not module.params['nfsv3'] and fsys.nfs.v3_enabled:
attr['nfs'] = NfsRule(v3_enabled=module.params['nfsv3'])
mod_fs = True
if module.params['nfsv4'] and not fsys.nfs.v4_1_enabled:
attr['nfs'] = NfsRule(v4_1_enabled=module.params['nfsv4'])
mod_fs = True
if not module.params['nfsv4'] and fsys.nfs.v4_1_enabled:
attr['nfs'] = NfsRule(v4_1_enabled=module.params['nfsv4'])
mod_fs = True
if module.params['nfsv3'] or module.params['nfsv4'] and fsys.nfs.v3_enabled or fsys.nfs.v4_1_enabled:
if fsys.nfs.rules != module.params['nfs_rules']:
attr['nfs'] = NfsRule(rules=module.params['nfs_rules'])
mod_fs = True
if module.params['user_quota'] and user_quota != fsys.default_user_quota:
attr['default_user_quota'] = user_quota
mod_fs = True
if module.params['group_quota'] and group_quota != fsys.default_group_quota:
attr['default_group_quota'] = group_quota
mod_fs = True
else:
if module.params['nfsv3'] and not fsys.nfs.enabled:
attr['nfs'] = NfsRule(enabled=module.params['nfsv3'])
mod_fs = True
if not module.params['nfsv3'] and fsys.nfs.enabled:
attr['nfs'] = NfsRule(enabled=module.params['nfsv3'])
mod_fs = True
if module.params['nfsv3'] and fsys.nfs.enabled:
if fsys.nfs.rules != module.params['nfs_rules']:
attr['nfs'] = NfsRule(rules=module.params['nfs_rules'])
mod_fs = True
if module.params['smb'] and not fsys.smb.enabled:
attr['smb'] = ProtocolRule(enabled=module.params['smb'])
mod_fs = True
if not module.params['smb'] and fsys.smb.enabled:
attr['smb'] = ProtocolRule(enabled=module.params['smb'])
mod_fs = True
if module.params['http'] and not fsys.http.enabled:
attr['http'] = ProtocolRule(enabled=module.params['http'])
mod_fs = True
if not module.params['http'] and fsys.http.enabled:
attr['http'] = ProtocolRule(enabled=module.params['http'])
mod_fs = True
if module.params['snapshot'] and not fsys.snapshot_directory_enabled:
attr['snapshot_directory_enabled'] = module.params['snapshot']
mod_fs = True
if not module.params['snapshot'] and fsys.snapshot_directory_enabled:
attr['snapshot_directory_enabled'] = module.params['snapshot']
mod_fs = True
if module.params['fastremove'] and not fsys.fast_remove_directory_enabled:
attr['fast_remove_directory_enabled'] = module.params['fastremove']
mod_fs = True
if not module.params['fastremove'] and fsys.fast_remove_directory_enabled:
attr['fast_remove_directory_enabled'] = module.params['fastremove']
mod_fs = True
api_version = blade.api_version.list_versions().versions
if HARD_LIMIT_API_VERSION in api_version:
if not module.params['hard_limit'] and fsys.hard_limit_enabled:
attr['hard_limit_enabled'] = module.params['hard_limit']
mod_fs = True
if module.params['hard_limit'] and not fsys.hard_limit_enabled:
attr['hard_limit_enabled'] = module.params['hard_limit']
mod_fs = True
if mod_fs:
n_attr = FileSystem(**attr)
try:
blade.file_systems.update_file_systems(name=module.params['name'], attributes=n_attr)
except Exception:
module.fail_json(msg="Failed to update filesystem {0}.".format(module.params['name']))
else:
changed = False
module.exit_json(changed=changed)
def delete_fs(module, blade):
""" Delete Filesystem"""
changed = True
if not module.check_mode:
try:
api_version = blade.api_version.list_versions().versions
if NFSV4_API_VERSION in api_version:
blade.file_systems.update_file_systems(name=module.params['name'],
attributes=FileSystem(nfs=NfsRule(v3_enabled=False,
v4_1_enabled=False),
smb=ProtocolRule(enabled=False),
http=ProtocolRule(enabled=False),
destroyed=True)
)
else:
blade.file_systems.update_file_systems(name=module.params['name'],
attributes=FileSystem(nfs=NfsRule(enabled=False),
smb=ProtocolRule(enabled=False),
http=ProtocolRule(enabled=False),
destroyed=True)
)
if module.params['eradicate']:
try:
blade.file_systems.delete_file_systems(module.params['name'])
except Exception:
module.fail_json(msg="Failed to delete filesystem {0}.".format(module.params['name']))
except Exception:
module.fail_json(msg="Failed to update filesystem {0} prior to deletion.".format(module.params['name']))
module.exit_json(changed=changed)
def eradicate_fs(module, blade):
""" Eradicate Filesystem"""
changed = True
if not module.check_mode:
try:
blade.file_systems.delete_file_systems(module.params['name'])
except Exception:
module.fail_json(msg="Failed to eradicate filesystem {0}.".format(module.params['name']))
module.exit_json(changed=changed)
def main():
argument_spec = purefb_argument_spec()
argument_spec.update(
dict(
name=dict(required=True),
eradicate=dict(default='false', type='bool'),
nfsv3=dict(default='true', type='bool'),
nfsv4=dict(default='true', type='bool'),
nfs_rules=dict(default='*(rw,no_root_squash)'),
smb=dict(default='false', type='bool'),
http=dict(default='false', type='bool'),
snapshot=dict(default='false', type='bool'),
fastremove=dict(default='false', type='bool'),
hard_limit=dict(default='false', type='bool'),
user_quota=dict(type='str'),
group_quota=dict(type='str'),
state=dict(default='present', choices=['present', 'absent']),
size=dict()
)
)
module = AnsibleModule(argument_spec,
supports_check_mode=True)
if not HAS_PURITY_FB:
module.fail_json(msg='purity_fb sdk is required for this module')
state = module.params['state']
blade = get_blade(module)
fsys = get_fs(module, blade)
if state == 'present' and not fsys:
create_fs(module, blade)
elif state == 'present' and fsys:
modify_fs(module, blade)
elif state == 'absent' and fsys and not fsys.destroyed:
delete_fs(module, blade)
elif state == 'absent' and fsys and fsys.destroyed and module.params['eradicate']:
eradicate_fs(module, blade)
elif state == 'absent' and not fsys:
module.exit_json(changed=False)
if __name__ == '__main__':
main()

View file

@ -1,663 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2019, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or
# https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: purefb_info
version_added: '2.9'
short_description: Collect information from Pure Storage FlashBlade
description:
- Collect information from a Pure Storage FlashBlade running the
Purity//FB operating system. By default, the module will collect basic
information including hosts, host groups, protection
groups and volume counts. Additional information can be collected
based on the configured set of arguments.
author:
- Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
gather_subset:
description:
- When supplied, this argument will define the information to be collected.
Possible values for this include all, minimum, config, performance,
capacity, network, subnets, lags, filesystems and snapshots.
required: false
type: list
default: minimum
extends_documentation_fragment:
- purestorage.fb
'''
EXAMPLES = r'''
- name: collect default set of info
purefb_info:
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
register: blade_info
- name: show default information
debug:
msg: "{{ blade_info['purefb_info']['default'] }}"
- name: collect configuration and capacity info
purefb_info:
gather_subset:
- config
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
register: blade_info
- name: show config information
debug:
msg: "{{ blade_info['purefb_info']['config'] }}"
- name: collect all info
purefb_info:
gather_subset:
- all
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
register: blade_info
- name: show all information
debug:
msg: "{{ blade_info['purefb_info'] }}"
'''
RETURN = r'''
purefb_info:
description: Returns the information collected from the FlashBlade
returned: always
type: complex
sample: {
"capacity": {
"aggregate": {
"data_reduction": 1.1179228,
"snapshots": 0,
"total_physical": 17519748439,
"unique": 17519748439,
"virtual": 19585726464
},
"file-system": {
"data_reduction": 1.3642412,
"snapshots": 0,
"total_physical": 4748219708,
"unique": 4748219708,
"virtual": 6477716992
},
"object-store": {
"data_reduction": 1.0263462,
"snapshots": 0,
"total_physical": 12771528731,
"unique": 12771528731,
"virtual": 6477716992
},
"total": 83359896948925
},
"config": {
"alert_watchers": {
"enabled": true,
"name": "notify@acmestorage.com"
},
"array_management": {
"base_dn": null,
"bind_password": null,
"bind_user": null,
"enabled": false,
"name": "management",
"services": [
"management"
],
"uris": []
},
"directory_service_roles": {
"array_admin": {
"group": null,
"group_base": null
},
"ops_admin": {
"group": null,
"group_base": null
},
"readonly": {
"group": null,
"group_base": null
},
"storage_admin": {
"group": null,
"group_base": null
}
},
"dns": {
"domain": "demo.acmestorage.com",
"name": "demo-fb-1",
"nameservers": [
"8.8.8.8"
],
"search": [
"demo.acmestorage.com"
]
},
"nfs_directory_service": {
"base_dn": null,
"bind_password": null,
"bind_user": null,
"enabled": false,
"name": "nfs",
"services": [
"nfs"
],
"uris": []
},
"ntp": [
"0.ntp.pool.org"
],
"smb_directory_service": {
"base_dn": null,
"bind_password": null,
"bind_user": null,
"enabled": false,
"name": "smb",
"services": [
"smb"
],
"uris": []
},
"smtp": {
"name": "demo-fb-1",
"relay_host": null,
"sender_domain": "acmestorage.com"
},
"ssl_certs": {
"certificate": "-----BEGIN CERTIFICATE-----\n\n-----END CERTIFICATE-----",
"common_name": "Acme Storage",
"country": "US",
"email": null,
"intermediate_certificate": null,
"issued_by": "Acme Storage",
"issued_to": "Acme Storage",
"key_size": 4096,
"locality": null,
"name": "global",
"organization": "Acme Storage",
"organizational_unit": "Acme Storage",
"passphrase": null,
"private_key": null,
"state": null,
"status": "self-signed",
"valid_from": "1508433967000",
"valid_to": "2458833967000"
}
},
"default": {
"blades": 15,
"buckets": 7,
"filesystems": 2,
"flashblade_name": "demo-fb-1",
"object_store_accounts": 1,
"object_store_users": 1,
"purity_version": "2.2.0",
"snapshots": 1,
"total_capacity": 83359896948925
},
"filesystems": {
"k8s-pvc-d24b1357-579e-11e8-811f-ecf4bbc88f54": {
"destroyed": false,
"fast_remove": false,
"hard_limit": true,
"nfs_rules": "*(rw,no_root_squash)",
"provisioned": 21474836480,
"snapshot_enabled": false
},
"z": {
"destroyed": false,
"fast_remove": false,
"hard_limit": false,
"provisioned": 1073741824,
"snapshot_enabled": false
}
},
"lag": {
"uplink": {
"lag_speed": 0,
"port_speed": 40000000000,
"ports": [
{
"name": "CH1.FM1.ETH1.1"
},
{
"name": "CH1.FM1.ETH1.2"
},
],
"status": "healthy"
}
},
"network": {
"fm1.admin0": {
"address": "10.10.100.6",
"gateway": "10.10.100.1",
"mtu": 1500,
"netmask": "255.255.255.0",
"services": [
"support"
],
"type": "vip",
"vlan": 2200
},
"fm2.admin0": {
"address": "10.10.100.7",
"gateway": "10.10.100.1",
"mtu": 1500,
"netmask": "255.255.255.0",
"services": [
"support"
],
"type": "vip",
"vlan": 2200
},
"nfs1": {
"address": "10.10.100.4",
"gateway": "10.10.100.1",
"mtu": 1500,
"netmask": "255.255.255.0",
"services": [
"data"
],
"type": "vip",
"vlan": 2200
},
"vir0": {
"address": "10.10.100.5",
"gateway": "10.10.100.1",
"mtu": 1500,
"netmask": "255.255.255.0",
"services": [
"management"
],
"type": "vip",
"vlan": 2200
}
},
"performance": {
"aggregate": {
"bytes_per_op": 0,
"bytes_per_read": 0,
"bytes_per_write": 0,
"read_bytes_per_sec": 0,
"reads_per_sec": 0,
"usec_per_other_op": 0,
"usec_per_read_op": 0,
"usec_per_write_op": 0,
"write_bytes_per_sec": 0,
"writes_per_sec": 0
},
"http": {
"bytes_per_op": 0,
"bytes_per_read": 0,
"bytes_per_write": 0,
"read_bytes_per_sec": 0,
"reads_per_sec": 0,
"usec_per_other_op": 0,
"usec_per_read_op": 0,
"usec_per_write_op": 0,
"write_bytes_per_sec": 0,
"writes_per_sec": 0
},
"nfs": {
"bytes_per_op": 0,
"bytes_per_read": 0,
"bytes_per_write": 0,
"read_bytes_per_sec": 0,
"reads_per_sec": 0,
"usec_per_other_op": 0,
"usec_per_read_op": 0,
"usec_per_write_op": 0,
"write_bytes_per_sec": 0,
"writes_per_sec": 0
},
"s3": {
"bytes_per_op": 0,
"bytes_per_read": 0,
"bytes_per_write": 0,
"read_bytes_per_sec": 0,
"reads_per_sec": 0,
"usec_per_other_op": 0,
"usec_per_read_op": 0,
"usec_per_write_op": 0,
"write_bytes_per_sec": 0,
"writes_per_sec": 0
}
},
"snapshots": {
"z.188": {
"destroyed": false,
"source": "z",
"source_destroyed": false,
"suffix": "188"
}
},
"subnet": {
"new-mgmt": {
"gateway": "10.10.100.1",
"interfaces": [
{
"name": "fm1.admin0"
},
{
"name": "fm2.admin0"
},
{
"name": "nfs1"
},
{
"name": "vir0"
}
],
"lag": "uplink",
"mtu": 1500,
"prefix": "10.10.100.0/24",
"services": [
"data",
"management",
"support"
],
"vlan": 2200
}
}
}
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pure import get_blade, purefb_argument_spec
MIN_REQUIRED_API_VERSION = '1.3'
HARD_LIMIT_API_VERSION = '1.4'
def generate_default_dict(blade):
default_info = {}
defaults = blade.arrays.list_arrays().items[0]
default_info['flashblade_name'] = defaults.name
default_info['purity_version'] = defaults.version
default_info['filesystems'] = \
len(blade.file_systems.list_file_systems().items)
default_info['snapshots'] = \
len(blade.file_system_snapshots.list_file_system_snapshots().items)
default_info['buckets'] = len(blade.buckets.list_buckets().items)
default_info['object_store_users'] = \
len(blade.object_store_users.list_object_store_users().items)
default_info['object_store_accounts'] = \
len(blade.object_store_accounts.list_object_store_accounts().items)
default_info['blades'] = len(blade.blade.list_blades().items)
default_info['total_capacity'] = \
blade.arrays.list_arrays_space().items[0].capacity
return default_info
def generate_perf_dict(blade):
perf_info = {}
total_perf = blade.arrays.list_arrays_performance()
http_perf = blade.arrays.list_arrays_performance(protocol='http')
s3_perf = blade.arrays.list_arrays_performance(protocol='s3')
nfs_perf = blade.arrays.list_arrays_performance(protocol='nfs')
perf_info['aggregate'] = {
'bytes_per_op': total_perf.items[0].bytes_per_op,
'bytes_per_read': total_perf.items[0].bytes_per_read,
'bytes_per_write': total_perf.items[0].bytes_per_write,
'read_bytes_per_sec': total_perf.items[0].read_bytes_per_sec,
'reads_per_sec': total_perf.items[0].reads_per_sec,
'usec_per_other_op': total_perf.items[0].usec_per_other_op,
'usec_per_read_op': total_perf.items[0].usec_per_read_op,
'usec_per_write_op': total_perf.items[0].usec_per_write_op,
'write_bytes_per_sec': total_perf.items[0].write_bytes_per_sec,
'writes_per_sec': total_perf.items[0].writes_per_sec,
}
perf_info['http'] = {
'bytes_per_op': http_perf.items[0].bytes_per_op,
'bytes_per_read': http_perf.items[0].bytes_per_read,
'bytes_per_write': http_perf.items[0].bytes_per_write,
'read_bytes_per_sec': http_perf.items[0].read_bytes_per_sec,
'reads_per_sec': http_perf.items[0].reads_per_sec,
'usec_per_other_op': http_perf.items[0].usec_per_other_op,
'usec_per_read_op': http_perf.items[0].usec_per_read_op,
'usec_per_write_op': http_perf.items[0].usec_per_write_op,
'write_bytes_per_sec': http_perf.items[0].write_bytes_per_sec,
'writes_per_sec': http_perf.items[0].writes_per_sec,
}
perf_info['s3'] = {
'bytes_per_op': s3_perf.items[0].bytes_per_op,
'bytes_per_read': s3_perf.items[0].bytes_per_read,
'bytes_per_write': s3_perf.items[0].bytes_per_write,
'read_bytes_per_sec': s3_perf.items[0].read_bytes_per_sec,
'reads_per_sec': s3_perf.items[0].reads_per_sec,
'usec_per_other_op': s3_perf.items[0].usec_per_other_op,
'usec_per_read_op': s3_perf.items[0].usec_per_read_op,
'usec_per_write_op': s3_perf.items[0].usec_per_write_op,
'write_bytes_per_sec': s3_perf.items[0].write_bytes_per_sec,
'writes_per_sec': s3_perf.items[0].writes_per_sec,
}
perf_info['nfs'] = {
'bytes_per_op': nfs_perf.items[0].bytes_per_op,
'bytes_per_read': nfs_perf.items[0].bytes_per_read,
'bytes_per_write': nfs_perf.items[0].bytes_per_write,
'read_bytes_per_sec': nfs_perf.items[0].read_bytes_per_sec,
'reads_per_sec': nfs_perf.items[0].reads_per_sec,
'usec_per_other_op': nfs_perf.items[0].usec_per_other_op,
'usec_per_read_op': nfs_perf.items[0].usec_per_read_op,
'usec_per_write_op': nfs_perf.items[0].usec_per_write_op,
'write_bytes_per_sec': nfs_perf.items[0].write_bytes_per_sec,
'writes_per_sec': nfs_perf.items[0].writes_per_sec,
}
return perf_info
def generate_config_dict(blade):
config_info = {}
config_info['dns'] = blade.dns.list_dns().items[0].to_dict()
config_info['smtp'] = blade.smtp.list_smtp().items[0].to_dict()
config_info['alert_watchers'] = \
blade.alert_watchers.list_alert_watchers().items[0].to_dict()
api_version = blade.api_version.list_versions().versions
if HARD_LIMIT_API_VERSION in api_version:
config_info['array_management'] = \
blade.directory_services.list_directory_services(names=['management']).items[0].to_dict()
config_info['directory_service_roles'] = {}
roles = blade.directory_services.list_directory_services_roles()
for role in range(0, len(roles.items)):
role_name = roles.items[role].name
config_info['directory_service_roles'][role_name] = {
'group': roles.items[role].group,
'group_base': roles.items[role].group_base
}
config_info['nfs_directory_service'] = \
blade.directory_services.list_directory_services(names=['nfs']).items[0].to_dict()
config_info['smb_directory_service'] = \
blade.directory_services.list_directory_services(names=['smb']).items[0].to_dict()
config_info['ntp'] = blade.arrays.list_arrays().items[0].ntp_servers
config_info['ssl_certs'] = \
blade.certificates.list_certificates().items[0].to_dict()
return config_info
def generate_subnet_dict(blade):
sub_info = {}
subnets = blade.subnets.list_subnets()
for sub in range(0, len(subnets.items)):
sub_name = subnets.items[sub].name
if subnets.items[sub].enabled:
sub_info[sub_name] = {
'gateway': subnets.items[sub].gateway,
'mtu': subnets.items[sub].mtu,
'vlan': subnets.items[sub].vlan,
'prefix': subnets.items[sub].prefix,
'services': subnets.items[sub].services,
}
sub_info[sub_name]['lag'] = subnets.items[sub].link_aggregation_group.name
sub_info[sub_name]['interfaces'] = []
for iface in range(0, len(subnets.items[sub].interfaces)):
sub_info[sub_name]['interfaces'].append({'name': subnets.items[sub].interfaces[iface].name})
return sub_info
def generate_lag_dict(blade):
lag_info = {}
groups = blade.link_aggregation_groups.list_link_aggregation_groups()
for groupcnt in range(0, len(groups.items)):
lag_name = groups.items[groupcnt].name
lag_info[lag_name] = {
'lag_speed': groups.items[groupcnt].lag_speed,
'port_speed': groups.items[groupcnt].port_speed,
'status': groups.items[groupcnt].status,
}
lag_info[lag_name]['ports'] = []
for port in range(0, len(groups.items[groupcnt].ports)):
lag_info[lag_name]['ports'].append({'name': groups.items[groupcnt].ports[port].name})
return lag_info
def generate_network_dict(blade):
net_info = {}
ports = blade.network_interfaces.list_network_interfaces()
for portcnt in range(0, len(ports.items)):
int_name = ports.items[portcnt].name
if ports.items[portcnt].enabled:
net_info[int_name] = {
'type': ports.items[portcnt].type,
'mtu': ports.items[portcnt].mtu,
'vlan': ports.items[portcnt].vlan,
'address': ports.items[portcnt].address,
'services': ports.items[portcnt].services,
'gateway': ports.items[portcnt].gateway,
'netmask': ports.items[portcnt].netmask,
}
return net_info
def generate_capacity_dict(blade):
capacity_info = {}
total_cap = blade.arrays.list_arrays_space()
file_cap = blade.arrays.list_arrays_space(type='file-system')
object_cap = blade.arrays.list_arrays_space(type='object-store')
capacity_info['total'] = total_cap.items[0].capacity
capacity_info['aggregate'] = {
'data_reduction': total_cap.items[0].space.data_reduction,
'snapshots': total_cap.items[0].space.snapshots,
'total_physical': total_cap.items[0].space.total_physical,
'unique': total_cap.items[0].space.unique,
'virtual': total_cap.items[0].space.virtual,
}
capacity_info['file-system'] = {
'data_reduction': file_cap.items[0].space.data_reduction,
'snapshots': file_cap.items[0].space.snapshots,
'total_physical': file_cap.items[0].space.total_physical,
'unique': file_cap.items[0].space.unique,
'virtual': file_cap.items[0].space.virtual,
}
capacity_info['object-store'] = {
'data_reduction': object_cap.items[0].space.data_reduction,
'snapshots': object_cap.items[0].space.snapshots,
'total_physical': object_cap.items[0].space.total_physical,
'unique': object_cap.items[0].space.unique,
'virtual': file_cap.items[0].space.virtual,
}
return capacity_info
def generate_snap_dict(blade):
snap_info = {}
snaps = blade.file_system_snapshots.list_file_system_snapshots()
for snap in range(0, len(snaps.items)):
snapshot = snaps.items[snap].name
snap_info[snapshot] = {
'destroyed': snaps.items[snap].destroyed,
'source': snaps.items[snap].source,
'suffix': snaps.items[snap].suffix,
'source_destroyed': snaps.items[snap].source_destroyed,
}
return snap_info
def generate_fs_dict(blade):
fs_info = {}
fsys = blade.file_systems.list_file_systems()
for fsystem in range(0, len(fsys.items)):
share = fsys.items[fsystem].name
fs_info[share] = {
'fast_remove': fsys.items[fsystem].fast_remove_directory_enabled,
'snapshot_enabled': fsys.items[fsystem].snapshot_directory_enabled,
'provisioned': fsys.items[fsystem].provisioned,
'destroyed': fsys.items[fsystem].destroyed,
}
if fsys.items[fsystem].http.enabled:
fs_info[share]['http'] = fsys.items[fsystem].http.enabled
if fsys.items[fsystem].smb.enabled:
fs_info[share]['smb_mode'] = fsys.items[fsystem].smb.acl_mode
if fsys.items[fsystem].nfs.enabled:
fs_info[share]['nfs_rules'] = fsys.items[fsystem].nfs.rules
api_version = blade.api_version.list_versions().versions
if HARD_LIMIT_API_VERSION in api_version:
fs_info[share]['hard_limit'] = fsys.items[fsystem].hard_limit_enabled
return fs_info
def main():
argument_spec = purefb_argument_spec()
argument_spec.update(dict(
gather_subset=dict(default='minimum', type='list',)
))
module = AnsibleModule(argument_spec, supports_check_mode=True)
blade = get_blade(module)
versions = blade.api_version.list_versions().versions
if MIN_REQUIRED_API_VERSION not in versions:
module.fail_json(msg='FlashBlade REST version not supported. Minimum version required: {0}'.format(MIN_REQUIRED_API_VERSION))
subset = [test.lower() for test in module.params['gather_subset']]
valid_subsets = ('all', 'minimum', 'config', 'performance', 'capacity',
'network', 'subnets', 'lags',
'filesystems', 'snapshots')
subset_test = (test in valid_subsets for test in subset)
if not all(subset_test):
module.fail_json(msg="value must gather_subset must be one or more of: %s, got: %s"
% (",".join(valid_subsets), ",".join(subset)))
info = {}
if 'minimum' in subset or 'all' in subset:
info['default'] = generate_default_dict(blade)
if 'performance' in subset or 'all' in subset:
info['performance'] = generate_perf_dict(blade)
if 'config' in subset or 'all' in subset:
info['config'] = generate_config_dict(blade)
if 'capacity' in subset or 'all' in subset:
info['capacity'] = generate_capacity_dict(blade)
if 'lags' in subset or 'all' in subset:
info['lag'] = generate_lag_dict(blade)
if 'network' in subset or 'all' in subset:
info['network'] = generate_network_dict(blade)
if 'subnets' in subset or 'all' in subset:
info['subnet'] = generate_subnet_dict(blade)
if 'filesystems' in subset or 'all' in subset:
info['filesystems'] = generate_fs_dict(blade)
if 'snapshots' in subset or 'all' in subset:
info['snapshots'] = generate_snap_dict(blade)
module.exit_json(changed=False, purefb_info=info)
if __name__ == '__main__':
main()

View file

@ -1,202 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: purefb_network
version_added: "2.8"
short_description: Manage network interfaces in a Pure Storage FlashBlade
description:
- This module manages network interfaces on Pure Storage FlashBlade.
- When creating a network interface a subnet must already exist with
a network prefix that covers the IP address of the interface being
created.
author: Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
name:
description:
- Interface Name.
required: true
type: str
state:
description:
- Create, delete or modifies a network interface.
required: false
default: present
choices: [ "present", "absent" ]
type: str
address:
description:
- IP address of interface.
required: false
type: str
services:
description:
- Define which services are configured for the interfaces.
required: false
choices: [ "data" ]
default: data
type: str
itype:
description:
- Type of interface.
required: false
choices: [ "vip" ]
default: vip
type: str
extends_documentation_fragment:
- purestorage.fb
'''
EXAMPLES = '''
- name: Create new network interface named foo
purefb_network:
name: foo
address: 10.21.200.23
state: present
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
- name: Change IP address of network interface named foo
purefb_network:
name: foo
state: present
address: 10.21.200.123
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
- name: Delete network interface named foo
purefb_network:
name: foo
state: absent
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641'''
RETURN = '''
'''
HAS_PURITY_FB = True
try:
from purity_fb import NetworkInterface
except ImportError:
HAS_PURITY_FB = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pure import get_blade, purefb_argument_spec
MINIMUM_API_VERSION = '1.3'
def get_iface(module, blade):
"""Return Filesystem or None"""
iface = []
iface.append(module.params['name'])
try:
res = blade.network_interfaces.list_network_interfaces(names=iface)
return res.items[0]
except Exception:
return None
def create_iface(module, blade):
"""Create Network Interface"""
iface = []
services = []
iface.append(module.params['name'])
services.append(module.params['services'])
try:
blade.network_interfaces.create_network_interfaces(names=iface,
network_interface=NetworkInterface(address=module.params['address'],
services=services,
type=module.params['itype']
)
)
changed = True
except Exception:
module.fail_json(msg='Interface creation failed. Check valid subnet exists for IP address {0}'.format(module.params['address']))
changed = False
module.exit_json(changed=changed)
def modify_iface(module, blade):
"""Modify Network Interface IP address"""
changed = False
iface = get_iface(module, blade)
iface_new = []
iface_new.append(module.params['name'])
if module.params['address'] != iface.address:
try:
blade.network_interfaces.update_network_interfaces(names=iface_new,
network_interface=NetworkInterface(address=module.params['address']))
changed = True
except Exception:
changed = False
module.exit_json(changed=changed)
def delete_iface(module, blade):
""" Delete Network Interface"""
iface = []
iface.append(module.params['name'])
try:
blade.network_interfaces.delete_network_interfaces(names=iface)
changed = True
except Exception:
changed = False
module.exit_json(changed=changed)
def main():
argument_spec = purefb_argument_spec()
argument_spec.update(
dict(
name=dict(required=True),
state=dict(default='present', choices=['present', 'absent']),
address=dict(),
services=dict(default='data', choices=['data']),
itype=dict(default='vip', choices=['vip']),
)
)
required_if = [["state", "present", ["address"]]]
module = AnsibleModule(argument_spec,
required_if=required_if,
supports_check_mode=False)
if not HAS_PURITY_FB:
module.fail_json(msg='purity_fb sdk is required for this module')
state = module.params['state']
blade = get_blade(module)
api_version = blade.api_version.list_versions().versions
if MINIMUM_API_VERSION not in api_version:
module.fail_json(msg='Upgrade Purity//FB to enable this module')
iface = get_iface(module, blade)
if state == 'present' and not iface:
create_iface(module, blade)
elif state == 'present' and iface:
modify_iface(module, blade)
elif state == 'absent' and iface:
delete_iface(module, blade)
elif state == 'absent' and not iface:
module.exit_json(changed=False)
if __name__ == '__main__':
main()

View file

@ -1,114 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2018, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: purefb_ra
version_added: '2.9'
short_description: Enable or Disable Pure Storage FlashBlade Remote Assist
description:
- Enable or Disable Remote Assist for a Pure Storage FlashBlade.
author:
- Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
state:
description:
- Define state of remote assist
- When set to I(enable) the RA port can be exposed using the
I(debug) module.
type: str
default: present
choices: [ present, absent ]
extends_documentation_fragment:
- purestorage.fb
'''
EXAMPLES = r'''
- name: Enable Remote Assist port
purefb_ra:
fb_url: 10.10.10.2
api_token: T-9f276a18-50ab-446e-8a0c-666a3529a1b6
- name: Disable Remote Assist port
purefb_ra:
state: absent
fb_url: 10.10.10.2
api_token: T-9f276a18-50ab-446e-8a0c-666a3529a1b6
'''
RETURN = r'''
'''
HAS_PURITY_FB = True
try:
from purity_fb import Support
except ImportError:
HAS_PURITY_FB = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pure import get_blade, purefb_argument_spec
MIN_REQUIRED_API_VERSION = "1.6"
def enable_ra(module, blade):
"""Enable Remote Assist"""
changed = True
if not module.check_mode:
ra_settings = Support(remote_assist_active=True)
try:
blade.support.update_support(support=ra_settings)
except Exception:
module.fail_json(msg='Enabling Remote Assist failed')
module.exit_json(changed=changed)
def disable_ra(module, blade):
"""Disable Remote Assist"""
changed = True
if not module.check_mode:
ra_settings = Support(remote_assist_active=False)
try:
blade.support.update_support(support=ra_settings)
except Exception:
module.fail_json(msg='Disabling Remote Assist failed')
module.exit_json(changed=changed)
def main():
argument_spec = purefb_argument_spec()
argument_spec.update(dict(
state=dict(type='str', default='present', choices=['present', 'absent']),
))
module = AnsibleModule(argument_spec,
supports_check_mode=True)
blade = get_blade(module)
api_version = blade.api_version.list_versions().versions
if MIN_REQUIRED_API_VERSION not in api_version:
module.fail_json(msg="Purity//FB must be upgraded to support this module.")
if not HAS_PURITY_FB:
module.fail_json(msg='purity_fb SDK is required for this module')
if module.params['state'] == 'present' and not blade.support.list_support().items[0].remote_assist_active:
enable_ra(module, blade)
elif module.params['state'] == 'absent' and blade.support.list_support().items[0].remote_assist_active:
disable_ra(module, blade)
module.exit_json(changed=False)
if __name__ == '__main__':
main()

View file

@ -1,136 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2018, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: purefb_s3acc
version_added: '2.8'
short_description: Create or delete FlashBlade Object Store accounts
description:
- Create or delete object store accounts on a Pure Storage FlashBlade.
author:
- Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
state:
description:
- Create or delete object store account
default: present
choices: [ absent, present ]
type: str
name:
description:
- The name of object store account
type: str
extends_documentation_fragment:
- purestorage.fb
'''
EXAMPLES = r'''
- name: Create object store account foo
purefb_s3acc:
name: foo
fb_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
- name: Delete object store account foo
purefb_s3acc:
name: foo
state: absent
fb_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
'''
RETURN = r'''
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pure import get_blade, purefb_argument_spec
MIN_REQUIRED_API_VERSION = '1.3'
def get_s3acc(module, blade):
"""Return Object Store Account or None"""
s3acc = None
accts = blade.object_store_accounts.list_object_store_accounts()
for acct in range(0, len(accts.items)):
if accts.items[acct].name == module.params['name']:
s3acc = accts.items[acct]
return s3acc
def update_s3acc(module, blade):
"""Update Object Store Account"""
changed = False
module.exit_json(changed=changed)
def create_s3acc(module, blade):
"""Create Object Store Account"""
changed = False
try:
blade.object_store_accounts.create_object_store_accounts(names=[module.params['name']])
changed = True
except Exception:
module.fail_json(msg='Object Store Account {0}: Creation failed'.format(module.params['name']))
module.exit_json(changed=changed)
def delete_s3acc(module, blade):
"""Delete Object Store Account"""
changed = False
count = len(blade.object_store_users.list_object_store_users(filter='name=\'' + module.params['name'] + '/*\'').items)
if count != 0:
module.fail_json(msg='Remove all Users from Object Store Account {0} before deletion'.format(module.params['name']))
else:
try:
blade.object_store_accounts.delete_object_store_accounts(names=[module.params['name']])
changed = True
except Exception:
module.fail_json(msg='Object Store Account {0}: Deletion failed'.format(module.params['name']))
module.exit_json(changed=changed)
def main():
argument_spec = purefb_argument_spec()
argument_spec.update(dict(
name=dict(required=True, type='str'),
state=dict(default='present', choices=['present', 'absent']),
))
module = AnsibleModule(argument_spec,
supports_check_mode=False)
state = module.params['state']
blade = get_blade(module)
versions = blade.api_version.list_versions().versions
if MIN_REQUIRED_API_VERSION not in versions:
module.fail_json(msg='FlashBlade REST version not supported. Minimum version required: {0}'.format(MIN_REQUIRED_API_VERSION))
s3acc = get_s3acc(module, blade)
if state == 'absent' and s3acc:
delete_s3acc(module, blade)
elif state == 'present' and s3acc:
update_s3acc(module, blade)
elif not s3acc and state == 'present':
create_s3acc(module, blade)
else:
module.exit_json(changed=False)
if __name__ == '__main__':
main()

View file

@ -1,201 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2018, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: purefb_s3user
version_added: '2.8'
short_description: Create or delete FlashBlade Object Store account users
description:
- Create or delete object store account users on a Pure Storage FlashBlade.
author:
- Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
state:
description:
- Create or delete object store account user
default: present
choices: [ absent, present ]
type: str
name:
description:
- The name of object store user
type: str
account:
description:
- The name of object store account associated with user
type: str
access_key:
description:
- Create secret access key.
- Key can be exposed using the I(debug) module
type: bool
default: true
extends_documentation_fragment:
- purestorage.fb
'''
EXAMPLES = r'''
- name: Create object store user (with access ID and key) foo in account bar
purefb_s3user:
name: foo
account: bar
fb_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
register: result
- debug:
msg: "S3 User: {{ result['s3user_info'] }}"
- name: Delete object store user foo in account bar
purefb_s3user:
name: foo
account: bar
state: absent
fb_url: 10.10.10.2
api_token: e31060a7-21fc-e277-6240-25983c6c4592
'''
RETURN = r'''
'''
HAS_PURITY_FB = True
try:
from purity_fb import ObjectStoreAccessKey
except ImportError:
HAS_PURITY_FB = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pure import get_blade, purefb_argument_spec
MIN_REQUIRED_API_VERSION = '1.3'
def get_s3acc(module, blade):
"""Return Object Store Account or None"""
s3acc = None
accts = blade.object_store_accounts.list_object_store_accounts()
for acct in range(0, len(accts.items)):
if accts.items[acct].name == module.params['account']:
s3acc = accts.items[acct]
return s3acc
def get_s3user(module, blade):
"""Return Object Store Account or None"""
full_user = module.params['account'] + "/" + module.params['name']
s3user = None
s3users = blade.object_store_users.list_object_store_users()
for user in range(0, len(s3users.items)):
if s3users.items[user].name == full_user:
s3user = s3users.items[user]
return s3user
def update_s3user(module, blade):
"""Update Object Store User"""
changed = False
s3user_facts = {}
user = module.params['account'] + "/" + module.params['name']
if module.params['access_key']:
try:
result = blade.object_store_access_keys.create_object_store_access_keys(
object_store_access_key=ObjectStoreAccessKey(user={'name': user}))
s3user_facts['fb_s3user'] = {'user': user,
'access_key': result.items[0].secret_access_key,
'access_id': result.items[0].name}
except Exception:
delete_s3user(module, blade)
module.fail_json(msg='Object Store User {0}: Creation failed'.format(user))
changed = True
module.exit_json(changed=changed, s3user_info=s3user_facts)
def create_s3user(module, blade):
"""Create Object Store Account"""
s3user_facts = {}
changed = False
user = module.params['account'] + "/" + module.params['name']
try:
blade.object_store_users.create_object_store_users(names=[user])
if module.params['access_key']:
try:
result = blade.object_store_access_keys.create_object_store_access_keys(
object_store_access_key=ObjectStoreAccessKey(user={'name': user}))
s3user_facts['fb_s3user'] = {'user': user,
'access_key': result.items[0].secret_access_key,
'access_id': result.items[0].name}
except Exception:
delete_s3user(module, blade)
module.fail_json(msg='Object Store User {0}: Creation failed'.format(user))
changed = True
except Exception:
module.fail_json(msg='Object Store User {0}: Creation failed'.format(user))
module.exit_json(changed=changed, s3user_info=s3user_facts)
def delete_s3user(module, blade):
"""Delete Object Store Account"""
changed = False
user = module.params['account'] + "/" + module.params['name']
try:
blade.object_store_users.delete_object_store_users(names=[user])
changed = True
except Exception:
module.fail_json(msg='Object Store Account {0}: Deletion failed'.format(module.params['name']))
module.exit_json(changed=changed)
def main():
argument_spec = purefb_argument_spec()
argument_spec.update(dict(
name=dict(required=True, type='str'),
account=dict(required=True, type='str'),
access_key=dict(default='true', type='bool'),
state=dict(default='present', choices=['present', 'absent']),
))
module = AnsibleModule(argument_spec,
supports_check_mode=False)
if not HAS_PURITY_FB:
module.fail_json(msg='purity_fb sdk is required for this module')
state = module.params['state']
blade = get_blade(module)
versions = blade.api_version.list_versions().versions
if MIN_REQUIRED_API_VERSION not in versions:
module.fail_json(msg='FlashBlade REST version not supported. Minimum version required: {0}'.format(MIN_REQUIRED_API_VERSION))
s3acc = get_s3acc(module, blade)
if not s3acc:
module.fail_json(msg='Object Store Account {0} does not exist'.format(module.params['account']))
s3user = get_s3user(module, blade)
if state == 'absent' and s3user:
delete_s3user(module, blade)
elif state == 'present' and s3user:
update_s3user(module, blade)
elif not s3user and state == 'present':
create_s3user(module, blade)
else:
module.exit_json(changed=False)
if __name__ == '__main__':
main()

View file

@ -1,112 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2018, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: purefb_smtp
version_added: '2.9'
short_description: Configure SMTP for Pure Storage FlashBlade
description:
- Configure SMTP for a Pure Storage FlashBlade.
- Whilst there can be no relay host, a sender domain must be configured.
author:
- Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
host:
description: Relay server name
type: str
domain:
description: Domain name for alert messages
required: true
type: str
extends_documentation_fragment:
- purestorage.fb
'''
EXAMPLES = r'''
- name: Configure SMTP settings
purefb_smtp:
host: hostname
domain: xyz.com
fb_url: 10.10.10.2
api_token: T-9f276a18-50ab-446e-8a0c-666a3529a1b6
'''
RETURN = r'''
'''
HAS_PURITY_FB = True
try:
from purity_fb import Smtp
except ImportError:
HAS_PURITY_FB = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pure import get_blade, purefb_argument_spec
MIN_REQUIRED_API_VERSION = "1.6"
def set_smtp(module, blade):
"""Configure SMTP settings"""
changed = True
if not module.check_mode:
current_smtp = blade.smtp.list_smtp().items[0]
if module.params['host'] and module.params['host'] != current_smtp.relay_host:
smtp_settings = Smtp(relay_host=module.params['host'])
try:
blade.smtp.update_smtp(smtp_settings=smtp_settings)
except Exception:
module.fail_json(msg='Configuring SMTP relay host failed')
elif current_smtp.relay_host and not module.params['host']:
smtp_settings = Smtp(relay_host='')
try:
blade.smtp.update_smtp(smtp_settings=smtp_settings)
except Exception:
module.fail_json(msg='Configuring SMTP relay host failed')
if module.params['domain'] != current_smtp.sender_domain:
smtp_settings = Smtp(sender_domain=module.params['domain'])
try:
blade.smtp.update_smtp(smtp_settings=smtp_settings)
except Exception:
module.fail_json(msg='Configuring SMTP sender domain failed')
else:
changed = False
module.exit_json(changed=changed)
def main():
argument_spec = purefb_argument_spec()
argument_spec.update(dict(
host=dict(type='str'),
domain=dict(type='str', required=True),
))
module = AnsibleModule(argument_spec,
supports_check_mode=True)
blade = get_blade(module)
api_version = blade.api_version.list_versions().versions
if MIN_REQUIRED_API_VERSION not in api_version:
module.fail_json(msg="Purity//FB must be upgraded to support this module.")
if not HAS_PURITY_FB:
module.fail_json(msg='purity_fb SDK is required for this module')
set_smtp(module, blade)
module.exit_json(changed=False)
if __name__ == '__main__':
main()

View file

@ -1,227 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: purefb_snap
version_added: '2.6'
short_description: Manage filesystem snapshots on Pure Storage FlashBlades
description:
- Create or delete volumes and filesystem snapshots on Pure Storage FlashBlades.
author:
- Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
name:
description:
- The name of the source filesystem.
required: true
type: str
suffix:
description:
- Suffix of snapshot name.
type: str
state:
description:
- Define whether the filesystem snapshot should exist or not.
choices: [ absent, present ]
default: present
type: str
eradicate:
description:
- Define whether to eradicate the snapshot on delete or leave in trash.
type: bool
default: 'no'
extends_documentation_fragment:
- purestorage.fb
'''
EXAMPLES = r'''
- name: Create snapshot foo.ansible
purefb_snap:
name: foo
suffix: ansible
fb_url: 10.10.10.2
fb_api_token: e31060a7-21fc-e277-6240-25983c6c4592
state: present
- name: Delete snapshot named foo.snap
purefb_snap:
name: foo
suffix: snap
fb_url: 10.10.10.2
fb_api_token: e31060a7-21fc-e277-6240-25983c6c4592
state: absent
- name: Recover deleted snapshot foo.ansible
purefb_snap:
name: foo
suffix: ansible
fb_url: 10.10.10.2
fb_api_token: e31060a7-21fc-e277-6240-25983c6c4592
state: present
- name: Eradicate snapshot named foo.snap
purefb_snap:
name: foo
suffix: snap
eradicate: true
fb_url: 10.10.10.2
fb_api_token: e31060a7-21fc-e277-6240-25983c6c4592
state: absent
'''
RETURN = r'''
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pure import get_blade, purefb_argument_spec
from datetime import datetime
HAS_PURITY_FB = True
try:
from purity_fb import FileSystemSnapshot, SnapshotSuffix
except ImportError:
HAS_PURITY_FB = False
def get_fs(module, blade):
"""Return Filesystem or None"""
fs = []
fs.append(module.params['name'])
try:
res = blade.file_systems.list_file_systems(names=fs)
return res.items[0]
except Exception:
return None
def get_fssnapshot(module, blade):
"""Return Snapshot or None"""
try:
filt = 'source=\'' + module.params['name'] + '\' and suffix=\'' + module.params['suffix'] + '\''
res = blade.file_system_snapshots.list_file_system_snapshots(filter=filt)
return res.items[0]
except Exception:
return None
def create_snapshot(module, blade):
"""Create Snapshot"""
if not module.check_mode:
source = []
source.append(module.params['name'])
try:
blade.file_system_snapshots.create_file_system_snapshots(sources=source, suffix=SnapshotSuffix(module.params['suffix']))
changed = True
except Exception:
changed = False
module.exit_json(changed=changed)
def recover_snapshot(module, blade):
"""Recover deleted Snapshot"""
if not module.check_mode:
snapname = module.params['name'] + "." + module.params['suffix']
new_attr = FileSystemSnapshot(destroyed=False)
try:
blade.file_system_snapshots.update_file_system_snapshots(name=snapname, attributes=new_attr)
changed = True
except Exception:
changed = False
module.exit_json(changed=changed)
def update_snapshot(module, blade):
"""Update Snapshot"""
changed = False
module.exit_json(changed=changed)
def delete_snapshot(module, blade):
""" Delete Snapshot"""
if not module.check_mode:
snapname = module.params['name'] + "." + module.params['suffix']
new_attr = FileSystemSnapshot(destroyed=True)
try:
blade.file_system_snapshots.update_file_system_snapshots(name=snapname, attributes=new_attr)
changed = True
if module.params['eradicate']:
try:
blade.file_system_snapshots.delete_file_system_snapshots(name=snapname)
changed = True
except Exception:
changed = False
except Exception:
changed = False
module.exit_json(changed=changed)
def eradicate_snapshot(module, blade):
""" Eradicate Snapshot"""
if not module.check_mode:
snapname = module.params['name'] + "." + module.params['suffix']
try:
blade.file_system_snapshots.delete_file_system_snapshots(name=snapname)
changed = True
except Exception:
changed = False
module.exit_json(changed=changed)
def main():
argument_spec = purefb_argument_spec()
argument_spec.update(
dict(
name=dict(required=True),
suffix=dict(type='str'),
eradicate=dict(default='false', type='bool'),
state=dict(default='present', choices=['present', 'absent'])
)
)
module = AnsibleModule(argument_spec,
supports_check_mode=True)
if not HAS_PURITY_FB:
module.fail_json(msg='purity_fb sdk is required for this module')
if module.params['suffix'] is None:
suffix = "snap-" + str((datetime.utcnow() - datetime(1970, 1, 1, 0, 0, 0, 0)).total_seconds())
module.params['suffix'] = suffix.replace(".", "")
state = module.params['state']
blade = get_blade(module)
fs = get_fs(module, blade)
snap = get_fssnapshot(module, blade)
if state == 'present' and fs and not fs.destroyed and not snap:
create_snapshot(module, blade)
elif state == 'present' and fs and not fs.destroyed and snap and not snap.destroyed:
update_snapshot(module, blade)
elif state == 'present' and fs and not fs.destroyed and snap and snap.destroyed:
recover_snapshot(module, blade)
elif state == 'present' and fs and fs.destroyed:
update_snapshot(module, blade)
elif state == 'present' and not fs:
update_snapshot(module, blade)
elif state == 'absent' and snap and not snap.destroyed:
delete_snapshot(module, blade)
elif state == 'absent' and snap and snap.destroyed:
eradicate_snapshot(module, blade)
elif state == 'absent' and not snap:
module.exit_json(changed=False)
if __name__ == '__main__':
main()

View file

@ -1,264 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# (c) 2017, Simon Dodsley (simon@purestorage.com)
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: purefb_subnet
version_added: "2.8"
short_description: Manage network subnets in a Pure Storage FlashBlade
description:
- This module manages network subnets on Pure Storage FlashBlade.
author: Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
options:
name:
description:
- Subnet Name.
required: true
type: str
state:
description:
- Create, delete or modifies a subnet.
required: false
default: present
choices: [ "present", "absent" ]
type: str
gateway:
description:
- IPv4 or IPv6 address of subnet gateway.
required: false
type: str
mtu:
description:
- MTU size of the subnet. Range is 1280 to 9216.
required: false
default: 1500
type: int
prefix:
description:
- IPv4 or IPv6 address associated with the subnet.
- Supply the prefix length (CIDR) as well as the IP address.
required: false
type: str
vlan:
description:
- VLAN ID of the subnet.
required: false
default: 0
type: int
extends_documentation_fragment:
- purestorage.fb
notes:
- Requires the netaddr Python package on the host.
requirements:
- netaddr
'''
EXAMPLES = '''
- name: Create new network subnet named foo
purefb_subnet:
name: foo
prefix: "10.21.200.3/24"
gateway: 10.21.200.1
mtu: 9000
vlan: 2200
state: present
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
- name: Change configuration of existing subnet foo
purefb_network:
name: foo
state: present
prefix: "10.21.100.3/24"
gateway: 10.21.100.1
mtu: 1500
address: 10.21.200.123
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641
- name: Delete network subnet named foo
purefb_subnet:
name: foo
state: absent
fb_url: 10.10.10.2
api_token: T-55a68eb5-c785-4720-a2ca-8b03903bf641'''
RETURN = '''
'''
HAS_PURITY_FB = True
try:
from purity_fb import Subnet
except ImportError:
HAS_PURITY_FB = False
try:
import netaddr
HAS_NETADDR = True
except ImportError:
HAS_NETADDR = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pure import get_blade, purefb_argument_spec
MINIMUM_API_VERSION = '1.3'
def get_subnet(module, blade):
"""Return Subnet or None"""
subnet = []
subnet.append(module.params['name'])
try:
res = blade.subnets.list_subnets(names=subnet)
return res.items[0]
except Exception:
return None
def create_subnet(module, blade):
"""Create Subnet"""
subnet = []
subnet.append(module.params['name'])
try:
blade.subnets.create_subnets(names=subnet,
subnet=Subnet(prefix=module.params['prefix'],
vlan=module.params['vlan'],
mtu=module.params['mtu'],
gateway=module.params['gateway']
)
)
changed = True
except Exception:
module.fail_json(msg='Failed to create subnet {0}. Confirm supplied parameters'.format(module.params['name']))
module.exit_json(changed=changed)
def modify_subnet(module, blade):
"""Modify Subnet settings"""
changed = False
subnet = get_subnet(module, blade)
subnet_new = []
subnet_new.append(module.params['name'])
if module.params['prefix']:
if module.params['prefix'] != subnet.prefix:
try:
blade.subnets.update_subnets(names=subnet_new,
subnet=Subnet(prefix=module.params['prefix']))
changed = True
except Exception:
module.fail_json(msg='Failed to change subnet {0} prefix to {1}'.format(module.params['name'],
module.params['prefix']))
if module.params['vlan']:
if module.params['vlan'] != subnet.vlan:
try:
blade.subnets.update_subnets(names=subnet_new,
subnet=Subnet(vlan=module.params['vlan']))
changed = True
except Exception:
module.fail_json(msg='Failed to change subnet {0} VLAN to {1}'.format(module.params['name'],
module.params['vlan']))
if module.params['gateway']:
if module.params['gateway'] != subnet.gateway:
try:
blade.subnets.update_subnets(names=subnet_new,
subnet=Subnet(gateway=module.params['gateway']))
changed = True
except Exception:
module.fail_json(msg='Failed to change subnet {0} gateway to {1}'.format(module.params['name'],
module.params['gateway']))
if module.params['mtu']:
if module.params['mtu'] != subnet.mtu:
try:
blade.subnets.update_subnets(names=subnet_new,
subnet=Subnet(mtu=module.params['mtu']))
changed = True
except Exception:
module.fail_json(msg='Failed to change subnet {0} MTU to {1}'.format(module.params['name'],
module.params['mtu']))
module.exit_json(changed=changed)
def delete_subnet(module, blade):
""" Delete Subnet"""
subnet = []
subnet.append(module.params['name'])
try:
blade.subnets.delete_subnets(names=subnet)
changed = True
except Exception:
changed = False
module.exit_json(changed=changed)
def main():
argument_spec = purefb_argument_spec()
argument_spec.update(
dict(
name=dict(required=True),
state=dict(default='present', choices=['present', 'absent']),
gateway=dict(),
mtu=dict(type='int', default=1500),
prefix=dict(),
vlan=dict(type='int', default=0),
)
)
required_if = [["state", "present", ["gateway", 'prefix']]]
module = AnsibleModule(argument_spec,
required_if=required_if,
supports_check_mode=False)
if not HAS_PURITY_FB:
module.fail_json(msg='purity_fb sdk is required for this module')
if not HAS_NETADDR:
module.fail_json(msg='netaddr module is required')
state = module.params['state']
blade = get_blade(module)
api_version = blade.api_version.list_versions().versions
if MINIMUM_API_VERSION not in api_version:
module.fail_json(msg='Upgrade Purity//FB to enable this module')
subnet = get_subnet(module, blade)
if state == 'present':
if not (1280 <= module.params['mtu'] <= 9216):
module.fail_json(msg='MTU {0} is out of range (1280 to 9216)'.format(module.params['mtu']))
if not (0 <= module.params['vlan'] <= 4094):
module.fail_json(msg='VLAN ID {0} is out of range (0 to 4094)'.format(module.params['vlan']))
if netaddr.IPAddress(module.params['gateway']) not in netaddr.IPNetwork(module.params['prefix']):
module.fail_json(msg='Gateway and subnet are not compatible.')
subnets = blade.subnets.list_subnets()
nrange = netaddr.IPSet([module.params['prefix']])
for sub in range(0, len(subnets.items)):
if subnets.items[sub].vlan == module.params['vlan'] and subnets.items[sub].name != module.params['name']:
module.fail_json(msg='VLAN ID {0} is already in use.'.format(module.params['vlan']))
if nrange & netaddr.IPSet([subnets.items[sub].prefix]) and subnets.items[sub].name != module.params['name']:
module.fail_json(msg='Prefix CIDR overlaps with existing subnet.')
if state == 'present' and not subnet:
create_subnet(module, blade)
elif state == 'present' and subnet:
modify_subnet(module, blade)
elif state == 'absent' and subnet:
delete_subnet(module, blade)
elif state == 'absent' and not subnet:
module.exit_json(changed=False)
if __name__ == '__main__':
main()

View file

@ -993,14 +993,6 @@ lib/ansible/modules/source_control/git.py validate-modules:parameter-type-not-in
lib/ansible/modules/source_control/subversion.py validate-modules:doc-required-mismatch
lib/ansible/modules/source_control/subversion.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/source_control/subversion.py validate-modules:undocumented-parameter
lib/ansible/modules/storage/purestorage/purefb_ds.py validate-modules:doc-required-mismatch
lib/ansible/modules/storage/purestorage/purefb_ds.py validate-modules:parameter-list-no-elements
lib/ansible/modules/storage/purestorage/purefb_dsrole.py validate-modules:doc-required-mismatch
lib/ansible/modules/storage/purestorage/purefb_fs.py validate-modules:doc-default-does-not-match-spec
lib/ansible/modules/storage/purestorage/purefb_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/storage/purestorage/purefb_info.py validate-modules:return-syntax-error
lib/ansible/modules/storage/purestorage/purefb_s3acc.py validate-modules:doc-required-mismatch
lib/ansible/modules/storage/purestorage/purefb_s3user.py validate-modules:doc-required-mismatch
lib/ansible/modules/system/getent.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/system/hostname.py validate-modules:invalid-ansiblemodule-schema
lib/ansible/modules/system/hostname.py validate-modules:parameter-type-not-in-doc