#
# LSST Data Management System
#
# This product includes software developed by the
# LSST Project (http://www.lsst.org/).
#
# See COPYRIGHT file at the top of the source tree.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the LSST License Statement and
# the GNU General Public License along with this program.  If not,
# see <https://www.lsstcorp.org/LegalNotices/>.
#
"""SQUASH (https://squash.lsst.codes) client.
Data objects, particularly Job, Metric, and Specification, use this client to
upload and retrieve data from the SQUASH verification database.
SQUASH will likely be replaced by a database served behind Data Management's
webserv API. This client is considered a shim during construction.
"""
from __future__ import print_function
__all__ = ['get', 'post', 'get_endpoint_url', 'reset_endpoint_cache',
           'get_default_timeout', 'get_default_api_version',
           'make_accept_header']
import json
import requests
import lsst.log
# Version of the SQUASH API this client is compatible with
_API_VERSION = '2.0'
# Default HTTP timeout (seconds) for all SQUASH client requests.
_TIMEOUT = 30.0
# URLs for SQUASH endpoints, cached by `get_endpoint_url()`.
_ENDPOINT_URLS = None
[docs]def get_endpoint_url(api_url, api_endpoint, **kwargs):
    """Lookup SQUASH endpoint URL.
    Parameters
    ----------
    api_url : `str`
        Root URL of the SQUASH API. For example,
        ``'https://squash.lsst.codes/dashboard/api/'``.
    api_endpoint : `str`
        Name of the SQUASH API endpoint. For example, ``'jobs'``.
    **kwargs : optional
        Additional keyword arguments passed to `get`.
    Returns
    -------
    endpoint_url : `str`
        Full SQUASH endpoint URL.
    Notes
    -----
    Endpoints are discovered from the SQUASH API itself. The SQUASH API is
    queried on the first call to `get_endpoint_url`. Subsequent calls use
    cached results for all endpoints. This cache can be reset with the
    `reset_endpoint_cache` function.
    """
    global _ENDPOINT_URLS
    if _ENDPOINT_URLS is None:
        r = get(api_url, **kwargs)
        _ENDPOINT_URLS = r.json()
    return _ENDPOINT_URLS[api_endpoint] 
[docs]def reset_endpoint_cache():
    """Reset the cache used by `get_endpoint_url`.
    """
    global _ENDPOINT_URLS
    _ENDPOINT_URLS = None 
[docs]def get_default_timeout():
    """Get the default HTTP client timeout setting.
    Returns
    -------
    timeout : `float`
        Default timeout setting, in seconds.
    """
    global _TIMEOUT
    return _TIMEOUT 
[docs]def get_default_api_version():
    """Get the default SQUASH API versioned used by the lsst.verify.squash
    client functions.
    Returns
    -------
    version : `str`
        API version. For example, ``'2.0'``.
    """
    global _API_VERSION
    return _API_VERSION 
[docs]def post(api_url, api_endpoint, json_doc=None,
         api_user=None, api_password=None, timeout=None, version=None):
    """POST a JSON document to SQUASH.
    Parameters
    ----------
    api_url : `str`
        Root URL of the SQUASH API. For example,
        ``'https://squash.lsst.codes/api'``.
    api_endpoint : `str`
        Name of the API endpoint to post to.
    json_doc : `dict`
        A JSON-serializable object.
    api_user : `str`
        API username.
    api_password : `str`
        API password.
    timeout : `float`, optional
        Request timeout. The value of `get_default_timeout` is used by default.
    version : `str`, optional
        API version. The value of `get_default_api_version` is used by default.
    Raises
    ------
    requests.exceptions.RequestException
       Raised if the HTTP request fails.
    Returns
    -------
    response : `requests.Response`
        Response object. Obtain JSON content with ``response.json()``.
    """
    log = lsst.log.Log.getLogger('verify.squash.post')
    api_endpoint_url = get_endpoint_url(api_url, api_endpoint)
    headers = {
        'Accept': make_accept_header(version)
    }
    try:
        # Disable redirect following for POST as requests will turn a POST into
        # a GET when following a redirect. http://ls.st/pbx
        r = requests.post(api_endpoint_url,
                          auth=(api_user, api_password),
                          json=json_doc,
                          allow_redirects=False,
                          headers=headers,
                          timeout=timeout or get_default_timeout())
        log.info('POST {0} status: {1}'.format(api_endpoint_url,
                                               r.status_code))
        r.raise_for_status()
        # be pedantic about return status. requests#status_code will not error
        # on 3xx codes
        if r.status_code != 201:
            message = 'Expected status=201. Got status={0}. {1}'.format(
                r.status_code, r.reason)
            raise requests.exceptions.RequestException(message)
    except requests.exceptions.RequestException as e:
        log.error(str(e))
        log.error(json.dumps(json_doc))
        raise e
    return r 
[docs]def get(api_url, api_endpoint=None,
        api_user=None, api_password=None, timeout=None, version=None):
    """GET request to the SQUASH API.
    Parameters
    ----------
    api_url : `str`
        Root URL of the SQUASH API. For example,
        ``'https://squash.lsst.codes/api'``.
    api_endpoint : `str`, optional
        Name of the API endpoint to post to. The ``api_url`` is requested if
        unset.
    api_user : `str`, optional
        API username.
    api_password : `str`, optional
        API password.
    timeout : `float`, optional
        Request timeout. The value of `get_default_timeout` is used by default.
    version : `str`, optional
        API version. The value of `get_default_api_version` is used by default.
    Raises
    ------
    requests.exceptions.RequestException
       Raised if the HTTP request fails.
    Returns
    -------
    response : `requests.Response`
        Response object. Obtain JSON content with ``response.json()``.
    """
    log = lsst.log.Log.getLogger('verify.squash.get')
    if api_user is not None and api_password is not None:
        auth = (api_user, api_password)
    else:
        auth = None
    if api_endpoint is not None:
        api_endpoint_url = get_endpoint_url(api_url, api_endpoint)
    else:
        api_endpoint_url = api_url
    headers = {
        'Accept': make_accept_header(version)
    }
    try:
        r = requests.get(api_endpoint_url,
                         auth=auth,
                         headers=headers,
                         timeout=timeout or get_default_timeout())
        log.info('GET {0} status: {1}'.format(api_endpoint_url,
                                              r.status_code))
        r.raise_for_status()
    except requests.exceptions.RequestException as e:
        log.error(str(e))
        raise e
    return r