summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Archibald <carchi@netapp.com>2018-05-18 17:17:01 -0700
committerMatt Davis <nitzmahone@users.noreply.github.com>2018-05-18 17:17:01 -0700
commit8b5f34e11034dbe3ffeeeb081735eae9e76c8194 (patch)
treed6f9d6e84bdf216a812a5dea05b41a7eb74087a7
parent53b7bf33a7172a8adba588b52c4169cde6d228d5 (diff)
downloadansible-8b5f34e11034dbe3ffeeeb081735eae9e76c8194.tar.gz
Add Na_ontap_broadcast_domain module. (#39753)
* add first module * fix case * Create na_ontap * Fix small pep8 errors * Fixes for issues found by Amit * fixes for amit * fix doc * get doc to compile
-rw-r--r--lib/ansible/module_utils/netapp.py73
-rw-r--r--lib/ansible/modules/storage/netapp/na_ontap_broadcast_domain.py253
-rw-r--r--lib/ansible/utils/module_docs_fragments/netapp.py42
3 files changed, 363 insertions, 5 deletions
diff --git a/lib/ansible/module_utils/netapp.py b/lib/ansible/module_utils/netapp.py
index e9236c9742..ac0c85e8e1 100644
--- a/lib/ansible/module_utils/netapp.py
+++ b/lib/ansible/module_utils/netapp.py
@@ -78,12 +78,22 @@ def has_sf_sdk():
return HAS_SF_SDK
-def ontap_sf_host_argument_spec():
+def na_ontap_host_argument_spec():
return dict(
hostname=dict(required=True, type='str'),
username=dict(required=True, type='str', aliases=['user']),
password=dict(required=True, type='str', aliases=['pass'], no_log=True),
+ https=dict(required=False, type='bool', default=False)
+ )
+
+
+def ontap_sf_host_argument_spec():
+
+ return dict(
+ hostname=dict(required=True, type='str'),
+ username=dict(required=True, type='str', aliases=['user']),
+ password=dict(required=True, type='str', aliases=['pass'], no_log=True)
)
@@ -102,6 +112,34 @@ def create_sf_connection(module, port=None):
module.fail_json(msg="the python SolidFire SDK module is required")
+def setup_na_ontap_zapi(module, vserver=None):
+ hostname = module.params['hostname']
+ username = module.params['username']
+ password = module.params['password']
+ https = module.params['https']
+
+ if HAS_NETAPP_LIB:
+ # set up zapi
+ server = zapi.NaServer(hostname)
+ server.set_username(username)
+ server.set_password(password)
+ if vserver:
+ server.set_vserver(vserver)
+ # Todo : Replace hard-coded values with configurable parameters.
+ server.set_api_version(major=1, minor=21)
+ # default is HTTP
+ if https is True:
+ server.set_port(443)
+ server.set_transport_type('HTTPS')
+ else:
+ server.set_port(80)
+ server.set_transport_type('HTTP')
+ server.set_server_type('FILER')
+ return server
+ else:
+ module.fail_json(msg="the python NetApp-Lib module is required")
+
+
def setup_ontap_zapi(module, vserver=None):
hostname = module.params['hostname']
username = module.params['username']
@@ -174,3 +212,36 @@ def request(url, data=None, headers=None, method='GET', use_proxy=True,
raise Exception(resp_code, data)
else:
return resp_code, data
+
+
+def ems_log_event(source, server, name="Ansible", id="12345", version="1.1",
+ category="Information", event="setup", autosupport="false"):
+ ems_log = zapi.NaElement('ems-autosupport-log')
+ # Host name invoking the API.
+ ems_log.add_new_child("computer-name", name)
+ # ID of event. A user defined event-id, range [0..2^32-2].
+ ems_log.add_new_child("event-id", id)
+ # Name of the application invoking the API.
+ ems_log.add_new_child("event-source", source)
+ # Version of application invoking the API.
+ ems_log.add_new_child("app-version", version)
+ # Application defined category of the event.
+ ems_log.add_new_child("category", category)
+ # Description of event to log. An application defined message to log.
+ ems_log.add_new_child("event-description", event)
+ ems_log.add_new_child("log-level", "6")
+ ems_log.add_new_child("auto-support", autosupport)
+ server.invoke_successfully(ems_log, True)
+
+
+def get_cserver(server):
+ vserver_info = zapi.NaElement('vserver-get-iter')
+ query_details = zapi.NaElement.create_node_with_children('vserver-info', **{'vserver-type': 'admin'})
+ query = zapi.NaElement('query')
+ query.add_child_elem(query_details)
+ vserver_info.add_child_elem(query)
+ result = server.invoke_successfully(vserver_info,
+ enable_tunneling=False)
+ attribute_list = result.get_child_by_name('attributes-list')
+ vserver_list = attribute_list.get_child_by_name('vserver-info')
+ return vserver_list.get_child_content('vserver-name')
diff --git a/lib/ansible/modules/storage/netapp/na_ontap_broadcast_domain.py b/lib/ansible/modules/storage/netapp/na_ontap_broadcast_domain.py
new file mode 100644
index 0000000000..9181082549
--- /dev/null
+++ b/lib/ansible/modules/storage/netapp/na_ontap_broadcast_domain.py
@@ -0,0 +1,253 @@
+#!/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_broadcast_domain
+short_description: Manage NetApp ONTAP broadcast domains.
+extends_documentation_fragment:
+ - netapp.na_ontap
+version_added: '2.6'
+author: Chris Archibald (carchi8py@gmail.com), Kevin Hutton (khutton@netapp.com), Suhas Bangalore Shekar (bsuhas@netapp.com)
+description:
+- Modify a ONTAP broadcast domain.
+options:
+ state:
+ description:
+ - Whether the specified broadcast domain should exist or not.
+ choices: ['present', 'absent']
+ default: present
+ broadcast_domain:
+ description:
+ - Specify the broadcast_domain name
+ required: true
+ mtu:
+ description:
+ - Specify the required mtu for the broadcast domain
+ ipspace:
+ description:
+ - Specify the required ipspace for the broadcast domain
+ ports:
+ description:
+ - Specify the ports associated with this broadcast domain. Should be comma separated
+
+'''
+
+EXAMPLES = """
+ - name: create broadcast domain
+ na_ontap_broadcast_domain:
+ state=present
+ username={{ netapp_username }}
+ password={{ netapp_password }}
+ hostname={{ netapp_hostname }}
+ broadcast_domain=123kevin
+ mtu=1000
+ ipspace=Default
+ ports=khutton-vsim1:e0d-12,khutton-vsim1:e0d-13
+ - name: delete broadcast domain
+ na_ontap_broadcast_domain:
+ state=absent
+ username={{ netapp_username }}
+ password={{ netapp_password }}
+ hostname={{ netapp_hostname }}
+ broadcast_domain=123kevin
+ mtu=1000
+ ipspace=Default
+ - name: modify broadcast domain
+ na_ontap_broadcast_domain:
+ state=absent
+ username={{ netapp_username }}
+ password={{ netapp_password }}
+ hostname={{ netapp_hostname }}
+ broadcast_domain=123kevin
+ mtu=1100
+ ipspace=Default
+"""
+
+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 NetAppOntapBroadcastDomain(object):
+ """
+ Create, Modifies and Destroys a Broadcast domain
+ """
+ def __init__(self):
+ """
+ Initialize the ONTAP Broadcast Domain class
+ """
+ self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
+ self.argument_spec.update(dict(
+ state=dict(required=False, choices=['present', 'absent'], default='present'),
+ broadcast_domain=dict(required=True, type='str'),
+ ipspace=dict(required=False, type='str'),
+ mtu=dict(required=False, type='str'),
+ ports=dict(required=False, type='list'),
+ ))
+
+ 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.broadcast_domain = parameters['broadcast_domain']
+ self.ipspace = parameters['ipspace']
+ self.mtu = parameters['mtu']
+ self.ports = parameters['ports']
+
+ 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)
+ return
+
+ def get_broadcast_domain(self):
+ """
+ Return details about the broadcast domain
+ :param:
+ name : broadcast domain name
+ :return: Details about the broadcas domain. None if not found.
+ :rtype: dict
+ """
+ domain_get_iter = netapp_utils.zapi.NaElement('net-port-broadcast-domain-get-iter')
+ broadcast_domain_info = netapp_utils.zapi.NaElement('net-port-broadcast-domain-info')
+ broadcast_domain_info.add_new_child('broadcast-domain', self.broadcast_domain)
+ query = netapp_utils.zapi.NaElement('query')
+ query.add_child_elem(broadcast_domain_info)
+ domain_get_iter.add_child_elem(query)
+ result = self.server.invoke_successfully(domain_get_iter, True)
+ domain_exists = None
+ # check if job exists
+ if result.get_child_by_name('num-records') and \
+ int(result.get_child_content('num-records')) == 1:
+ domain_info = result.get_child_by_name('attributes-list').\
+ get_child_by_name('net-port-broadcast-domain-info')
+ domain_name = domain_info.get_child_content('broadcast-domain')
+ domain_mtu = domain_info.get_child_content('mtu')
+ domain_ipspace = domain_info.get_child_content('ipspace')
+ domain_exists = {
+ 'domain-name': domain_name,
+ 'mtu': domain_mtu,
+ 'ipspace': domain_ipspace
+ }
+ return domain_exists
+
+ def create_broadcast_domain(self):
+ """
+ Creates a new broadcast domain
+ """
+ domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-create')
+ domain_obj.add_new_child("broadcast-domain", self.broadcast_domain)
+ if self.ipspace:
+ domain_obj.add_new_child("ipspace", self.ipspace)
+ domain_obj.add_new_child("mtu", self.mtu)
+ if self.ports:
+ ports_obj = netapp_utils.zapi.NaElement('ports')
+ domain_obj.add_child_elem(ports_obj)
+ for port in self.ports:
+ ports_obj.add_new_child('net-qualified-port-name', port)
+ try:
+ self.server.invoke_successfully(domain_obj, True)
+ except netapp_utils.zapi.NaApiError as error:
+ self.module.fail_json(msg='Error creating broadcast domain %s: %s' %
+ (self.broadcast_domain, to_native(error)),
+ exception=traceback.format_exc())
+
+ def delete_broadcast_domain(self):
+ """
+ Deletes a broadcast domain
+ """
+ domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-destroy')
+ domain_obj.add_new_child("broadcast-domain", self.broadcast_domain)
+ if self.ipspace:
+ domain_obj.add_new_child("ipspace", self.ipspace)
+ try:
+ self.server.invoke_successfully(domain_obj, True)
+ except netapp_utils.zapi.NaApiError as error:
+ self.module.fail_json(msg='Error deleting broadcast domain %s: %s' %
+ (self.broadcast_domain, to_native(error)),
+ exception=traceback.format_exc())
+
+ def modify_broadcast_domain(self):
+ """
+ Modifies ipspace and mtu options of a broadcast domain
+ """
+ domain_obj = netapp_utils.zapi.NaElement('net-port-broadcast-domain-modify')
+ domain_obj.add_new_child("broadcast-domain", self.broadcast_domain)
+ if self.ipspace:
+ domain_obj.add_new_child("ipspace", self.ipspace)
+ if self.mtu:
+ domain_obj.add_new_child("mtu", self.mtu)
+ try:
+ self.server.invoke_successfully(domain_obj, True)
+ except netapp_utils.zapi.NaApiError as error:
+ self.module.fail_json(msg='Error modifying broadcast domain %s: %s' %
+ (self.broadcast_domain, to_native(error)),
+ exception=traceback.format_exc())
+
+ def apply(self):
+ """
+ Run Module based on play book
+ """
+ changed = False
+ broadcast_domain_details = self.get_broadcast_domain()
+ broadcast_domain_exists = 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_broadcast_domain", cserver)
+ if broadcast_domain_details:
+ broadcast_domain_exists = True
+ if self.state == 'absent': # delete
+ changed = True
+ elif self.state == 'present': # modify
+ if (self.mtu and self.mtu != broadcast_domain_details['mtu']) or \
+ (self.ipspace and self.ipspace != broadcast_domain_details['ipspace']):
+ 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 broadcast_domain_exists:
+ self.create_broadcast_domain()
+ else: # execute modify
+ self.modify_broadcast_domain()
+ elif self.state == 'absent': # execute delete
+ self.delete_broadcast_domain()
+ self.module.exit_json(changed=changed)
+
+
+def main():
+ """
+ Creates the NetApp ONTAP Broadcast Domain Object that can be created, deleted and modified.
+ """
+ obj = NetAppOntapBroadcastDomain()
+ obj.apply()
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/ansible/utils/module_docs_fragments/netapp.py b/lib/ansible/utils/module_docs_fragments/netapp.py
index 3629f2c453..653d4d1d20 100644
--- a/lib/ansible/utils/module_docs_fragments/netapp.py
+++ b/lib/ansible/utils/module_docs_fragments/netapp.py
@@ -1,5 +1,5 @@
#
-# (c) 2016, Sumit Kumar <sumit4@netapp.com>
+# (c) 2018, Sumit Kumar <sumit4@netapp.com>, chris Archibald <carchi@netapp.com>
#
# This file is part of Ansible
#
@@ -28,8 +28,8 @@ notes:
- Ansible modules are available for the following NetApp Storage Platforms: E-Series, ONTAP, SolidFire
"""
- # Documentation fragment for ONTAP
- ONTAP = """
+ # Documentation fragment for ONTAP (na_ontap)
+ NA_ONTAP = """
options:
hostname:
required: true
@@ -46,14 +46,48 @@ options:
description:
- Password for the specified user.
aliases: ['pass']
+ https:
+ description:
+ - Enable and disabled https
+ type: bool
+ default: false
+
+requirements:
+ - A physical or virtual clustered Data ONTAP system. The modules were developed with Clustered Data ONTAP 9.3
+ - Ansible 2.6
+ - netapp-lib (2017.10.30). Install using 'pip install netapp-lib'
+ - To enable http on the cluster you must run the following commands 'set -privilege advanced;' 'system services web modify -http-enabled true;'
+notes:
+ - The modules prefixed with na\\_ontap are built to support the ONTAP storage platform.
+
+ """
+
+ # Documentation fragment for ONTAP (na_cdot)
+ ONTAP = """
+options:
+ hostname:
+ required: true
+ description:
+ - The hostname or IP address of the ONTAP instance.
+ username:
+ required: true
+ description:
+ - This can be a Cluster-scoped or SVM-scoped account, depending on whether a Cluster-level or SVM-level API is required.
+ For more information, please read the documentation U(https://goo.gl/BRu78Z).
+ aliases: ['user']
+ password:
+ required: true
+ description:
+ - Password for the specified user.
+ aliases: ['pass']
requirements:
- A physical or virtual clustered Data ONTAP system. The modules were developed with Clustered Data ONTAP 8.3
- Ansible 2.2
- netapp-lib (2015.9.25). Install using 'pip install netapp-lib'
notes:
- - The modules prefixed with C(netapp\\_cdot) are built to support the ONTAP storage platform.
+ - The modules prefixed with na\\_cdot are built to support the ONTAP storage platform.
"""