File: //lib/python3.9/site-packages/ansible_collections/netapp/storagegrid/plugins/module_utils/netapp.py
# This code is part of Ansible, but is an independent component.
# This particular file snippet, and this file snippet only, is BSD licensed.
# Modules you write using this snippet, which is embedded dynamically by Ansible
# still belong to the author of the module, and may assign their own license
# to the complete work.
#
# Copyright (c) 2020, NetApp Ansible Team <[email protected]>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import json
import mimetypes
import os
import random
from pprint import pformat
from ansible.module_utils import six
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.six.moves.urllib.error import HTTPError, URLError
from ansible.module_utils.urls import open_url
from ansible.module_utils.api import basic_auth_argument_spec
from ansible.module_utils._text import to_native
COLLECTION_VERSION = "21.11.1"
try:
import requests
HAS_REQUESTS = True
except ImportError:
HAS_REQUESTS = False
import ssl
try:
from urlparse import urlparse, urlunparse
except ImportError:
from urllib.parse import urlparse, urlunparse
POW2_BYTE_MAP = dict(
# Here, 1 kb = 1024
bytes=1,
b=1,
kb=1024,
mb=1024**2,
gb=1024**3,
tb=1024**4,
pb=1024**5,
eb=1024**6,
zb=1024**7,
yb=1024**8,
)
def na_storagegrid_host_argument_spec():
return dict(
api_url=dict(required=True, type="str"),
validate_certs=dict(required=False, type="bool", default=True),
auth_token=dict(required=True, type="str", no_log=True),
)
class SGRestAPI(object):
def __init__(self, module, timeout=60):
self.module = module
self.auth_token = self.module.params["auth_token"]
self.api_url = self.module.params["api_url"]
self.verify = self.module.params["validate_certs"]
self.timeout = timeout
self.check_required_library()
self.sg_version = dict(major=-1, minor=-1, full="", valid=False)
def check_required_library(self):
if not HAS_REQUESTS:
self.module.fail_json(msg=missing_required_lib("requests"))
def send_request(self, method, api, params, json=None):
"""send http request and process reponse, including error conditions"""
url = "%s/%s" % (self.api_url, api)
status_code = None
content = None
json_dict = None
json_error = None
error_details = None
headers = {
"Content-type": "application/json",
"Authorization": self.auth_token,
"Cache-Control": "no-cache",
}
def get_json(response):
"""extract json, and error message if present"""
try:
json = response.json()
except ValueError:
return None, None
success_code = [200, 201, 202, 204]
if response.status_code not in success_code:
error = json.get("message")
else:
error = None
return json, error
try:
response = requests.request(
method,
url,
headers=headers,
timeout=self.timeout,
json=json,
verify=self.verify,
params=params,
)
status_code = response.status_code
# If the response was successful, no Exception will be raised
json_dict, json_error = get_json(response)
except requests.exceptions.HTTPError as err:
__, json_error = get_json(response)
if json_error is None:
error_details = str(err)
except requests.exceptions.ConnectionError as err:
error_details = str(err)
except Exception as err:
error_details = str(err)
if json_error is not None:
error_details = json_error
return json_dict, error_details
# If an error was reported in the json payload, it is handled below
def get(self, api, params=None):
method = "GET"
return self.send_request(method, api, params)
def post(self, api, data, params=None):
method = "POST"
return self.send_request(method, api, params, json=data)
def patch(self, api, data, params=None):
method = "PATCH"
return self.send_request(method, api, params, json=data)
def put(self, api, data, params=None):
method = "PUT"
return self.send_request(method, api, params, json=data)
def delete(self, api, data, params=None):
method = "DELETE"
return self.send_request(method, api, params, json=data)
def get_sg_product_version(self, api_root="grid"):
method = "GET"
api = "api/v3/%s/config/product-version" % api_root
message, error = self.send_request(method, api, params={})
if error:
self.module.fail_json(msg=error)
self.set_version(message)
def set_version(self, message):
try:
product_version = message.get("data", "not found").get("productVersion", "not_found")
except AttributeError:
self.sg_version["valid"] = False
return
self.sg_version["major"], self.sg_version["minor"] = list(map(int, product_version.split(".")[0:2]))
self.sg_version["full"] = product_version
self.sg_version["valid"] = True
def get_sg_version(self):
if self.sg_version["valid"]:
return self.sg_version["major"], self.sg_version["minor"]
return -1, -1
def meets_sg_minimum_version(self, minimum_major, minimum_minor):
return self.get_sg_version() >= (minimum_major, minimum_minor)
def requires_sg_version(self, module_or_option, version):
return "%s requires StorageGRID %s or later." % (module_or_option, version)
def fail_if_not_sg_minimum_version(self, module_or_option, minimum_major, minimum_minor):
version = self.get_sg_version()
if version < (minimum_major, minimum_minor):
msg = "Error: " + self.requires_sg_version(module_or_option, "%d.%d" % (minimum_major, minimum_minor))
msg += " Found: %s.%s." % version
self.module.fail_json(msg=msg)