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