From 56dd5a702d708af204e4ff4b77e3871d5ed10083 Mon Sep 17 00:00:00 2001 From: Michael Price Date: Tue, 14 Feb 2017 14:53:18 -0600 Subject: [PATCH] Refactor E-Series AMG module to use module_utils (#20871) * Refactor E-Series AMG module to use module_utils Refactor the NetApp E-Series module to utlize the common module_utils and doc_fragments. * Resolve a PEP8 issue with a missing newline * Resolve compatibility issue with json import --- lib/ansible/module_utils/netapp.py | 63 +++++++++++++++++ .../modules/storage/netapp/netapp_e_amg.py | 68 ++----------------- .../utils/module_docs_fragments/netapp.py | 29 ++++++++ 3 files changed, 96 insertions(+), 64 deletions(-) diff --git a/lib/ansible/module_utils/netapp.py b/lib/ansible/module_utils/netapp.py index 20b8e23443..83b150accc 100644 --- a/lib/ansible/module_utils/netapp.py +++ b/lib/ansible/module_utils/netapp.py @@ -1,5 +1,6 @@ # # (c) 2016, Sumit Kumar +# (c) 2016, Michael Price # # This file is part of Ansible # @@ -16,6 +17,16 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . +try: + import json +except ImportError: + import simplejson as json + +from ansible.module_utils.six.moves.urllib.error import HTTPError + +from ansible.module_utils.pycompat24 import get_exception +from ansible.module_utils.urls import open_url + HAS_NETAPP_LIB = False try: from netapp_lib.api.zapi import zapi @@ -88,3 +99,55 @@ def setup_ontap_zapi(module, vserver=None): return server else: module.fail_json(msg="the python NetApp-Lib module is required") + + +def eseries_host_argument_spec(): + """Retrieve a base argument specifiation common to all NetApp E-Series modules""" + argument_spec = basic_auth_argument_spec() + argument_spec.update(dict( + api_username=dict(type='str', required=True), + api_password=dict(type='str', required=True, no_log=True), + api_url=dict(type='str', required=True), + ssid=dict(type='str', required=True), + validate_certs=dict(required=False, default=True), + )) + return argument_spec + +def request(url, data=None, headers=None, method='GET', use_proxy=True, + force=False, last_mod_time=None, timeout=10, validate_certs=True, + url_username=None, url_password=None, http_agent=None, force_basic_auth=True, ignore_errors=False): + """Issue an HTTP request to a url, retrieving an optional JSON response.""" + + if headers is None: + headers = { + "Content-Type": "application/json", + "Accept": "application/json", + } + + try: + r = open_url(url=url, data=data, headers=headers, method=method, use_proxy=use_proxy, + force=force, last_mod_time=last_mod_time, timeout=timeout, validate_certs=validate_certs, + url_username=url_username, url_password=url_password, http_agent=http_agent, + force_basic_auth=force_basic_auth) + except HTTPError: + err = get_exception() + r = err.fp + + try: + raw_data = r.read() + if raw_data: + data = json.loads(raw_data) + else: + raw_data = None + except: + if ignore_errors: + pass + else: + raise Exception(raw_data) + + resp_code = r.getcode() + + if resp_code >= 400 and not ignore_errors: + raise Exception(resp_code, data) + else: + return resp_code, data diff --git a/lib/ansible/modules/storage/netapp/netapp_e_amg.py b/lib/ansible/modules/storage/netapp/netapp_e_amg.py index e5f60b2945..c3f57dc41d 100644 --- a/lib/ansible/modules/storage/netapp/netapp_e_amg.py +++ b/lib/ansible/modules/storage/netapp/netapp_e_amg.py @@ -28,26 +28,9 @@ description: - Allows for the creation, removal and updating of Asynchronous Mirror Groups for NetApp E-series storage arrays version_added: '2.2' author: Kevin Hulquest (@hulquest) +extends_documentation_fragment: + - netapp.eseries options: - api_username: - required: true - description: - - The username to authenticate with the SANtricity WebServices Proxy or embedded REST API. - api_password: - required: true - description: - - The password to authenticate with the SANtricity WebServices Proxy or embedded REST API. - api_url: - required: true - description: - - The url to the SANtricity WebServices Proxy or embedded REST API. - example: - - https://prod-1.wahoo.acme.com/devmgr/v2 - validate_certs: - required: false - default: true - description: - - Should https certificates be validated? name: description: - The name of the async array you wish to target, or create. @@ -90,10 +73,6 @@ options: - The threshold (in minutes) for notifying the user that periodic synchronization has taken too long to complete. required: no default: 10 - ssid: - description: - - The ID of the primary storage array for the async mirror action - required: yes state: description: - A C(state) of present will either create or update the async mirror group. @@ -143,49 +122,14 @@ msg: import json -from ansible.module_utils.api import basic_auth_argument_spec from ansible.module_utils.basic import AnsibleModule, get_exception -from ansible.module_utils.urls import open_url -from ansible.module_utils.six.moves.urllib.error import HTTPError +from ansible.module_utils.netapp import request, eseries_host_argument_spec HEADERS = { "Content-Type": "application/json", "Accept": "application/json", } - -def request(url, data=None, headers=None, method='GET', use_proxy=True, - force=False, last_mod_time=None, timeout=10, validate_certs=True, - url_username=None, url_password=None, http_agent=None, force_basic_auth=False, ignore_errors=False): - try: - r = open_url(url=url, data=data, headers=headers, method=method, use_proxy=use_proxy, - force=force, last_mod_time=last_mod_time, timeout=timeout, validate_certs=validate_certs, - url_username=url_username, url_password=url_password, http_agent=http_agent, - force_basic_auth=force_basic_auth) - except HTTPError: - err = get_exception() - r = err.fp - - try: - raw_data = r.read() - if raw_data: - data = json.loads(raw_data) - else: - data = None - except: - if ignore_errors: - pass - else: - raise Exception(raw_data) - - resp_code = r.getcode() - - if resp_code >= 400 and not ignore_errors: - raise Exception(resp_code, data) - else: - return resp_code, data - - def has_match(module, ssid, api_url, api_pwd, api_usr, body): compare_keys = ['syncIntervalMinutes', 'syncWarnThresholdMinutes', 'recoveryWarnThresholdMinutes', 'repoUtilizationWarnThreshold'] @@ -271,11 +215,8 @@ def remove_amg(module, ssid, api_url, pwd, user, async_id): def main(): - argument_spec = basic_auth_argument_spec() + argument_spec = eseries_host_argument_spec() argument_spec.update(dict( - api_username=dict(type='str', required=True), - api_password=dict(type='str', required=True, no_log=True), - api_url=dict(type='str', required=True), name=dict(required=True, type='str'), new_name=dict(required=False, type='str'), secondaryArrayId=dict(required=True, type='str'), @@ -284,7 +225,6 @@ def main(): recoveryWarnThresholdMinutes=dict(required=False, default=20, type='int'), repoUtilizationWarnThreshold=dict(required=False, default=80, type='int'), interfaceType=dict(required=False, choices=['fibre', 'iscsi'], type='str'), - ssid=dict(required=True, type='str'), state=dict(required=True, choices=['present', 'absent']), syncWarnThresholdMinutes=dict(required=False, default=10, type='int') )) diff --git a/lib/ansible/utils/module_docs_fragments/netapp.py b/lib/ansible/utils/module_docs_fragments/netapp.py index 57a2095e24..1f62ce5ec8 100644 --- a/lib/ansible/utils/module_docs_fragments/netapp.py +++ b/lib/ansible/utils/module_docs_fragments/netapp.py @@ -77,3 +77,32 @@ notes: - The modules prefixed with C(sf\_) are built to support the SolidFire storage platform. """ + + +# Documentation fragment for E-Series + ESERIES = """ +options: + api_username: + required: true + description: + - The username to authenticate with the SANtricity WebServices Proxy or embedded REST API. + api_password: + required: true + description: + - The password to authenticate with the SANtricity WebServices Proxy or embedded REST API. + api_url: + required: true + description: + - The url to the SANtricity WebServices Proxy or embedded REST API. + example: + - https://prod-1.wahoo.acme.com/devmgr/v2 + validate_certs: + required: false + default: true + description: + - Should https certificates be validated? + ssid: + required: true + description: + - The ID of the array to manage. This value must be unique for each array. + """