fifth set of modules (#40491)

* fifth set of modules

* fix issues

* Fixes

* fix choices

* fix snapshot

* spelling

* review fixes'
pull/33986/merge
Chris Archibald 6 years ago committed by Matt Davis
parent 3bae9ed00c
commit 7d551bba21

@ -0,0 +1,374 @@
#!/usr/bin/python
# (c) 2018, NetApp, Inc
# 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: na_ontap_nfs
short_description: Manage Ontap NFS status
extends_documentation_fragment:
- netapp.na_ontap
version_added: '2.6'
author: Suhas Bangalore Shekar (bsuhas@netapp.com)
description:
- Enable or disable nfs on ONTAP
options:
state:
description:
- Whether nfs should exist or not.
choices: ['present', 'absent']
default: present
service_state:
description:
- Whether the specified nfs should be enabled or disabled. Creates nfs service if doesnt exist.
choices: ['started', 'stopped']
vserver:
description:
- Name of the vserver to use.
required: true
nfsv3:
description:
- status of nfsv3.
choices: ['enabled', 'disabled']
nfsv4:
description:
- status of nfsv4.
choices: ['enabled', 'disabled']
nfsv41:
description:
- status of nfsv41.
aliases: ['nfsv4.1']
choices: ['enabled', 'disabled']
vstorage_state:
description:
- status of vstorage_state.
choices: ['enabled', 'disabled']
nfsv4_id_domain:
description:
- Name of the nfsv4_id_domain to use.
tcp:
description:
- Enable TCP.
choices: ['enabled', 'disabled']
udp:
description:
- Enable UDP.
choices: ['enabled', 'disabled']
"""
EXAMPLES = """
- name: change nfs status
na_ontap_nfs:
state: present
service_state: stopped
vserver: vs_hack
nfsv3: disabled
nfsv4: disabled
nfsv41: enabled
tcp: disabled
udp: disabled
vstorage_state: disabled
nfsv4_id_domain: example.com
hostname: "{{ netapp_hostname }}"
username: "{{ netapp_username }}"
password: "{{ netapp_password }}"
"""
RETURN = """
"""
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
import ansible.module_utils.netapp as netapp_utils
HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
class NetAppONTAPNFS(object):
""" object initialize and class methods """
def __init__(self):
self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
self.argument_spec.update(dict(
state=dict(required=False, type='str', choices=['present', 'absent'], default='present'),
service_state=dict(required=False, choices=['started', 'stopped']),
vserver=dict(required=True, type='str'),
nfsv3=dict(required=False, default=None, choices=['enabled', 'disabled']),
nfsv4=dict(required=False, default=None, choices=['enabled', 'disabled']),
nfsv41=dict(required=False, default=None, choices=['enabled', 'disabled'], aliases=['nfsv4.1']),
vstorage_state=dict(required=False, default=None, choices=['enabled', 'disabled']),
tcp=dict(required=False, default=None, choices=['enabled', 'disabled']),
udp=dict(required=False, default=None, choices=['enabled', 'disabled']),
nfsv4_id_domain=dict(required=False, type='str', default=None),
))
self.module = AnsibleModule(
argument_spec=self.argument_spec,
supports_check_mode=True
)
parameters = self.module.params
# set up service_state variables
self.state = parameters['state']
self.service_state = parameters['service_state']
self.vserver = parameters['vserver']
self.nfsv3 = parameters['nfsv3']
self.nfsv4 = parameters['nfsv4']
self.nfsv41 = parameters['nfsv41']
self.vstorage_state = parameters['vstorage_state']
self.nfsv4_id_domain = parameters['nfsv4_id_domain']
self.udp = parameters['udp']
self.tcp = parameters['tcp']
if HAS_NETAPP_LIB is False:
self.module.fail_json(msg="the python NetApp-Lib module is required")
else:
self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.vserver)
def get_nfs_service(self):
"""
Return details about nfs
:param:
name : name of the vserver
:return: Details about nfs. None if not found.
:rtype: dict
"""
nfs_get_iter = netapp_utils.zapi.NaElement('nfs-service-get-iter')
nfs_info = netapp_utils.zapi.NaElement('nfs-info')
nfs_info.add_new_child('vserver', self.vserver)
query = netapp_utils.zapi.NaElement('query')
query.add_child_elem(nfs_info)
nfs_get_iter.add_child_elem(query)
result = self.server.invoke_successfully(nfs_get_iter, True)
nfs_details = None
# check if job exists
if result.get_child_by_name('num-records') and \
int(result.get_child_content('num-records')) >= 1:
attributes_list = result.get_child_by_name('attributes-list').get_child_by_name('nfs-info')
is_nfsv3_enabled = attributes_list.get_child_content('is-nfsv3-enabled')
is_nfsv40_enabled = attributes_list.get_child_content('is-nfsv40-enabled')
is_nfsv41_enabled = attributes_list.get_child_content('is-nfsv41-enabled')
is_vstorage_enabled = attributes_list.get_child_content('is-vstorage-enabled')
nfsv4_id_domain_value = attributes_list.get_child_content('nfsv4-id-domain')
is_tcp_enabled = attributes_list.get_child_content('is-tcp-enabled')
is_udp_enabled = attributes_list.get_child_content('is-udp-enabled')
nfs_details = {
'is_nfsv3_enabled': is_nfsv3_enabled,
'is_nfsv40_enabled': is_nfsv40_enabled,
'is_nfsv41_enabled': is_nfsv41_enabled,
'is_vstorage_enabled': is_vstorage_enabled,
'nfsv4_id_domain': nfsv4_id_domain_value,
'is_tcp_enabled': is_tcp_enabled,
'is_udp_enabled': is_udp_enabled
}
return nfs_details
def get_nfs_status(self):
"""
Return status of nfs
:param:
name : Name of the vserver
:return: status of nfs. None if not found.
:rtype: boolean
"""
nfs_status = netapp_utils.zapi.NaElement('nfs-status')
result = self.server.invoke_successfully(nfs_status, True)
return_value = result.get_child_content('is-enabled')
return return_value
def enable_nfs(self):
"""
enable nfs (online). If the NFS service was not explicitly created,
this API will create one with default options.
"""
nfs_enable = netapp_utils.zapi.NaElement.create_node_with_children('nfs-enable')
try:
self.server.invoke_successfully(nfs_enable,
enable_tunneling=True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error changing the service_state of nfs %s to %s: %s' %
(self.vserver, self.service_state, to_native(error)),
exception=traceback.format_exc())
def disable_nfs(self):
"""
disable nfs (offline).
"""
nfs_disable = netapp_utils.zapi.NaElement.create_node_with_children('nfs-disable')
try:
self.server.invoke_successfully(nfs_disable,
enable_tunneling=True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error changing the service_state of nfs %s to %s: %s' %
(self.vserver, self.service_state, to_native(error)),
exception=traceback.format_exc())
def modify_nfs(self):
"""
modify nfs service
"""
nfs_modify = netapp_utils.zapi.NaElement('nfs-service-modify')
if self.nfsv3 == 'enabled':
nfs_modify.add_new_child('is-nfsv3-enabled', 'true')
elif self.nfsv3 == 'disabled':
nfs_modify.add_new_child('is-nfsv3-enabled', 'false')
if self.nfsv4 == 'enabled':
nfs_modify.add_new_child('is-nfsv40-enabled', 'true')
elif self.nfsv4 == 'disabled':
nfs_modify.add_new_child('is-nfsv40-enabled', 'false')
if self.nfsv41 == 'enabled':
nfs_modify.add_new_child('is-nfsv41-enabled', 'true')
elif self.nfsv41 == 'disabled':
nfs_modify.add_new_child('is-nfsv41-enabled', 'false')
if self.vstorage_state == 'enabled':
nfs_modify.add_new_child('is-vstorage-enabled', 'true')
elif self.vstorage_state == 'disabled':
nfs_modify.add_new_child('is-vstorage-enabled', 'false')
if self.tcp == 'enabled':
nfs_modify.add_new_child('is-tcp-enabled', 'true')
elif self.tcp == 'disabled':
nfs_modify.add_new_child('is-tcp-enabled', 'false')
if self.udp == 'enabled':
nfs_modify.add_new_child('is-udp-enabled', 'true')
elif self.udp == 'disabled':
nfs_modify.add_new_child('is-udp-enabled', 'false')
try:
self.server.invoke_successfully(nfs_modify,
enable_tunneling=True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error modifying nfs: %s'
% (to_native(error)),
exception=traceback.format_exc())
def modify_nfsv4_id_domain(self):
"""
modify nfs service
"""
nfsv4_id_domain_modify = netapp_utils.zapi.NaElement.create_node_with_children(
'nfs-service-modify', **{'nfsv4-id-domain': self.nfsv4_id_domain})
if nfsv4_id_domain_modify is not None:
try:
self.server.invoke_successfully(nfsv4_id_domain_modify,
enable_tunneling=True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error modifying nfs: %s'
% (to_native(error)),
exception=traceback.format_exc())
def delete_nfs(self):
"""
delete nfs service.
"""
nfs_delete = netapp_utils.zapi.NaElement.create_node_with_children('nfs-service-destroy')
try:
self.server.invoke_successfully(nfs_delete,
enable_tunneling=True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error deleting nfs: %s' %
(to_native(error)),
exception=traceback.format_exc())
def apply(self):
"""Apply action to nfs"""
changed = False
nfs_exists = False
modify_nfs = False
enable_nfs = False
disable_nfs = False
netapp_utils.ems_log_event("na_ontap_nfs", self.server)
nfs_enabled = self.get_nfs_status()
nfs_service_details = self.get_nfs_service()
is_nfsv4_id_domain_changed = False
def state_changed(expected, current):
if expected == "enabled" and current == "true":
return False
if expected == "disabled" and current == "false":
return False
return True
def is_modify_needed():
if (((self.nfsv3 is not None) and state_changed(self.nfsv3, nfs_service_details['is_nfsv3_enabled'])) or
((self.nfsv4 is not None) and state_changed(self.nfsv4, nfs_service_details['is_nfsv40_enabled'])) or
((self.nfsv41 is not None) and state_changed(self.nfsv41, nfs_service_details['is_nfsv41_enabled'])) or
((self.tcp is not None) and state_changed(self.tcp, nfs_service_details['is_tcp_enabled'])) or
((self.udp is not None) and state_changed(self.udp, nfs_service_details['is_udp_enabled'])) or
((self.vstorage_state is not None) and state_changed(self.vstorage_state, nfs_service_details['is_vstorage_enabled']))):
return True
return False
def is_domain_changed():
if (self.nfsv4_id_domain is not None) and (self.nfsv4_id_domain != nfs_service_details['nfsv4_id_domain']):
return True
return False
if nfs_service_details:
nfs_exists = True
if self.state == 'absent': # delete
changed = True
elif self.state == 'present': # modify
if self.service_state == 'started' and nfs_enabled == 'false':
enable_nfs = True
changed = True
elif self.service_state == 'stopped' and nfs_enabled == 'true':
disable_nfs = True
changed = True
if is_modify_needed():
modify_nfs = True
changed = True
if is_domain_changed():
is_nfsv4_id_domain_changed = True
changed = True
else:
if self.state == 'present': # create
changed = True
if changed:
if self.module.check_mode:
pass
else:
if self.state == 'present': # execute create
if not nfs_exists:
self.enable_nfs()
nfs_service_details = self.get_nfs_service()
if self.service_state == 'stopped':
self.disable_nfs()
if is_modify_needed():
self.modify_nfs()
if is_domain_changed():
self.modify_nfsv4_id_domain()
else:
if enable_nfs:
self.enable_nfs()
elif disable_nfs:
self.disable_nfs()
if modify_nfs:
self.modify_nfs()
if is_nfsv4_id_domain_changed:
self.modify_nfsv4_id_domain()
elif self.state == 'absent': # execute delete
self.delete_nfs()
self.module.exit_json(changed=changed)
def main():
""" Create object and call apply """
obj = NetAppONTAPNFS()
obj.apply()
if __name__ == '__main__':
main()

@ -0,0 +1,224 @@
#!/usr/bin/python
# (c) 2018, NetApp, Inc
# 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: na_ontap_ntp
short_description: Create/Delete/modify_version ONTAP NTP server
extends_documentation_fragment:
- netapp.na_ontap
version_added: '2.6'
author: Suhas Bangalore Shekar (bsuhas@netapp.com), Archana Ganesan (garchana@netapp.com)
description:
- Create or delete or modify ntp server in ONTAP
options:
state:
description:
- Whether the specified ntp server should exist or not.
choices: ['present', 'absent']
default: 'present'
server_name:
description:
- The name of the ntp server to manage.
required: True
version:
description:
- give version for ntp server
choices: ['auto', '3', '4']
default: 'auto'
"""
EXAMPLES = """
- name: Create NTP server
na_ontap_ntp:
state: present
version: auto
hostname: "{{ netapp_hostname }}"
username: "{{ netapp_username }}"
password: "{{ netapp_password }}"
- name: Delete NTP server
na_ontap_ntp:
state: absent
hostname: "{{ netapp_hostname }}"
username: "{{ netapp_username }}"
password: "{{ netapp_password }}"
"""
RETURN = """
"""
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
import ansible.module_utils.netapp as netapp_utils
HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
class NetAppOntapNTPServer(object):
""" object initialize and class methods """
def __init__(self):
self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
self.argument_spec.update(dict(
state=dict(required=False, choices=[
'present', 'absent'], default='present'),
server_name=dict(required=True, type='str'),
version=dict(required=False, type='str', default='auto',
choices=['auto', '3', '4']),
))
self.module = AnsibleModule(
argument_spec=self.argument_spec,
supports_check_mode=True
)
parameters = self.module.params
# set up state variables
self.state = parameters['state']
self.server_name = parameters['server_name']
self.version = parameters['version']
if HAS_NETAPP_LIB is False:
self.module.fail_json(
msg="the python NetApp-Lib module is required")
else:
self.server = netapp_utils.setup_na_ontap_zapi(module=self.module)
def get_ntp_server(self):
"""
Return details about the ntp server
:param:
name : Name of the server_name
:return: Details about the ntp server. None if not found.
:rtype: dict
"""
ntp_iter = netapp_utils.zapi.NaElement('ntp-server-get-iter')
ntp_info = netapp_utils.zapi.NaElement('ntp-server-info')
ntp_info.add_new_child('server-name', self.server_name)
query = netapp_utils.zapi.NaElement('query')
query.add_child_elem(ntp_info)
ntp_iter.add_child_elem(query)
result = self.server.invoke_successfully(ntp_iter, True)
return_value = None
if result.get_child_by_name('num-records') and \
int(result.get_child_content('num-records')) == 1:
ntp_server_name = result.get_child_by_name('attributes-list').\
get_child_by_name('ntp-server-info').\
get_child_content('server-name')
server_version = result.get_child_by_name('attributes-list').\
get_child_by_name('ntp-server-info').\
get_child_content('version')
return_value = {
'server-name': ntp_server_name,
'version': server_version
}
return return_value
def create_ntp_server(self):
"""
create ntp server.
"""
ntp_server_create = netapp_utils.zapi.NaElement.create_node_with_children(
'ntp-server-create', **{'server-name': self.server_name,
'version': self.version
})
try:
self.server.invoke_successfully(ntp_server_create,
enable_tunneling=True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error creating ntp server %s: %s'
% (self.server_name, to_native(error)),
exception=traceback.format_exc())
def delete_ntp_server(self):
"""
delete ntp server.
"""
ntp_server_delete = netapp_utils.zapi.NaElement.create_node_with_children(
'ntp-server-delete', **{'server-name': self.server_name})
try:
self.server.invoke_successfully(ntp_server_delete,
enable_tunneling=True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error deleting ntp server %s: %s'
% (self.server_name, to_native(error)),
exception=traceback.format_exc())
def modify_version(self):
"""
modify the version.
"""
ntp_modify_versoin = netapp_utils.zapi.NaElement.create_node_with_children(
'ntp-server-modify',
**{'server-name': self.server_name, 'version': self.version})
try:
self.server.invoke_successfully(ntp_modify_versoin,
enable_tunneling=True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error modifying version for ntp server %s: %s'
% (self.server_name, to_native(error)),
exception=traceback.format_exc())
def apply(self):
"""Apply action to ntp-server"""
changed = False
ntp_modify = False
results = netapp_utils.get_cserver(self.server)
cserver = netapp_utils.setup_na_ontap_zapi(
module=self.module, vserver=results)
netapp_utils.ems_log_event("na_ontap_ntp", cserver)
ntp_server_details = self.get_ntp_server()
if ntp_server_details is not None:
if self.state == 'absent': # delete
changed = True
elif self.state == 'present' and self.version:
# modify version
if self.version != ntp_server_details['version']:
ntp_modify = True
changed = True
else:
if self.state == 'present': # create
changed = True
if changed:
if self.module.check_mode:
pass
else:
if self.state == 'present':
if ntp_server_details is None:
self.create_ntp_server()
elif ntp_modify:
self.modify_version()
elif self.state == 'absent':
self.delete_ntp_server()
self.module.exit_json(changed=changed)
def main():
""" Create object and call apply """
ntp_obj = NetAppOntapNTPServer()
ntp_obj.apply()
if __name__ == '__main__':
main()

@ -0,0 +1,233 @@
#!/usr/bin/python
# (c) 2018, NetApp, Inc
# 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: na_ontap_qtree
short_description: Manage qtrees
extends_documentation_fragment:
- netapp.na_ontap
version_added: '2.6'
author: Sumit Kumar (sumit4@netapp.com)
description:
- Create or destroy Qtrees.
options:
state:
description:
- Whether the specified Qtree should exist or not.
choices: ['present', 'absent']
default: 'present'
name:
description:
- The name of the Qtree to manage.
required: true
new_name:
description:
- New name of the Qtree to be renamed.
flexvol_name:
description:
- The name of the FlexVol the Qtree should exist on. Required when C(state=present).
vserver:
description:
- The name of the vserver to use.
required: true
'''
EXAMPLES = """
- name: Create QTree
na_ontap_qtree:
state: present
name: ansibleQTree
flexvol_name: ansibleVolume
vserver: ansibleVServer
hostname: "{{ netapp_hostname }}"
username: "{{ netapp_username }}"
password: "{{ netapp_password }}"
- name: Rename QTree
na_ontap_qtree:
state: present
name: ansibleQTree
flexvol_name: ansibleVolume
vserver: ansibleVServer
hostname: "{{ netapp_hostname }}"
username: "{{ netapp_username }}"
password: "{{ netapp_password }}"
"""
RETURN = """
"""
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
import ansible.module_utils.netapp as netapp_utils
HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
class NetAppOntapQTree(object):
def __init__(self):
self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
self.argument_spec.update(dict(
state=dict(required=False, choices=[
'present', 'absent'], default='present'),
name=dict(required=True, type='str'),
new_name=dict(required=False, type='str'),
flexvol_name=dict(type='str'),
vserver=dict(required=True, type='str'),
))
self.module = AnsibleModule(
argument_spec=self.argument_spec,
required_if=[
('state', 'present', ['flexvol_name'])
],
supports_check_mode=True
)
p = self.module.params
# set up state variables
self.state = p['state']
self.name = p['name']
self.new_name = p['new_name']
self.flexvol_name = p['flexvol_name']
self.vserver = p['vserver']
if HAS_NETAPP_LIB is False:
self.module.fail_json(
msg="the python NetApp-Lib module is required")
else:
self.server = netapp_utils.setup_na_ontap_zapi(
module=self.module, vserver=self.vserver)
def get_qtree(self):
"""
Checks if the qtree exists.
:return:
True if qtree found
False if qtree is not found
:rtype: bool
"""
qtree_list_iter = netapp_utils.zapi.NaElement('qtree-list-iter')
query_details = netapp_utils.zapi.NaElement.create_node_with_children(
'qtree-info', **{'vserver': self.vserver,
'volume': self.flexvol_name,
'qtree': self.name})
query = netapp_utils.zapi.NaElement('query')
query.add_child_elem(query_details)
qtree_list_iter.add_child_elem(query)
result = self.server.invoke_successfully(qtree_list_iter,
enable_tunneling=True)
if (result.get_child_by_name('num-records') and
int(result.get_child_content('num-records')) >= 1):
return True
else:
return False
def create_qtree(self):
qtree_create = netapp_utils.zapi.NaElement.create_node_with_children(
'qtree-create', **{'volume': self.flexvol_name,
'qtree': self.name})
try:
self.server.invoke_successfully(qtree_create,
enable_tunneling=True)
except netapp_utils.zapi.NaApiError as e:
self.module.fail_json(msg="Error provisioning qtree %s: %s" % (self.name, to_native(e)),
exception=traceback.format_exc())
def delete_qtree(self):
path = '/vol/%s/%s' % (self.flexvol_name, self.name)
qtree_delete = netapp_utils.zapi.NaElement.create_node_with_children(
'qtree-delete', **{'qtree': path})
try:
self.server.invoke_successfully(qtree_delete,
enable_tunneling=True)
except netapp_utils.zapi.NaApiError as e:
self.module.fail_json(msg="Error deleting qtree %s: %s" % (path, to_native(e)),
exception=traceback.format_exc())
def rename_qtree(self):
path = '/vol/%s/%s' % (self.flexvol_name, self.name)
new_path = '/vol/%s/%s' % (self.flexvol_name, self.new_name)
qtree_rename = netapp_utils.zapi.NaElement.create_node_with_children(
'qtree-rename', **{'qtree': path,
'new-qtree-name': new_path})
try:
self.server.invoke_successfully(qtree_rename,
enable_tunneling=True)
except netapp_utils.zapi.NaApiError as e:
self.module.fail_json(msg="Error renaming qtree %s: %s" % (self.name, to_native(e)),
exception=traceback.format_exc())
def apply(self):
changed = False
qtree_exists = False
rename_qtree = False
netapp_utils.ems_log_event("na_ontap_qtree", self.server)
qtree_detail = self.get_qtree()
if qtree_detail:
qtree_exists = True
if self.state == 'absent': # delete
changed = True
else: # rename
if self.new_name and self.name != self.new_name:
changed = True
rename_qtree = True
else:
if self.state == 'present': # create
changed = True
if changed:
if self.module.check_mode:
pass
else:
if self.state == 'present':
if not qtree_exists:
self.create_qtree()
elif rename_qtree:
self.rename_qtree()
elif self.state == 'absent':
self.delete_qtree()
self.module.exit_json(changed=changed)
def main():
v = NetAppOntapQTree()
v.apply()
if __name__ == '__main__':
main()

@ -0,0 +1,264 @@
#!/usr/bin/python
# (c) 2018, NetApp, Inc
# 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: na_ontap_service_processor_network
short_description: Manage NetApp Ontap service processor network
extends_documentation_fragment:
- netapp.na_ontap
version_added: '2.6'
author:
- Chris Archibald (carchi@netapp.com), Kevin Hutton (khutton@netapp.com)
description:
- Modify a Ontap service processor network
options:
state:
description:
- Whether the specified service processor network should exist or not.
choices: ['present']
default: present
address_type:
description:
- Specify address class.
required: true
choices: ['ipv4', 'ipv6']
is_enabled:
description:
- Specify whether to enable or disable the service processor network.
required: true
choices: ['true', 'false']
node:
description:
- The node where the the service processor network should be enabled
required: true
dhcp:
description:
- Specify dhcp type.
choices: ['v4', 'none']
gateway_ip_address:
description:
- Specify the gateway ip.
ip_address:
description:
- Specify the service processor ip address.
netmask:
description:
- Specify the service processor netmask.
prefix_length:
description:
- Specify the service processor prefix_length.
'''
EXAMPLES = """
- name: Modify Service Processor Network
na_ontap_service_processor_network:
state=present
address_type=ipv4
is_enabled=true
dhcp=v4
node=FPaaS-A300-01
node={{ netapp_node }}
username={{ netapp_username }}
password={{ netapp_password }}
hostname={{ netapp_hostname }}
"""
RETURN = """
"""
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
import ansible.module_utils.netapp as netapp_utils
HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
class NetAppOntapServiceProcessorNetwork(object):
"""
Modify a Service Processor Network
"""
def __init__(self):
"""
Initialize the NetAppOntapServiceProcessorNetwork class
"""
self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
self.argument_spec.update(dict(
state=dict(required=False, choices=['present'], default='present'),
address_type=dict(required=True, choices=['ipv4', 'ipv6']),
is_enabled=dict(required=True, choices=['true', 'false']),
node=dict(required=True, type='str'),
dhcp=dict(required=False, choices=['v4', 'none']),
gateway_ip_address=dict(required=False, type='str'),
ip_address=dict(required=False, type='str'),
netmask=dict(required=False, type='str'),
prefix_length=dict(required=False, type='int'),
))
self.module = AnsibleModule(
argument_spec=self.argument_spec,
supports_check_mode=True
)
parameters = self.module.params
# set up state variables
self.state = parameters['state']
self.address_type = parameters['address_type']
self.dhcp = parameters['dhcp']
self.gateway_ip_address = parameters['gateway_ip_address']
self.ip_address = parameters['ip_address']
self.is_enabled = parameters['is_enabled']
self.netmask = parameters['netmask']
self.node = parameters['node']
self.prefix_length = parameters['prefix_length']
if HAS_NETAPP_LIB is False:
self.module.fail_json(
msg="the python NetApp-Lib module is required")
else:
self.server = netapp_utils.setup_na_ontap_zapi(
module=self.module, vserver=None)
return
def get_service_processor_network(self):
"""
Return details about service processor network
:param:
name : name of the vserver
:return: Details about service processor network. None if not found.
:rtype: dict
"""
spn_get_iter = netapp_utils.zapi.NaElement(
'service-processor-network-get-iter')
spn_info = netapp_utils.zapi.NaElement(
'service-processor-network-info')
spn_info.add_new_child('node', self.node)
spn_info.add_new_child('address-type', self.address_type)
spn_info.add_new_child('is-enabled', self.is_enabled)
query = netapp_utils.zapi.NaElement('query')
query.add_child_elem(spn_info)
spn_get_iter.add_child_elem(query)
result = self.server.invoke_successfully(spn_get_iter, True)
sp_network_details = None
# check if job exists
if result.get_child_by_name('num-records') and \
int(result.get_child_content('num-records')) >= 1:
attributes_list = result.get_child_by_name('attributes-list').\
get_child_by_name('service-processor-network-info')
node_value = attributes_list.get_child_content('node')
address_type_value = attributes_list.get_child_content(
'address-type')
dhcp_value = attributes_list.get_child_content('dhcp')
gateway_ip_address_value = attributes_list.get_child_content(
'gateway-ip-address')
ip_address_value = attributes_list.get_child_content('ip-address')
is_enabled_value = attributes_list.get_child_content('is-enabled')
netmask_value = attributes_list.get_child_content('netmask')
prefix_length_value = attributes_list.get_child_content(
'prefix-length')
sp_network_details = {
'node_value': node_value,
'address_type_value': address_type_value,
'dhcp_value': dhcp_value,
'gateway_ip_address_value': gateway_ip_address_value,
'ip_address_value': ip_address_value,
'is_enabled_value': is_enabled_value,
'netmask_value': netmask_value,
'prefix_length_value': prefix_length_value
}
return sp_network_details
def modify_service_processor_network(self):
"""
Modify a service processor network
"""
service_obj = netapp_utils.zapi.NaElement(
'service-processor-network-modify')
service_obj.add_new_child("node", self.node)
service_obj.add_new_child("address-type", self.address_type)
service_obj.add_new_child("is-enabled", self.is_enabled)
if self.dhcp:
service_obj.add_new_child("dhcp", self.dhcp)
if self.gateway_ip_address:
service_obj.add_new_child(
"gateway-ip-address", self.gateway_ip_address)
if self.ip_address:
service_obj.add_new_child("ip-address", self.ip_address)
if self.netmask:
service_obj.add_new_child("netmask", self.netmask)
if self.prefix_length is not None:
service_obj.add_new_child("prefix-length", str(self.prefix_length))
try:
result = self.server.invoke_successfully(service_obj,
enable_tunneling=True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error modifying \
service processor network: %s'
% (to_native(error)),
exception=traceback.format_exc())
def apply(self):
"""
Run Module based on play book
"""
changed = False
results = netapp_utils.get_cserver(self.server)
cserver = netapp_utils.setup_ontap_zapi(
module=self.module, vserver=results)
netapp_utils.ems_log_event(
"na_ontap_service_processor_network", cserver)
spn_details = self.get_service_processor_network()
spn_exists = False
if spn_details:
spn_exists = True
if self.state == 'present': # modify
if (self.dhcp and
self.dhcp != spn_details['dhcp_value']) or \
(self.gateway_ip_address and
self.gateway_ip_address != spn_details['gateway_ip_address_value']) or \
(self.ip_address and
self.ip_address != spn_details['ip_address_value']) or \
(self.netmask and
self.netmask != spn_details['netmask_value']) or \
(self.prefix_length and str(self.prefix_length)
!= spn_details['prefix_length_value']):
changed = True
else:
pass
if changed:
if self.module.check_mode:
pass
else:
if self.state == 'present': # execute modify
if spn_exists:
self.modify_service_processor_network()
self.module.exit_json(changed=changed)
def main():
"""
Create the NetApp Ontap Service Processor Network Object and modify it
"""
obj = NetAppOntapServiceProcessorNetwork()
obj.apply()
if __name__ == '__main__':
main()

@ -0,0 +1,319 @@
#!/usr/bin/python
# (c) 2018, NetApp, Inc
# 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: na_ontap_snapshot
short_description: Manage NetApp Sanpshots
extends_documentation_fragment:
- netapp.na_ontap
version_added: '2.6'
author:
- Chris Archibald (carchi@netapp.com), Kevin Hutton (khutton@netapp.com)
description:
- Create/Modify/Delete Ontap snapshots
options:
state:
description:
- If you want to create/modify a snapshot, or delete it.
choices: ['present', 'absent']
default: present
snapshot:
description:
Name of the snapshot to be managed.
The maximum string length is 256 characters.
required: true
volume:
description:
- Name of the volume on which the snapshot is to be created.
required: true
async_bool:
description:
- If true, the snapshot is to be created asynchronously.
type: bool
comment:
description:
A human readable comment attached with the snapshot.
The size of the comment can be at most 255 characters.
snapmirror_label:
description:
A human readable SnapMirror Label attached with the snapshot.
Size of the label can be at most 31 characters.
ignore_owners:
description:
- if this field is true, snapshot will be deleted
even if some other processes are accessing it.
type: bool
snapshot_instance_uuid:
description:
- The 128 bit unique snapshot identifier expressed in the form of UUID.
vserver:
description:
- The Vserver name
new_comment:
description:
A human readable comment attached with the snapshot.
The size of the comment can be at most 255 characters.
This will replace the existing comment
'''
EXAMPLES = """
- name: create SnapShot
tags:
- create
na_ontap_snapshot:
state=present
snapshot={{ snapshot name }}
volume={{ vol name }}
comment="i am a comment"
vserver={{ vserver name }}
username={{ netapp username }}
password={{ netapp password }}
hostname={{ netapp hostname }}
- name: delete SnapShot
tags:
- delete
na_ontap_snapshot:
state=absent
snapshot={{ snapshot name }}
volume={{ vol name }}
vserver={{ vserver name }}
username={{ netapp username }}
password={{ netapp password }}
hostname={{ netapp hostname }}
- name: modify SnapShot
tags:
- modify
na_ontap_snapshot:
state=present
snapshot={{ snapshot name }}
new_comment="New comments are great"
volume={{ vol name }}
vserver={{ vserver name }}
username={{ netapp username }}
password={{ netapp password }}
hostname={{ netapp hostname }}
"""
RETURN = """
"""
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
import ansible.module_utils.netapp as netapp_utils
HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
class NetAppOntapSnapshot(object):
"""
Creates, modifies, and deletes a Snapshot
"""
def __init__(self):
self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
self.argument_spec.update(dict(
state=dict(required=False, choices=[
'present', 'absent'], default='present'),
snapshot=dict(required=True, type="str"),
volume=dict(required=True, type="str"),
async_bool=dict(required=False, type="bool", default=False),
comment=dict(required=False, type="str"),
snapmirror_label=dict(required=False, type="str"),
ignore_owners=dict(required=False, type="bool", default=False),
snapshot_instance_uuid=dict(required=False, type="str"),
vserver=dict(required=True, type="str"),
new_comment=dict(required=False, type="str"),
))
self.module = AnsibleModule(
argument_spec=self.argument_spec,
supports_check_mode=True
)
parameters = self.module.params
# set up state variables
# These are the required variables
self.state = parameters['state']
self.snapshot = parameters['snapshot']
self.vserver = parameters['vserver']
# these are the optional variables for creating a snapshot
self.volume = parameters['volume']
self.async_bool = parameters['async_bool']
self.comment = parameters['comment']
self.snapmirror_label = parameters['snapmirror_label']
# these are the optional variables for deleting a snapshot\
self.ignore_owners = parameters['ignore_owners']
self.snapshot_instance_uuid = parameters['snapshot_instance_uuid']
# These are the optional for Modify.
# You can NOT change a snapcenter name
self.new_comment = parameters['new_comment']
if HAS_NETAPP_LIB is False:
self.module.fail_json(
msg="the python NetApp-Lib module is required")
else:
self.server = netapp_utils.setup_na_ontap_zapi(
module=self.module, vserver=self.vserver)
return
def create_snapshot(self):
"""
Creates a new snapshot
"""
snapshot_obj = netapp_utils.zapi.NaElement("snapshot-create")
# set up required variables to create a snapshot
snapshot_obj.add_new_child("snapshot", self.snapshot)
snapshot_obj.add_new_child("volume", self.volume)
# Set up optional variables to create a snapshot
if self.async_bool:
snapshot_obj.add_new_child("async", self.async_bool)
if self.comment:
snapshot_obj.add_new_child("comment", self.comment)
if self.snapmirror_label:
snapshot_obj.add_new_child(
"snapmirror-label", self.snapmirror_label)
try:
self.server.invoke_successfully(snapshot_obj, True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error creating snapshot %s: %s' %
(self.snapshot, to_native(error)),
exception=traceback.format_exc())
def delete_snapshot(self):
"""
Deletes an existing snapshot
"""
snapshot_obj = netapp_utils.zapi.NaElement("snapshot-delete")
# Set up required variables to delete a snapshot
snapshot_obj.add_new_child("snapshot", self.snapshot)
snapshot_obj.add_new_child("volume", self.volume)
# set up optional variables to delete a snapshot
if self.ignore_owners:
snapshot_obj.add_new_child("ignore-owners", self.ignore_owners)
if self.snapshot_instance_uuid:
snapshot_obj.add_new_child(
"snapshot-instance-uuid", self.snapshot_instance_uuid)
try:
self.server.invoke_successfully(snapshot_obj, True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error deleting snapshot %s: %s' %
(self.snapshot, to_native(error)),
exception=traceback.format_exc())
def modify_snapshot(self):
"""
Modify an existing snapshot
:return:
"""
snapshot_obj = netapp_utils.zapi.NaElement("snapshot-modify-iter")
# Create query object, this is the existing object
query = netapp_utils.zapi.NaElement("query")
snapshot_info_obj = netapp_utils.zapi.NaElement("snapshot-info")
snapshot_info_obj.add_new_child("name", self.snapshot)
query.add_child_elem(snapshot_info_obj)
snapshot_obj.add_child_elem(query)
# this is what we want to modify in the snapshot object
attributes = netapp_utils.zapi.NaElement("attributes")
snapshot_info_obj = netapp_utils.zapi.NaElement("snapshot-info")
snapshot_info_obj.add_new_child("name", self.snapshot)
snapshot_info_obj.add_new_child("comment", self.new_comment)
attributes.add_child_elem(snapshot_info_obj)
snapshot_obj.add_child_elem(attributes)
try:
self.server.invoke_successfully(snapshot_obj, True)
except netapp_utils.zapi.NaApiError as error:
self.module.fail_json(msg='Error modifying snapshot %s: %s' %
(self.snapshot, to_native(error)),
exception=traceback.format_exc())
def does_snapshot_exist(self):
"""
Checks to see if a snapshot exists or not
:return: Return True if a snapshot exists, false if it dosn't
"""
snapshot_obj = netapp_utils.zapi.NaElement("snapshot-get-iter")
desired_attr = netapp_utils.zapi.NaElement("desired-attributes")
snapshot_info = netapp_utils.zapi.NaElement('snapshot-info')
comment = netapp_utils.zapi.NaElement('comment')
# add more desired attributes that are allowed to be modified
snapshot_info.add_child_elem(comment)
desired_attr.add_child_elem(snapshot_info)
snapshot_obj.add_child_elem(desired_attr)
# compose query
query = netapp_utils.zapi.NaElement("query")
snapshot_info_obj = netapp_utils.zapi.NaElement("snapshot-info")
snapshot_info_obj.add_new_child("name", self.snapshot)
snapshot_info_obj.add_new_child("volume", self.volume)
query.add_child_elem(snapshot_info_obj)
snapshot_obj.add_child_elem(query)
result = self.server.invoke_successfully(snapshot_obj, True)
return_value = None
# TODO: Snapshot with the same name will mess this up,
# need to fix that later
if result.get_child_by_name('num-records') and \
int(result.get_child_content('num-records')) == 1:
attributes_list = result.get_child_by_name('attributes-list')
snap_info = attributes_list.get_child_by_name('snapshot-info')
return_value = {'comment': snap_info.get_child_content('comment')}
return return_value
def apply(self):
"""
Check to see which play we should run
"""
changed = False
comment_changed = False
netapp_utils.ems_log_event("na_ontap_snapshot", self.server)
existing_snapshot = self.does_snapshot_exist()
if existing_snapshot is not None:
if self.state == 'absent':
changed = True
elif self.state == 'present' and self.new_comment:
if existing_snapshot['comment'] != self.new_comment:
comment_changed = True
changed = True
else:
if self.state == 'present':
changed = True
if changed:
if self.module.check_mode:
pass
else:
if self.state == 'present':
if not existing_snapshot:
self.create_snapshot()
elif comment_changed:
self.modify_snapshot()
elif self.state == 'absent':
if existing_snapshot:
self.delete_snapshot()
self.module.exit_json(changed=changed)
def main():
"""
Creates, modifies, and deletes a Snapshot
"""
obj = NetAppOntapSnapshot()
obj.apply()
if __name__ == '__main__':
main()
Loading…
Cancel
Save