Repository URL to install this package:
Version:
4.2.64-4.2 ▾
|
contegoclient
/
usr
/
lib
/
python2.7
/
site-packages
/
contego_python_novaclient_ext
/
contegoclient
/
client.py
|
---|
"""
OpenStack Client interface. Handles the REST calls and responses.
"""
import copy
import hashlib
import logging
import time
from oslo_utils import importutils
import requests
try:
import json
except ImportError:
import simplejson as json
from novaclient import exceptions
class HTTPClient:
USER_AGENT = 'contegoclient'
def __init__(self, user, password=None, project_id=None, auth_url=None,
domain_name='default',
insecure=False, timeout=None, proxy_tenant_id=None,
proxy_token=None, region_name=None,
endpoint_type='publicURL', service_type=None,
service_name=None, volume_service_name=None,
timings=False, bypass_url=None,
os_cache=False, no_cache=True,
http_log_debug=False, auth_system='keystone',
auth_plugin=None, auth_token=None,
cacert=None, user_id=None
):
self.user = user
self.user_id = user_id
self.password = password
self.project_id = project_id
self.password_func = None
if auth_system and auth_system != 'keystone' and not auth_plugin:
raise exceptions.AuthSystemNotFound(auth_system)
if not auth_url and auth_system and auth_system != 'keystone':
auth_url = auth_plugin.get_auth_url()
if not auth_url:
raise exceptions.EndpointNotFound()
self.auth_url = auth_url.rstrip('/') if auth_url else auth_url
self.version = 'v1.1'
self.auth_version = 2
self.domain_name = domain_name
self.region_name = region_name
self.endpoint_type = endpoint_type
self.service_type = service_type
self.service_name = service_name
self.volume_service_name = volume_service_name
self.timings = timings
self.bypass_url = bypass_url.rstrip('/') if bypass_url else bypass_url
self.os_cache = os_cache or not no_cache
self.http_log_debug = http_log_debug
if timeout:
self.timeout = float(timeout)
else:
self.timeout = None
self.times = [] # [("item", starttime, endtime), ...]
self.management_url = self.bypass_url or None
self.auth_token = auth_token
self.proxy_token = proxy_token
self.proxy_tenant_id = proxy_tenant_id
self.keyring_saver = None
self.keyring_saved = False
if insecure:
self.verify_cert = False
else:
self.verify_cert = cacert or True
self.auth_system = auth_system
self.auth_plugin = auth_plugin
self._session = None
self._current_url = None
self._logger = logging.getLogger(__name__)
if self.http_log_debug and not self._logger.handlers:
# Logging level is already set on the root logger
ch = logging.StreamHandler()
self._logger.addHandler(ch)
self._logger.propagate = False
if hasattr(requests, 'logging'):
rql = requests.logging.getLogger(requests.__name__)
rql.addHandler(ch)
# Since we have already setup the root logger on debug, we
# have to set it up here on WARNING (its original level)
# otherwise we will get all the requests logging messages
rql.setLevel(logging.WARNING)
# NOTE(melwitt): Service catalog is only set if bypass_url isn't
# used. Otherwise, we can cache using services_url.
self.service_catalog = None
self.services_url = {}
def set_management_url(self, url):
self.management_url = url
def _redact(self, target, path, text=None):
"""Replace the value of a key in `target`.
The key can be at the top level by specifying a list with a single
key as the path. Nested dictionaries are also supported by passing a
list of keys to be navigated to find the one that should be replaced.
In this case the last one is the one that will be replaced.
:param dict target: the dictionary that may have a key to be redacted;
modified in place
:param list path: a list representing the nested structure in `target`
that should be redacted; modified in place
:param string text: optional text to use as a replacement for the
redacted key. if text is not specified, the
default text will be sha1 hash of the value being
redacted
"""
if len(path):
key = path.pop()
else:
return
# move to the most nested dict
for p in path:
try:
target = target[p]
except KeyError:
return
if key in target:
if text:
target[key] = text
else:
# because in python3 byte string handling is ... ug
value = target[key].encode('utf-8')
sha1sum = hashlib.sha1(value)
target[key] = "{SHA1}%s" % sha1sum.hexdigest()
def http_log_req(self, method, url, kwargs):
if not self.http_log_debug:
return
string_parts = ['curl -g -i']
if not kwargs.get('verify', True):
string_parts.append(' --insecure')
string_parts.append(" '%s'" % url)
string_parts.append(' -X %s' % method)
headers = copy.deepcopy(kwargs.get('headers'))
self._redact(headers, ['X-Auth-Token'])
# because dict ordering changes from 2 to 3
keys = sorted(headers.keys())
for name in keys:
value = headers[name]
header = ' -H "%s: %s"' % (name, value)
string_parts.append(header)
if 'data' in kwargs:
data = json.loads(kwargs.get('data'))
self._redact(data, ['auth', 'passwordCredentials', 'password'])
string_parts.append(" -d '%s'" % json.dumps(data))
self._logger.debug("REQ: %s" % "".join(string_parts))
def http_log_resp(self, resp):
if not self.http_log_debug:
return
if resp.text and resp.status_code != 400:
try:
body = json.loads(resp.text)
self._redact(body, ['access', 'token', 'id'])
except ValueError:
body = None
else:
body = None
self._logger.debug("RESP: [%(status)s] %(headers)s\nRESP BODY: "
"%(text)s\n", {'status': resp.status_code,
'headers': resp.headers,
'text': json.dumps(body)})
def request(self, url, method, **kwargs):
kwargs.setdefault('headers', kwargs.get('headers', {}))
kwargs['headers']['User-Agent'] = self.USER_AGENT
kwargs['headers']['Accept'] = 'application/json'
if 'body' in kwargs:
kwargs['headers']['Content-Type'] = 'application/json'
kwargs['data'] = json.dumps(kwargs['body'])
del kwargs['body']
if self.timeout:
kwargs.setdefault('timeout', self.timeout)
kwargs['verify'] = self.verify_cert
self.http_log_req(method, url, kwargs)
resp = requests.request(method, url, **kwargs)
self.http_log_resp(resp)
if resp.text:
if resp.status_code == 400:
if ('Connection refused' in resp.text or
'actively refused' in resp.text):
raise exceptions.ConnectionRefused(resp.text)
try:
body = json.loads(resp.text)
except ValueError as err:
body = None
self._logger.error(err)
else:
body = None
if resp.status_code >= 400:
raise exceptions.from_response(resp, body, url, method)
return resp, body
def _time_request(self, url, method, **kwargs):
start_time = time.time()
resp, body = self.request(url, method, **kwargs)
self.times.append(("%s %s" % (method, url),
start_time, time.time()))
return resp, body
def _cs_request(self, url, method, **kwargs):
url = self.management_url + url
try:
kwargs.setdefault('headers', {})['X-Auth-Token'] = self.auth_token
if self.project_id:
kwargs['headers']['X-Auth-Project-Id'] = self.project_id
resp, body = self._time_request(url, method, **kwargs)
return resp, body
except exceptions.Unauthorized as e:
raise e
def get(self, url, **kwargs):
return self._cs_request(url, 'GET', **kwargs)
def get_client_class(version):
version_map = {
'2': 'contego_python_novaclient_ext.contegoclient.client2.Client',
}
client_path = version_map[str(version)]
return importutils.import_class(client_path)
def Client(version, *args, **kwargs):
client_class = get_client_class(version)
return client_class(*args, **kwargs)