Server IP : 85.214.239.14 / Your IP : 3.129.70.54 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Mon Sep 30 15:36:27 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /lib/python3/dist-packages/ansible_collections/netapp/ontap/plugins/modules/ |
Upload File : |
#!/usr/bin/python ''' # (c) 2020-2022, 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 DOCUMENTATION = ''' author: NetApp Ansible Team (@carchi8py) <ng-ansibleteam@netapp.com> description: - Call a ZAPI on ONTAP. - Cluster ZAPIs are run using a cluster admin account. - Vserver ZAPIs can be run using a vsadmin account or using vserver tunneling (cluster admin with I(vserver option)). - In case of success, a json dictionary is returned as C(response). - In case of a ZAPI error, C(status), C(errno), C(reason) are set to help with diagnosing the issue, - and the call is reported as an error ('failed'). - Other errors (eg connection issues) are reported as Ansible error. extends_documentation_fragment: - netapp.ontap.netapp.na_ontap_zapi module: na_ontap_zapit short_description: NetApp ONTAP Run any ZAPI on ONTAP version_added: "20.4.0" options: zapi: description: - A dictionary for the zapi and arguments. - An XML tag I(<tag>value</tag>) is a dictionary with tag as the key. - Value can be another dictionary, a list of dictionaries, a string, or nothing. - eg I(<tag/>) is represented as I(tag:) - A single zapi can be called at a time. Ansible warns if duplicate keys are found and only uses the last entry. required: true type: dict vserver: description: - if provided, forces vserver tunneling. username identifies a cluster admin account. type: str ''' EXAMPLES = """ - name: Ontap ZAPI hosts: localhost gather_facts: False collections: - netapp.ontap vars: login: &login hostname: "{{ admin_ip }}" username: "{{ admin_username }}" password: "{{ admin_password }}" https: true validate_certs: false svm_login: &svm_login hostname: "{{ svm_admin_ip }}" username: "{{ svm_admin_username }}" password: "{{ svm_admin_password }}" https: true validate_certs: false tasks: - name: run ontap ZAPI command as cluster admin netapp.ontap.na_ontap_zapit: <<: *login zapi: system-get-version: register: output - debug: var=output - name: run ontap ZAPI command as cluster admin netapp.ontap.na_ontap_zapit: <<: *login zapi: vserver-get-iter: register: output - debug: var=output - name: run ontap ZAPI command as cluster admin netapp.ontap.na_ontap_zapit: <<: *login zapi: vserver-get-iter: desired-attributes: vserver-info: - aggr-list: - aggr-name - allowed-protocols: - protocols - vserver-aggr-info-list: - vserser-aggr-info - uuid query: vserver-info: vserver-name: trident_svm register: output - debug: var=output - name: run ontap ZAPI command as vsadmin netapp.ontap.na_ontap_zapit: <<: *svm_login zapi: vserver-get-iter: desired-attributes: vserver-info: - uuid register: output - debug: var=output - name: run ontap ZAPI command as vserver tunneling netapp.ontap.na_ontap_zapit: <<: *login vserver: trident_svm zapi: vserver-get-iter: desired-attributes: vserver-info: - uuid register: output - debug: var=output - name: run ontap active-directory ZAPI command netapp.ontap.na_ontap_zapit: <<: *login vserver: trident_svm zapi: active-directory-account-create: account-name: testaccount admin-username: testuser admin-password: testpass domain: testdomain organizational-unit: testou register: output ignore_errors: True - debug: var=output """ RETURN = """ response: description: - If successful, a json dictionary representing the data returned by the ZAPI. - If the ZAPI was executed but failed, an empty dictionary. - Not present if the ZAPI call cannot be performed. returned: On success type: dict status: description: - If the ZAPI was executed but failed, the status set by the ZAPI. - Not present if successful, or if the ZAPI call cannot be performed. returned: On error type: str errno: description: - If the ZAPI was executed but failed, the error code set by the ZAPI. - Not present if successful, or if the ZAPI call cannot be performed. returned: On error type: str reason: description: - If the ZAPI was executed but failed, the error reason set by the ZAPI. - Not present if successful, or if the ZAPI call cannot be performed. returned: On error type: str """ import traceback from ansible.module_utils.basic import AnsibleModule from ansible.module_utils._text import to_native import ansible_collections.netapp.ontap.plugins.module_utils.netapp as netapp_utils try: import xmltodict HAS_XMLTODICT = True except ImportError: HAS_XMLTODICT = False try: import json HAS_JSON = True except ImportError: HAS_JSON = False class NetAppONTAPZapi: ''' calls a ZAPI command ''' def __init__(self): self.argument_spec = netapp_utils.na_ontap_zapi_only_spec() self.argument_spec.update(dict( zapi=dict(required=True, type='dict'), vserver=dict(required=False, type='str'), )) self.module = AnsibleModule( argument_spec=self.argument_spec, supports_check_mode=False ) parameters = self.module.params # set up state variables self.zapi = parameters['zapi'] self.vserver = parameters['vserver'] if not HAS_JSON: self.module.fail_json(msg="the python json module is required") if not netapp_utils.has_netapp_lib(): self.module.fail_json(msg=netapp_utils.netapp_lib_is_required()) if not HAS_XMLTODICT: self.module.fail_json(msg="the python xmltodict module is required") if self.vserver is not None: self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.vserver) else: self.server = netapp_utils.setup_na_ontap_zapi(module=self.module) def jsonify_and_parse_output(self, xml_data): ''' convert from XML to JSON extract status and error fields is present ''' try: as_str = xml_data.to_string() except Exception as exc: self.module.fail_json(msg='Error running zapi in to_string: %s' % str(exc)) try: as_dict = xmltodict.parse(as_str, xml_attribs=True) except Exception as exc: self.module.fail_json(msg='Error running zapi in xmltodict: %s: %s' % (as_str, str(exc))) try: as_json = json.loads(json.dumps(as_dict)) except Exception as exc: self.module.fail_json(msg='Error running zapi in json load/dump: %s: %s' % (as_dict, str(exc))) if 'results' not in as_json: self.module.fail_json(msg='Error running zapi, no results field: %s: %s' % (as_str, repr(as_json))) # set status, and if applicable errno/reason, and remove attribute fields errno = None reason = None response = as_json.pop('results') status = response.get('@status', 'no_status_attr') if status != 'passed': # collect errno and reason errno = response.get('@errno', None) if errno is None: errno = response.get('errorno', None) if errno is None: errno = 'ESTATUSFAILED' reason = response.get('@reason', None) if reason is None: reason = response.get('reason', None) if reason is None: reason = 'Execution failure with unknown reason.' for key in ('@status', '@errno', '@reason', '@xmlns'): try: # remove irrelevant info del response[key] except KeyError: pass return response, status, errno, reason def run_zapi(self): ''' calls the ZAPI ''' zapi_struct = self.zapi error = None if not isinstance(zapi_struct, dict): error = 'A directory entry is expected, eg: system-get-version: ' zapi = zapi_struct else: zapi = list(zapi_struct.keys()) if len(zapi) != 1: error = 'A single ZAPI can be called at a time' else: zapi = zapi[0] # log first, then error out as needed if error: self.module.fail_json(msg='%s, received: %s' % (error, zapi)) zapi_obj = netapp_utils.zapi.NaElement(zapi) attributes = zapi_struct[zapi] if attributes is not None and attributes != 'None': zapi_obj.translate_struct(attributes) try: output = self.server.invoke_elem(zapi_obj, True) except netapp_utils.zapi.NaApiError as error: self.module.fail_json(msg='Error running zapi %s: %s' % (zapi, to_native(error)), exception=traceback.format_exc()) return self.jsonify_and_parse_output(output) def apply(self): ''' calls the zapi and returns json output ''' response, status, errno, reason = self.run_zapi() if status == 'passed': self.module.exit_json(changed=True, response=response) msg = 'ZAPI failure: check errno and reason.' self.module.fail_json(changed=False, response=response, status=status, errno=errno, reason=reason, msg=msg) def main(): """ Execute action from playbook """ zapi = NetAppONTAPZapi() zapi.apply() if __name__ == '__main__': main()