mirror of https://github.com/ansible/ansible.git
fifth set of modules (#40491)
* fifth set of modules * fix issues * Fixes * fix choices * fix snapshot * spelling * review fixes'pull/33986/merge
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…
Reference in New Issue