summaryrefslogtreecommitdiff
path: root/quantumclient/common
diff options
context:
space:
mode:
Diffstat (limited to 'quantumclient/common')
-rw-r--r--quantumclient/common/__init__.py8
-rw-r--r--quantumclient/common/clientmanager.py87
-rw-r--r--quantumclient/common/command.py41
-rw-r--r--quantumclient/common/constants.py43
-rw-r--r--quantumclient/common/exceptions.py153
-rw-r--r--quantumclient/common/serializer.py410
-rw-r--r--quantumclient/common/utils.py188
7 files changed, 5 insertions, 925 deletions
diff --git a/quantumclient/common/__init__.py b/quantumclient/common/__init__.py
index 1415c50..7e695ff 100644
--- a/quantumclient/common/__init__.py
+++ b/quantumclient/common/__init__.py
@@ -14,11 +14,3 @@
# License for the specific language governing permissions and limitations
# under the License.
# @author: Somik Behera, Nicira Networks, Inc.
-
-import gettext
-
-t = gettext.translation('quantumclient', fallback=True)
-
-
-def _(msg):
- return t.ugettext(msg)
diff --git a/quantumclient/common/clientmanager.py b/quantumclient/common/clientmanager.py
deleted file mode 100644
index 4d219e4..0000000
--- a/quantumclient/common/clientmanager.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-"""Manage access to the clients, including authenticating when needed.
-"""
-
-import logging
-
-from quantumclient import client
-from quantumclient.quantum import client as quantum_client
-
-
-LOG = logging.getLogger(__name__)
-
-
-class ClientCache(object):
- """Descriptor class for caching created client handles.
- """
-
- def __init__(self, factory):
- self.factory = factory
- self._handle = None
-
- def __get__(self, instance, owner):
- # Tell the ClientManager to login to keystone
- if self._handle is None:
- self._handle = self.factory(instance)
- return self._handle
-
-
-class ClientManager(object):
- """Manages access to API clients, including authentication.
- """
- quantum = ClientCache(quantum_client.make_client)
-
- def __init__(self, token=None, url=None,
- auth_url=None,
- endpoint_type=None,
- tenant_name=None, tenant_id=None,
- username=None, password=None,
- region_name=None,
- api_version=None,
- auth_strategy=None,
- insecure=False
- ):
- self._token = token
- self._url = url
- self._auth_url = auth_url
- self._endpoint_type = endpoint_type
- self._tenant_name = tenant_name
- self._tenant_id = tenant_id
- self._username = username
- self._password = password
- self._region_name = region_name
- self._api_version = api_version
- self._service_catalog = None
- self._auth_strategy = auth_strategy
- self._insecure = insecure
- return
-
- def initialize(self):
- if not self._url:
- httpclient = client.HTTPClient(username=self._username,
- tenant_name=self._tenant_name,
- password=self._password,
- region_name=self._region_name,
- auth_url=self._auth_url,
- endpoint_type=self._endpoint_type,
- insecure=self._insecure)
- httpclient.authenticate()
- # Populate other password flow attributes
- self._token = httpclient.auth_token
- self._url = httpclient.endpoint_url
diff --git a/quantumclient/common/command.py b/quantumclient/common/command.py
deleted file mode 100644
index 7191436..0000000
--- a/quantumclient/common/command.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-"""
-OpenStack base command
-"""
-
-from cliff import command
-
-
-class OpenStackCommand(command.Command):
- """Base class for OpenStack commands
- """
-
- api = None
-
- def run(self, parsed_args):
- if not self.api:
- return
- else:
- return super(OpenStackCommand, self).run(parsed_args)
-
- def get_data(self, parsed_args):
- pass
-
- def take_action(self, parsed_args):
- return self.get_data(parsed_args)
diff --git a/quantumclient/common/constants.py b/quantumclient/common/constants.py
deleted file mode 100644
index a8e8276..0000000
--- a/quantumclient/common/constants.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (c) 2012 OpenStack, LLC.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-EXT_NS = '_extension_ns'
-XML_NS_V20 = 'http://openstack.org/quantum/api/v2.0'
-XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance"
-XSI_ATTR = "xsi:nil"
-XSI_NIL_ATTR = "xmlns:xsi"
-TYPE_XMLNS = "xmlns:quantum"
-TYPE_ATTR = "quantum:type"
-VIRTUAL_ROOT_KEY = "_v_root"
-ATOM_NAMESPACE = "http://www.w3.org/2005/Atom"
-ATOM_XMLNS = "xmlns:atom"
-ATOM_LINK_NOTATION = "{%s}link" % ATOM_NAMESPACE
-
-TYPE_BOOL = "bool"
-TYPE_INT = "int"
-TYPE_LONG = "long"
-TYPE_FLOAT = "float"
-TYPE_LIST = "list"
-TYPE_DICT = "dict"
-
-PLURALS = {'networks': 'network',
- 'ports': 'port',
- 'subnets': 'subnet',
- 'dns_nameservers': 'dns_nameserver',
- 'host_routes': 'host_route',
- 'allocation_pools': 'allocation_pool',
- 'fixed_ips': 'fixed_ip',
- 'extensions': 'extension'}
diff --git a/quantumclient/common/exceptions.py b/quantumclient/common/exceptions.py
index ee33ef7..ab22951 100644
--- a/quantumclient/common/exceptions.py
+++ b/quantumclient/common/exceptions.py
@@ -15,155 +15,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from quantumclient.common import _
+from neutronclient.common.exceptions import * # noqa
-"""
-Quantum base exception handling.
-"""
-
-
-class QuantumException(Exception):
- """Base Quantum Exception
-
- Taken from nova.exception.NovaException
- To correctly use this class, inherit from it and define
- a 'message' property. That message will get printf'd
- with the keyword arguments provided to the constructor.
-
- """
- message = _("An unknown exception occurred.")
-
- def __init__(self, **kwargs):
- try:
- self._error_string = self.message % kwargs
-
- except Exception:
- # at least get the core message out if something happened
- self._error_string = self.message
-
- def __str__(self):
- return self._error_string
-
-
-class NotFound(QuantumException):
- pass
-
-
-class QuantumClientException(QuantumException):
-
- def __init__(self, **kwargs):
- message = kwargs.get('message')
- self.status_code = kwargs.get('status_code', 0)
- if message:
- self.message = message
- super(QuantumClientException, self).__init__(**kwargs)
-
-
-# NOTE: on the client side, we use different exception types in order
-# to allow client library users to handle server exceptions in try...except
-# blocks. The actual error message is the one generated on the server side
-class NetworkNotFoundClient(QuantumClientException):
- pass
-
-
-class PortNotFoundClient(QuantumClientException):
- pass
-
-
-class MalformedResponseBody(QuantumException):
- message = _("Malformed response body: %(reason)s")
-
-
-class StateInvalidClient(QuantumClientException):
- pass
-
-
-class NetworkInUseClient(QuantumClientException):
- pass
-
-
-class PortInUseClient(QuantumClientException):
- pass
-
-
-class AlreadyAttachedClient(QuantumClientException):
- pass
-
-
-class Unauthorized(QuantumClientException):
- message = _("Unauthorized: bad credentials.")
-
-
-class Forbidden(QuantumClientException):
- message = _("Forbidden: your credentials don't give you access to this "
- "resource.")
-
-
-class EndpointNotFound(QuantumClientException):
- """Could not find Service or Region in Service Catalog."""
- message = _("Could not find Service or Region in Service Catalog.")
-
-
-class EndpointTypeNotFound(QuantumClientException):
- """Could not find endpoint type in Service Catalog."""
-
- def __str__(self):
- msg = "Could not find endpoint type %s in Service Catalog."
- return msg % repr(self.message)
-
-
-class AmbiguousEndpoints(QuantumClientException):
- """Found more than one matching endpoint in Service Catalog."""
-
- def __str__(self):
- return "AmbiguousEndpoints: %s" % repr(self.message)
-
-
-class QuantumCLIError(QuantumClientException):
- """Exception raised when command line parsing fails."""
- pass
-
-
-class RequestURITooLong(QuantumClientException):
- """Raised when a request fails with HTTP error 414."""
-
- def __init__(self, **kwargs):
- self.excess = kwargs.get('excess', 0)
- super(RequestURITooLong, self).__init__(**kwargs)
-
-
-class ConnectionFailed(QuantumClientException):
- message = _("Connection to quantum failed: %(reason)s")
-
-
-class BadInputError(Exception):
- """Error resulting from a client sending bad input to a server."""
- pass
-
-
-class Error(Exception):
- def __init__(self, message=None):
- super(Error, self).__init__(message)
-
-
-class MalformedRequestBody(QuantumException):
- message = _("Malformed request body: %(reason)s")
-
-
-class Invalid(Error):
- pass
-
-
-class InvalidContentType(Invalid):
- message = _("Invalid content type %(content_type)s.")
-
-
-class UnsupportedVersion(Exception):
- """Indicates that the user is trying to use an unsupported
- version of the API
- """
- pass
-
-
-class CommandError(Exception):
- pass
+QuantumException = NeutronException
diff --git a/quantumclient/common/serializer.py b/quantumclient/common/serializer.py
deleted file mode 100644
index 9c595e4..0000000
--- a/quantumclient/common/serializer.py
+++ /dev/null
@@ -1,410 +0,0 @@
-# Copyright 2013 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-###
-### Codes from quantum wsgi
-###
-
-import logging
-
-from xml.etree import ElementTree as etree
-from xml.parsers import expat
-
-from quantumclient.common import constants
-from quantumclient.common import exceptions as exception
-from quantumclient.openstack.common.gettextutils import _
-from quantumclient.openstack.common import jsonutils
-
-LOG = logging.getLogger(__name__)
-
-
-class ActionDispatcher(object):
- """Maps method name to local methods through action name."""
-
- def dispatch(self, *args, **kwargs):
- """Find and call local method."""
- action = kwargs.pop('action', 'default')
- action_method = getattr(self, str(action), self.default)
- return action_method(*args, **kwargs)
-
- def default(self, data):
- raise NotImplementedError()
-
-
-class DictSerializer(ActionDispatcher):
- """Default request body serialization."""
-
- def serialize(self, data, action='default'):
- return self.dispatch(data, action=action)
-
- def default(self, data):
- return ""
-
-
-class JSONDictSerializer(DictSerializer):
- """Default JSON request body serialization."""
-
- def default(self, data):
- def sanitizer(obj):
- return unicode(obj)
- return jsonutils.dumps(data, default=sanitizer)
-
-
-class XMLDictSerializer(DictSerializer):
-
- def __init__(self, metadata=None, xmlns=None):
- """XMLDictSerializer constructor.
-
- :param metadata: information needed to deserialize xml into
- a dictionary.
- :param xmlns: XML namespace to include with serialized xml
- """
- super(XMLDictSerializer, self).__init__()
- self.metadata = metadata or {}
- if not xmlns:
- xmlns = self.metadata.get('xmlns')
- if not xmlns:
- xmlns = constants.XML_NS_V20
- self.xmlns = xmlns
-
- def default(self, data):
- """Default serializer of XMLDictSerializer.
-
- :param data: expect data to contain a single key as XML root, or
- contain another '*_links' key as atom links. Other
- case will use 'VIRTUAL_ROOT_KEY' as XML root.
- """
- try:
- links = None
- has_atom = False
- if data is None:
- root_key = constants.VIRTUAL_ROOT_KEY
- root_value = None
- else:
- link_keys = [k for k in data.iterkeys() or []
- if k.endswith('_links')]
- if link_keys:
- links = data.pop(link_keys[0], None)
- has_atom = True
- root_key = (len(data) == 1 and
- data.keys()[0] or constants.VIRTUAL_ROOT_KEY)
- root_value = data.get(root_key, data)
- doc = etree.Element("_temp_root")
- used_prefixes = []
- self._to_xml_node(doc, self.metadata, root_key,
- root_value, used_prefixes)
- if links:
- self._create_link_nodes(list(doc)[0], links)
- return self.to_xml_string(list(doc)[0], used_prefixes, has_atom)
- except AttributeError as e:
- LOG.exception(str(e))
- return ''
-
- def __call__(self, data):
- # Provides a migration path to a cleaner WSGI layer, this
- # "default" stuff and extreme extensibility isn't being used
- # like originally intended
- return self.default(data)
-
- def to_xml_string(self, node, used_prefixes, has_atom=False):
- self._add_xmlns(node, used_prefixes, has_atom)
- return etree.tostring(node, encoding='UTF-8')
-
- #NOTE (ameade): the has_atom should be removed after all of the
- # xml serializers and view builders have been updated to the current
- # spec that required all responses include the xmlns:atom, the has_atom
- # flag is to prevent current tests from breaking
- def _add_xmlns(self, node, used_prefixes, has_atom=False):
- node.set('xmlns', self.xmlns)
- node.set(constants.TYPE_XMLNS, self.xmlns)
- if has_atom:
- node.set(constants.ATOM_XMLNS, constants.ATOM_NAMESPACE)
- node.set(constants.XSI_NIL_ATTR, constants.XSI_NAMESPACE)
- ext_ns = self.metadata.get(constants.EXT_NS, {})
- for prefix in used_prefixes:
- if prefix in ext_ns:
- node.set('xmlns:' + prefix, ext_ns[prefix])
-
- def _to_xml_node(self, parent, metadata, nodename, data, used_prefixes):
- """Recursive method to convert data members to XML nodes."""
- result = etree.SubElement(parent, nodename)
- if ":" in nodename:
- used_prefixes.append(nodename.split(":", 1)[0])
- #TODO(bcwaldon): accomplish this without a type-check
- if isinstance(data, list):
- if not data:
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_LIST)
- return result
- singular = metadata.get('plurals', {}).get(nodename, None)
- if singular is None:
- if nodename.endswith('s'):
- singular = nodename[:-1]
- else:
- singular = 'item'
- for item in data:
- self._to_xml_node(result, metadata, singular, item,
- used_prefixes)
- #TODO(bcwaldon): accomplish this without a type-check
- elif isinstance(data, dict):
- if not data:
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_DICT)
- return result
- attrs = metadata.get('attributes', {}).get(nodename, {})
- for k, v in data.items():
- if k in attrs:
- result.set(k, str(v))
- else:
- self._to_xml_node(result, metadata, k, v,
- used_prefixes)
- elif data is None:
- result.set(constants.XSI_ATTR, 'true')
- else:
- if isinstance(data, bool):
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_BOOL)
- elif isinstance(data, int):
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_INT)
- elif isinstance(data, long):
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_LONG)
- elif isinstance(data, float):
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_FLOAT)
- LOG.debug(_("Data %(data)s type is %(type)s"),
- {'data': data,
- 'type': type(data)})
- if isinstance(data, str):
- result.text = unicode(data, 'utf-8')
- else:
- result.text = unicode(data)
- return result
-
- def _create_link_nodes(self, xml_doc, links):
- for link in links:
- link_node = etree.SubElement(xml_doc, 'atom:link')
- link_node.set('rel', link['rel'])
- link_node.set('href', link['href'])
-
-
-class TextDeserializer(ActionDispatcher):
- """Default request body deserialization."""
-
- def deserialize(self, datastring, action='default'):
- return self.dispatch(datastring, action=action)
-
- def default(self, datastring):
- return {}
-
-
-class JSONDeserializer(TextDeserializer):
-
- def _from_json(self, datastring):
- try:
- return jsonutils.loads(datastring)
- except ValueError:
- msg = _("Cannot understand JSON")
- raise exception.MalformedRequestBody(reason=msg)
-
- def default(self, datastring):
- return {'body': self._from_json(datastring)}
-
-
-class XMLDeserializer(TextDeserializer):
-
- def __init__(self, metadata=None):
- """XMLDeserializer constructor.
-
- :param metadata: information needed to deserialize xml into
- a dictionary.
- """
- super(XMLDeserializer, self).__init__()
- self.metadata = metadata or {}
- xmlns = self.metadata.get('xmlns')
- if not xmlns:
- xmlns = constants.XML_NS_V20
- self.xmlns = xmlns
-
- def _get_key(self, tag):
- tags = tag.split("}", 1)
- if len(tags) == 2:
- ns = tags[0][1:]
- bare_tag = tags[1]
- ext_ns = self.metadata.get(constants.EXT_NS, {})
- if ns == self.xmlns:
- return bare_tag
- for prefix, _ns in ext_ns.items():
- if ns == _ns:
- return prefix + ":" + bare_tag
- else:
- return tag
-
- def _get_links(self, root_tag, node):
- link_nodes = node.findall(constants.ATOM_LINK_NOTATION)
- root_tag = self._get_key(node.tag)
- link_key = "%s_links" % root_tag
- link_list = []
- for link in link_nodes:
- link_list.append({'rel': link.get('rel'),
- 'href': link.get('href')})
- # Remove link node in order to avoid link node being
- # processed as an item in _from_xml_node
- node.remove(link)
- return link_list and {link_key: link_list} or {}
-
- def _from_xml(self, datastring):
- if datastring is None:
- return None
- plurals = set(self.metadata.get('plurals', {}))
- try:
- node = etree.fromstring(datastring)
- root_tag = self._get_key(node.tag)
- links = self._get_links(root_tag, node)
- result = self._from_xml_node(node, plurals)
- # There is no case where root_tag = constants.VIRTUAL_ROOT_KEY
- # and links is not None because of the way data are serialized
- if root_tag == constants.VIRTUAL_ROOT_KEY:
- return result
- return dict({root_tag: result}, **links)
- except Exception as e:
- parseError = False
- # Python2.7
- if (hasattr(etree, 'ParseError') and
- isinstance(e, getattr(etree, 'ParseError'))):
- parseError = True
- # Python2.6
- elif isinstance(e, expat.ExpatError):
- parseError = True
- if parseError:
- msg = _("Cannot understand XML")
- raise exception.MalformedRequestBody(reason=msg)
- else:
- raise
-
- def _from_xml_node(self, node, listnames):
- """Convert a minidom node to a simple Python type.
-
- :param listnames: list of XML node names whose subnodes should
- be considered list items.
-
- """
- attrNil = node.get(str(etree.QName(constants.XSI_NAMESPACE, "nil")))
- attrType = node.get(str(etree.QName(
- self.metadata.get('xmlns'), "type")))
- if (attrNil and attrNil.lower() == 'true'):
- return None
- elif not len(node) and not node.text:
- if (attrType and attrType == constants.TYPE_DICT):
- return {}
- elif (attrType and attrType == constants.TYPE_LIST):
- return []
- else:
- return ''
- elif (len(node) == 0 and node.text):
- converters = {constants.TYPE_BOOL:
- lambda x: x.lower() == 'true',
- constants.TYPE_INT:
- lambda x: int(x),
- constants.TYPE_LONG:
- lambda x: long(x),
- constants.TYPE_FLOAT:
- lambda x: float(x)}
- if attrType and attrType in converters:
- return converters[attrType](node.text)
- else:
- return node.text
- elif self._get_key(node.tag) in listnames:
- return [self._from_xml_node(n, listnames) for n in node]
- else:
- result = dict()
- for attr in node.keys():
- if (attr == 'xmlns' or
- attr.startswith('xmlns:') or
- attr == constants.XSI_ATTR or
- attr == constants.TYPE_ATTR):
- continue
- result[self._get_key(attr)] = node.get(attr)
- children = list(node)
- for child in children:
- result[self._get_key(child.tag)] = self._from_xml_node(
- child, listnames)
- return result
-
- def default(self, datastring):
- return {'body': self._from_xml(datastring)}
-
- def __call__(self, datastring):
- # Adding a migration path to allow us to remove unncessary classes
- return self.default(datastring)
-
-
-# NOTE(maru): this class is duplicated from quantum.wsgi
-class Serializer(object):
- """Serializes and deserializes dictionaries to certain MIME types."""
-
- def __init__(self, metadata=None, default_xmlns=None):
- """Create a serializer based on the given WSGI environment.
-
- 'metadata' is an optional dict mapping MIME types to information
- needed to serialize a dictionary to that type.
-
- """
- self.metadata = metadata or {}
- self.default_xmlns = default_xmlns
-
- def _get_serialize_handler(self, content_type):
- handlers = {
- 'application/json': JSONDictSerializer(),
- 'application/xml': XMLDictSerializer(self.metadata),
- }
-
- try:
- return handlers[content_type]
- except Exception:
- raise exception.InvalidContentType(content_type=content_type)
-
- def serialize(self, data, content_type):
- """Serialize a dictionary into the specified content type."""
- return self._get_serialize_handler(content_type).serialize(data)
-
- def deserialize(self, datastring, content_type):
- """Deserialize a string to a dictionary.
-
- The string must be in the format of a supported MIME type.
-
- """
- return self.get_deserialize_handler(content_type).deserialize(
- datastring)
-
- def get_deserialize_handler(self, content_type):
- handlers = {
- 'application/json': JSONDeserializer(),
- 'application/xml': XMLDeserializer(self.metadata),
- }
-
- try:
- return handlers[content_type]
- except Exception:
- raise exception.InvalidContentType(content_type=content_type)
diff --git a/quantumclient/common/utils.py b/quantumclient/common/utils.py
index 192b46f..01a0442 100644
--- a/quantumclient/common/utils.py
+++ b/quantumclient/common/utils.py
@@ -1,6 +1,7 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2011, Nicira Networks, Inc.
+# Copyright 2011 Nicira Networks, Inc
+# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -13,188 +14,5 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-#
-# Borrowed from nova code base, more utilities will be added/borrowed as and
-# when needed.
-# @author: Somik Behera, Nicira Networks, Inc.
-
-"""Utilities and helper functions."""
-
-import datetime
-import json
-import logging
-import os
-import sys
-
-from quantumclient.common import exceptions
-from quantumclient.openstack.common import strutils
-
-
-def env(*vars, **kwargs):
- """Returns the first environment variable set.
-
- if none are non-empty, defaults to '' or keyword arg default.
- """
- for v in vars:
- value = os.environ.get(v)
- if value:
- return value
- return kwargs.get('default', '')
-
-
-def to_primitive(value):
- if isinstance(value, list) or isinstance(value, tuple):
- o = []
- for v in value:
- o.append(to_primitive(v))
- return o
- elif isinstance(value, dict):
- o = {}
- for k, v in value.iteritems():
- o[k] = to_primitive(v)
- return o
- elif isinstance(value, datetime.datetime):
- return str(value)
- elif hasattr(value, 'iteritems'):
- return to_primitive(dict(value.iteritems()))
- elif hasattr(value, '__iter__'):
- return to_primitive(list(value))
- else:
- return value
-
-
-def dumps(value, indent=None):
- try:
- return json.dumps(value, indent=indent)
- except TypeError:
- pass
- return json.dumps(to_primitive(value))
-
-
-def loads(s):
- return json.loads(s)
-
-
-def import_class(import_str):
- """Returns a class from a string including module and class.
-
- :param import_str: a string representation of the class name
- :rtype: the requested class
- """
- mod_str, _sep, class_str = import_str.rpartition('.')
- __import__(mod_str)
- return getattr(sys.modules[mod_str], class_str)
-
-
-def get_client_class(api_name, version, version_map):
- """Returns the client class for the requested API version
-
- :param api_name: the name of the API, e.g. 'compute', 'image', etc
- :param version: the requested API version
- :param version_map: a dict of client classes keyed by version
- :rtype: a client class for the requested API version
- """
- try:
- client_path = version_map[str(version)]
- except (KeyError, ValueError):
- msg = "Invalid %s client version '%s'. must be one of: %s" % (
- (api_name, version, ', '.join(version_map.keys())))
- raise exceptions.UnsupportedVersion(msg)
-
- return import_class(client_path)
-
-
-def get_item_properties(item, fields, mixed_case_fields=[], formatters={}):
- """Return a tuple containing the item properties.
-
- :param item: a single item resource (e.g. Server, Tenant, etc)
- :param fields: tuple of strings with the desired field names
- :param mixed_case_fields: tuple of field names to preserve case
- :param formatters: dictionary mapping field names to callables
- to format the values
- """
- row = []
-
- for field in fields:
- if field in formatters:
- row.append(formatters[field](item))
- else:
- if field in mixed_case_fields:
- field_name = field.replace(' ', '_')
- else:
- field_name = field.lower().replace(' ', '_')
- if not hasattr(item, field_name) and isinstance(item, dict):
- data = item[field_name]
- else:
- data = getattr(item, field_name, '')
- if data is None:
- data = ''
- row.append(data)
- return tuple(row)
-
-
-def str2bool(strbool):
- if strbool is None:
- return None
- else:
- return strbool.lower() == 'true'
-
-
-def str2dict(strdict):
- '''Convert key1=value1,key2=value2,... string into dictionary.
-
- :param strdict: key1=value1,key2=value2
- '''
- _info = {}
- for kv_str in strdict.split(","):
- k, v = kv_str.split("=", 1)
- _info.update({k: v})
- return _info
-
-
-def http_log_req(_logger, args, kwargs):
- if not _logger.isEnabledFor(logging.DEBUG):
- return
-
- string_parts = ['curl -i']
- for element in args:
- if element in ('GET', 'POST', 'DELETE', 'PUT'):
- string_parts.append(' -X %s' % element)
- else:
- string_parts.append(' %s' % element)
-
- for element in kwargs['headers']:
- header = ' -H "%s: %s"' % (element, kwargs['headers'][element])
- string_parts.append(header)
-
- if 'body' in kwargs and kwargs['body']:
- string_parts.append(" -d '%s'" % (kwargs['body']))
- string_parts = safe_encode_list(string_parts)
- _logger.debug("\nREQ: %s\n" % "".join(string_parts))
-
-
-def http_log_resp(_logger, resp, body):
- if not _logger.isEnabledFor(logging.DEBUG):
- return
- _logger.debug("RESP:%s %s\n", resp, body)
-
-
-def _safe_encode_without_obj(data):
- if isinstance(data, basestring):
- return strutils.safe_encode(data)
- return data
-
-
-def safe_encode_list(data):
- return map(_safe_encode_without_obj, data)
-
-
-def safe_encode_dict(data):
- def _encode_item((k, v)):
- if isinstance(v, list):
- return (k, safe_encode_list(v))
- elif isinstance(v, dict):
- return (k, safe_encode_dict(v))
- return (k, _safe_encode_without_obj(v))
- return dict(map(_encode_item, data.items()))
+from neutronclient.common.utils import * # noqa