diff --git a/novaclient/openstack/common/__init__.py b/novaclient/openstack/common/__init__.py
index d1223eaf7..e69de29bb 100644
--- a/novaclient/openstack/common/__init__.py
+++ b/novaclient/openstack/common/__init__.py
@@ -1,17 +0,0 @@
-#
-#    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.
-
-import six
-
-
-six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox'))
diff --git a/novaclient/openstack/common/_i18n.py b/novaclient/openstack/common/_i18n.py
new file mode 100644
index 000000000..6ae2ff239
--- /dev/null
+++ b/novaclient/openstack/common/_i18n.py
@@ -0,0 +1,40 @@
+#    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.
+
+"""oslo.i18n integration module.
+
+See http://docs.openstack.org/developer/oslo.i18n/usage.html
+
+"""
+
+import oslo.i18n
+
+
+# NOTE(dhellmann): This reference to o-s-l-o will be replaced by the
+# application name when this module is synced into the separate
+# repository. It is OK to have more than one translation function
+# using the same domain, since there will still only be one message
+# catalog.
+_translators = oslo.i18n.TranslatorFactory(domain='novaclient')
+
+# The primary translation function using the well-known name "_"
+_ = _translators.primary
+
+# Translators for log levels.
+#
+# The abbreviated names are meant to reflect the usual use of a short
+# name like '_'. The "L" is for "log" and the other letter comes from
+# the level.
+_LI = _translators.log_info
+_LW = _translators.log_warning
+_LE = _translators.log_error
+_LC = _translators.log_critical
diff --git a/novaclient/openstack/common/apiclient/base.py b/novaclient/openstack/common/apiclient/base.py
index 8380ba397..cc5c8b005 100644
--- a/novaclient/openstack/common/apiclient/base.py
+++ b/novaclient/openstack/common/apiclient/base.py
@@ -26,13 +26,12 @@ Base utilities to build API operation managers and objects on top of.
 import abc
 import copy
 
+from oslo.utils import strutils
 import six
 from six.moves.urllib import parse
 
+from novaclient.openstack.common._i18n import _
 from novaclient.openstack.common.apiclient import exceptions
-from novaclient.openstack.common.gettextutils import _
-from novaclient.openstack.common import strutils
-from novaclient.openstack.common import uuidutils
 
 
 def getid(obj):
@@ -100,12 +99,13 @@ class BaseManager(HookableMixin):
         super(BaseManager, self).__init__()
         self.client = client
 
-    def _list(self, url, response_key, obj_class=None, json=None):
+    def _list(self, url, response_key=None, obj_class=None, json=None):
         """List the collection.
 
         :param url: a partial URL, e.g., '/servers'
         :param response_key: the key to be looked up in response dictionary,
-            e.g., 'servers'
+            e.g., 'servers'. If response_key is None - all response body
+            will be used.
         :param obj_class: class for constructing the returned objects
             (self.resource_class will be used by default)
         :param json: data that will be encoded as JSON and passed in POST
@@ -119,7 +119,7 @@ class BaseManager(HookableMixin):
         if obj_class is None:
             obj_class = self.resource_class
 
-        data = body[response_key]
+        data = body[response_key] if response_key is not None else body
         # NOTE(ja): keystone returns values as list as {'values': [ ... ]}
         #           unlike other services which just return the list...
         try:
@@ -129,15 +129,17 @@ class BaseManager(HookableMixin):
 
         return [obj_class(self, res, loaded=True) for res in data if res]
 
-    def _get(self, url, response_key):
+    def _get(self, url, response_key=None):
         """Get an object from collection.
 
         :param url: a partial URL, e.g., '/servers'
         :param response_key: the key to be looked up in response dictionary,
-            e.g., 'server'
+            e.g., 'server'. If response_key is None - all response body
+            will be used.
         """
         body = self.client.get(url).json()
-        return self.resource_class(self, body[response_key], loaded=True)
+        data = body[response_key] if response_key is not None else body
+        return self.resource_class(self, data, loaded=True)
 
     def _head(self, url):
         """Retrieve request headers for an object.
@@ -147,21 +149,23 @@ class BaseManager(HookableMixin):
         resp = self.client.head(url)
         return resp.status_code == 204
 
-    def _post(self, url, json, response_key, return_raw=False):
+    def _post(self, url, json, response_key=None, return_raw=False):
         """Create an object.
 
         :param url: a partial URL, e.g., '/servers'
         :param json: data that will be encoded as JSON and passed in POST
             request (GET will be sent by default)
         :param response_key: the key to be looked up in response dictionary,
-            e.g., 'servers'
+            e.g., 'server'. If response_key is None - all response body
+            will be used.
         :param return_raw: flag to force returning raw JSON instead of
             Python object of self.resource_class
         """
         body = self.client.post(url, json=json).json()
+        data = body[response_key] if response_key is not None else body
         if return_raw:
-            return body[response_key]
-        return self.resource_class(self, body[response_key])
+            return data
+        return self.resource_class(self, data)
 
     def _put(self, url, json=None, response_key=None):
         """Update an object with PUT method.
@@ -170,7 +174,8 @@ class BaseManager(HookableMixin):
         :param json: data that will be encoded as JSON and passed in POST
             request (GET will be sent by default)
         :param response_key: the key to be looked up in response dictionary,
-            e.g., 'servers'
+            e.g., 'servers'. If response_key is None - all response body
+            will be used.
         """
         resp = self.client.put(url, json=json)
         # PUT requests may not return a body
@@ -188,7 +193,8 @@ class BaseManager(HookableMixin):
         :param json: data that will be encoded as JSON and passed in POST
             request (GET will be sent by default)
         :param response_key: the key to be looked up in response dictionary,
-            e.g., 'servers'
+            e.g., 'servers'. If response_key is None - all response body
+            will be used.
         """
         body = self.client.patch(url, json=json).json()
         if response_key is not None:
@@ -437,21 +443,6 @@ class Resource(object):
         self._info = info
         self._add_details(info)
         self._loaded = loaded
-        self._init_completion_cache()
-
-    def _init_completion_cache(self):
-        cache_write = getattr(self.manager, 'write_to_completion_cache', None)
-        if not cache_write:
-            return
-
-        # NOTE(sirp): ensure `id` is already present because if it isn't we'll
-        # enter an infinite loop of __getattr__ -> get -> __init__ ->
-        # __getattr__ -> ...
-        if 'id' in self.__dict__ and uuidutils.is_uuid_like(self.id):
-            cache_write('uuid', self.id)
-
-        if self.human_id:
-            cache_write('human_id', self.human_id)
 
     def __repr__(self):
         reprkeys = sorted(k
diff --git a/novaclient/openstack/common/apiclient/client.py b/novaclient/openstack/common/apiclient/client.py
index a3666daf0..7780cea91 100644
--- a/novaclient/openstack/common/apiclient/client.py
+++ b/novaclient/openstack/common/apiclient/client.py
@@ -33,11 +33,11 @@ try:
 except ImportError:
     import json
 
+from oslo.utils import importutils
 import requests
 
+from novaclient.openstack.common._i18n import _
 from novaclient.openstack.common.apiclient import exceptions
-from novaclient.openstack.common.gettextutils import _
-from novaclient.openstack.common import importutils
 
 
 _logger = logging.getLogger(__name__)
@@ -156,7 +156,7 @@ class HTTPClient(object):
              requests.Session.request (such as `headers`) or `json`
              that will be encoded as JSON and used as `data` argument
         """
-        kwargs.setdefault("headers", kwargs.get("headers", {}))
+        kwargs.setdefault("headers", {})
         kwargs["headers"]["User-Agent"] = self.user_agent
         if self.original_ip:
             kwargs["headers"]["Forwarded"] = "for=%s;by=%s" % (
@@ -247,6 +247,10 @@ class HTTPClient(object):
                 raise
             self.cached_token = None
             client.cached_endpoint = None
+            if self.auth_plugin.opts.get('token'):
+                self.auth_plugin.opts['token'] = None
+            if self.auth_plugin.opts.get('endpoint'):
+                self.auth_plugin.opts['endpoint'] = None
             self.authenticate()
             try:
                 token, endpoint = self.auth_plugin.token_and_endpoint(
@@ -357,8 +361,7 @@ class BaseClient(object):
                     "Must be one of: %(version_map)s") % {
                         'api_name': api_name,
                         'version': version,
-                        'version_map': ', '.join(version_map.keys())
-                    }
+                        'version_map': ', '.join(version_map.keys())}
             raise exceptions.UnsupportedVersion(msg)
 
         return importutils.import_class(client_path)
diff --git a/novaclient/openstack/common/apiclient/exceptions.py b/novaclient/openstack/common/apiclient/exceptions.py
index 8e0d2ad9b..15e885b9b 100644
--- a/novaclient/openstack/common/apiclient/exceptions.py
+++ b/novaclient/openstack/common/apiclient/exceptions.py
@@ -25,7 +25,7 @@ import sys
 
 import six
 
-from novaclient.openstack.common.gettextutils import _
+from novaclient.openstack.common._i18n import _
 
 
 class ClientException(Exception):
@@ -34,14 +34,6 @@ class ClientException(Exception):
     pass
 
 
-class MissingArgs(ClientException):
-    """Supplied arguments are not sufficient for calling a function."""
-    def __init__(self, missing):
-        self.missing = missing
-        msg = _("Missing arguments: %s") % ", ".join(missing)
-        super(MissingArgs, self).__init__(msg)
-
-
 class ValidationError(ClientException):
     """Error in validation on API client side."""
     pass
@@ -447,8 +439,8 @@ def from_response(response, method, url):
         except ValueError:
             pass
         else:
-            if isinstance(body, dict):
-                error = list(body.values())[0]
+            if isinstance(body, dict) and isinstance(body.get("error"), dict):
+                error = body["error"]
                 kwargs["message"] = error.get("message")
                 kwargs["details"] = error.get("details")
     elif content_type.startswith("text/"):
diff --git a/novaclient/openstack/common/apiclient/fake_client.py b/novaclient/openstack/common/apiclient/fake_client.py
index b6670a67b..eeb9b810a 100644
--- a/novaclient/openstack/common/apiclient/fake_client.py
+++ b/novaclient/openstack/common/apiclient/fake_client.py
@@ -33,7 +33,9 @@ from six.moves.urllib import parse
 from novaclient.openstack.common.apiclient import client
 
 
-def assert_has_keys(dct, required=[], optional=[]):
+def assert_has_keys(dct, required=None, optional=None):
+    required = required or []
+    optional = optional or []
     for k in required:
         try:
             assert k in dct
diff --git a/novaclient/openstack/common/apiclient/utils.py b/novaclient/openstack/common/apiclient/utils.py
new file mode 100644
index 000000000..09ddae43b
--- /dev/null
+++ b/novaclient/openstack/common/apiclient/utils.py
@@ -0,0 +1,87 @@
+#
+#    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.
+
+from oslo.utils import encodeutils
+import six
+
+from novaclient.openstack.common._i18n import _
+from novaclient.openstack.common.apiclient import exceptions
+from novaclient.openstack.common import uuidutils
+
+
+def find_resource(manager, name_or_id, **find_args):
+    """Look for resource in a given manager.
+
+    Used as a helper for the _find_* methods.
+    Example:
+
+    .. code-block:: python
+
+        def _find_hypervisor(cs, hypervisor):
+            #Get a hypervisor by name or ID.
+            return cliutils.find_resource(cs.hypervisors, hypervisor)
+    """
+    # first try to get entity as integer id
+    try:
+        return manager.get(int(name_or_id))
+    except (TypeError, ValueError, exceptions.NotFound):
+        pass
+
+    # now try to get entity as uuid
+    try:
+        if six.PY2:
+            tmp_id = encodeutils.safe_encode(name_or_id)
+        else:
+            tmp_id = encodeutils.safe_decode(name_or_id)
+
+        if uuidutils.is_uuid_like(tmp_id):
+            return manager.get(tmp_id)
+    except (TypeError, ValueError, exceptions.NotFound):
+        pass
+
+    # for str id which is not uuid
+    if getattr(manager, 'is_alphanum_id_allowed', False):
+        try:
+            return manager.get(name_or_id)
+        except exceptions.NotFound:
+            pass
+
+    try:
+        try:
+            return manager.find(human_id=name_or_id, **find_args)
+        except exceptions.NotFound:
+            pass
+
+        # finally try to find entity by name
+        try:
+            resource = getattr(manager, 'resource_class', None)
+            name_attr = resource.NAME_ATTR if resource else 'name'
+            kwargs = {name_attr: name_or_id}
+            kwargs.update(find_args)
+            return manager.find(**kwargs)
+        except exceptions.NotFound:
+            msg = _("No %(name)s with a name or "
+                    "ID of '%(name_or_id)s' exists.") % \
+                {
+                    "name": manager.resource_class.__name__.lower(),
+                    "name_or_id": name_or_id
+                }
+            raise exceptions.CommandError(msg)
+    except exceptions.NoUniqueMatch:
+        msg = _("Multiple %(name)s matches found for "
+                "'%(name_or_id)s', use an ID to be more specific.") % \
+            {
+                "name": manager.resource_class.__name__.lower(),
+                "name_or_id": name_or_id
+            }
+        raise exceptions.CommandError(msg)
diff --git a/novaclient/openstack/common/cliutils.py b/novaclient/openstack/common/cliutils.py
index 6a96da57b..ac2cf7573 100644
--- a/novaclient/openstack/common/cliutils.py
+++ b/novaclient/openstack/common/cliutils.py
@@ -24,14 +24,21 @@ import os
 import sys
 import textwrap
 
+from oslo.utils import encodeutils
+from oslo.utils import strutils
 import prettytable
 import six
 from six import moves
 
-from novaclient.openstack.common.apiclient import exceptions
-from novaclient.openstack.common.gettextutils import _
-from novaclient.openstack.common import strutils
-from novaclient.openstack.common import uuidutils
+from novaclient.openstack.common._i18n import _
+
+
+class MissingArgs(Exception):
+    """Supplied arguments are not sufficient for calling a function."""
+    def __init__(self, missing):
+        self.missing = missing
+        msg = _("Missing arguments: %s") % ", ".join(missing)
+        super(MissingArgs, self).__init__(msg)
 
 
 def validate_args(fn, *args, **kwargs):
@@ -56,7 +63,7 @@ def validate_args(fn, *args, **kwargs):
     required_args = argspec.args[:len(argspec.args) - num_defaults]
 
     def isbound(method):
-        return getattr(method, 'im_self', None) is not None
+        return getattr(method, '__self__', None) is not None
 
     if isbound(fn):
         required_args.pop(0)
@@ -64,7 +71,7 @@ def validate_args(fn, *args, **kwargs):
     missing = [arg for arg in required_args if arg not in kwargs]
     missing = missing[len(args):]
     if missing:
-        raise exceptions.MissingArgs(missing)
+        raise MissingArgs(missing)
 
 
 def arg(*args, **kwargs):
@@ -132,7 +139,7 @@ def isunauthenticated(func):
 
 
 def print_list(objs, fields, formatters=None, sortby_index=0,
-               mixed_case_fields=None):
+               mixed_case_fields=None, field_labels=None):
     """Print a list or objects as a table, one row per object.
 
     :param objs: iterable of :class:`Resource`
@@ -141,14 +148,22 @@ def print_list(objs, fields, formatters=None, sortby_index=0,
     :param sortby_index: index of the field for sorting table rows
     :param mixed_case_fields: fields corresponding to object attributes that
         have mixed case names (e.g., 'serverId')
+    :param field_labels: Labels to use in the heading of the table, default to
+        fields.
     """
     formatters = formatters or {}
     mixed_case_fields = mixed_case_fields or []
+    field_labels = field_labels or fields
+    if len(field_labels) != len(fields):
+        raise ValueError(_("Field labels list %(labels)s has different number "
+                           "of elements than fields list %(fields)s"),
+                         {'labels': field_labels, 'fields': fields})
+
     if sortby_index is None:
         kwargs = {}
     else:
-        kwargs = {'sortby': fields[sortby_index]}
-    pt = prettytable.PrettyTable(fields, caching=False)
+        kwargs = {'sortby': field_labels[sortby_index]}
+    pt = prettytable.PrettyTable(field_labels)
     pt.align = 'l'
 
     for o in objs:
@@ -165,7 +180,7 @@ def print_list(objs, fields, formatters=None, sortby_index=0,
                 row.append(data)
         pt.add_row(row)
 
-    print(strutils.safe_encode(pt.get_string(**kwargs)))
+    print(encodeutils.safe_encode(pt.get_string(**kwargs)))
 
 
 def print_dict(dct, dict_property="Property", wrap=0):
@@ -175,7 +190,7 @@ def print_dict(dct, dict_property="Property", wrap=0):
     :param dict_property: name of the first column
     :param wrap: wrapping for the second column
     """
-    pt = prettytable.PrettyTable([dict_property, 'Value'], caching=False)
+    pt = prettytable.PrettyTable([dict_property, 'Value'])
     pt.align = 'l'
     for k, v in six.iteritems(dct):
         # convert dict to str to check length
@@ -193,7 +208,7 @@ def print_dict(dct, dict_property="Property", wrap=0):
                 col1 = ''
         else:
             pt.add_row([k, v])
-    print(strutils.safe_encode(pt.get_string()))
+    print(encodeutils.safe_encode(pt.get_string()))
 
 
 def get_password(max_password_prompts=3):
@@ -217,76 +232,16 @@ def get_password(max_password_prompts=3):
     return pw
 
 
-def find_resource(manager, name_or_id, **find_args):
-    """Look for resource in a given manager.
-
-    Used as a helper for the _find_* methods.
-    Example:
-
-        def _find_hypervisor(cs, hypervisor):
-            #Get a hypervisor by name or ID.
-            return cliutils.find_resource(cs.hypervisors, hypervisor)
-    """
-    # first try to get entity as integer id
-    try:
-        return manager.get(int(name_or_id))
-    except (TypeError, ValueError, exceptions.NotFound):
-        pass
-
-    # now try to get entity as uuid
-    try:
-        tmp_id = strutils.safe_encode(name_or_id)
-
-        if uuidutils.is_uuid_like(tmp_id):
-            return manager.get(tmp_id)
-    except (TypeError, ValueError, exceptions.NotFound):
-        pass
-
-    # for str id which is not uuid
-    if getattr(manager, 'is_alphanum_id_allowed', False):
-        try:
-            return manager.get(name_or_id)
-        except exceptions.NotFound:
-            pass
-
-    try:
-        try:
-            return manager.find(human_id=name_or_id, **find_args)
-        except exceptions.NotFound:
-            pass
-
-        # finally try to find entity by name
-        try:
-            resource = getattr(manager, 'resource_class', None)
-            name_attr = resource.NAME_ATTR if resource else 'name'
-            kwargs = {name_attr: name_or_id}
-            kwargs.update(find_args)
-            return manager.find(**kwargs)
-        except exceptions.NotFound:
-            msg = _("No %(name)s with a name or "
-                    "ID of '%(name_or_id)s' exists.") % \
-                {
-                    "name": manager.resource_class.__name__.lower(),
-                    "name_or_id": name_or_id
-                }
-            raise exceptions.CommandError(msg)
-    except exceptions.NoUniqueMatch:
-        msg = _("Multiple %(name)s matches found for "
-                "'%(name_or_id)s', use an ID to be more specific.") % \
-            {
-                "name": manager.resource_class.__name__.lower(),
-                "name_or_id": name_or_id
-            }
-        raise exceptions.CommandError(msg)
-
-
 def service_type(stype):
     """Adds 'service_type' attribute to decorated function.
 
     Usage:
-        @service_type('volume')
-        def mymethod(f):
-            ...
+
+    .. code-block:: python
+
+       @service_type('volume')
+       def mymethod(f):
+       ...
     """
     def inner(f):
         f.service_type = stype
diff --git a/novaclient/openstack/common/gettextutils.py b/novaclient/openstack/common/gettextutils.py
deleted file mode 100644
index a48a72812..000000000
--- a/novaclient/openstack/common/gettextutils.py
+++ /dev/null
@@ -1,498 +0,0 @@
-# Copyright 2012 Red Hat, Inc.
-# Copyright 2013 IBM Corp.
-# 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.
-
-"""
-gettext for openstack-common modules.
-
-Usual usage in an openstack.common module:
-
-    from novaclient.openstack.common.gettextutils import _
-"""
-
-import copy
-import functools
-import gettext
-import locale
-from logging import handlers
-import os
-
-from babel import localedata
-import six
-
-_AVAILABLE_LANGUAGES = {}
-
-# FIXME(dhellmann): Remove this when moving to oslo.i18n.
-USE_LAZY = False
-
-
-class TranslatorFactory(object):
-    """Create translator functions
-    """
-
-    def __init__(self, domain, lazy=False, localedir=None):
-        """Establish a set of translation functions for the domain.
-
-        :param domain: Name of translation domain,
-                       specifying a message catalog.
-        :type domain: str
-        :param lazy: Delays translation until a message is emitted.
-                     Defaults to False.
-        :type lazy: Boolean
-        :param localedir: Directory with translation catalogs.
-        :type localedir: str
-        """
-        self.domain = domain
-        self.lazy = lazy
-        if localedir is None:
-            localedir = os.environ.get(domain.upper() + '_LOCALEDIR')
-        self.localedir = localedir
-
-    def _make_translation_func(self, domain=None):
-        """Return a new translation function ready for use.
-
-        Takes into account whether or not lazy translation is being
-        done.
-
-        The domain can be specified to override the default from the
-        factory, but the localedir from the factory is always used
-        because we assume the log-level translation catalogs are
-        installed in the same directory as the main application
-        catalog.
-
-        """
-        if domain is None:
-            domain = self.domain
-        if self.lazy:
-            return functools.partial(Message, domain=domain)
-        t = gettext.translation(
-            domain,
-            localedir=self.localedir,
-            fallback=True,
-        )
-        if six.PY3:
-            return t.gettext
-        return t.ugettext
-
-    @property
-    def primary(self):
-        "The default translation function."
-        return self._make_translation_func()
-
-    def _make_log_translation_func(self, level):
-        return self._make_translation_func(self.domain + '-log-' + level)
-
-    @property
-    def log_info(self):
-        "Translate info-level log messages."
-        return self._make_log_translation_func('info')
-
-    @property
-    def log_warning(self):
-        "Translate warning-level log messages."
-        return self._make_log_translation_func('warning')
-
-    @property
-    def log_error(self):
-        "Translate error-level log messages."
-        return self._make_log_translation_func('error')
-
-    @property
-    def log_critical(self):
-        "Translate critical-level log messages."
-        return self._make_log_translation_func('critical')
-
-
-# NOTE(dhellmann): When this module moves out of the incubator into
-# oslo.i18n, these global variables can be moved to an integration
-# module within each application.
-
-# Create the global translation functions.
-_translators = TranslatorFactory('novaclient')
-
-# The primary translation function using the well-known name "_"
-_ = _translators.primary
-
-# Translators for log levels.
-#
-# The abbreviated names are meant to reflect the usual use of a short
-# name like '_'. The "L" is for "log" and the other letter comes from
-# the level.
-_LI = _translators.log_info
-_LW = _translators.log_warning
-_LE = _translators.log_error
-_LC = _translators.log_critical
-
-# NOTE(dhellmann): End of globals that will move to the application's
-# integration module.
-
-
-def enable_lazy():
-    """Convenience function for configuring _() to use lazy gettext
-
-    Call this at the start of execution to enable the gettextutils._
-    function to use lazy gettext functionality. This is useful if
-    your project is importing _ directly instead of using the
-    gettextutils.install() way of importing the _ function.
-    """
-    # FIXME(dhellmann): This function will be removed in oslo.i18n,
-    # because the TranslatorFactory makes it superfluous.
-    global _, _LI, _LW, _LE, _LC, USE_LAZY
-    tf = TranslatorFactory('novaclient', lazy=True)
-    _ = tf.primary
-    _LI = tf.log_info
-    _LW = tf.log_warning
-    _LE = tf.log_error
-    _LC = tf.log_critical
-    USE_LAZY = True
-
-
-def install(domain, lazy=False):
-    """Install a _() function using the given translation domain.
-
-    Given a translation domain, install a _() function using gettext's
-    install() function.
-
-    The main difference from gettext.install() is that we allow
-    overriding the default localedir (e.g. /usr/share/locale) using
-    a translation-domain-specific environment variable (e.g.
-    NOVA_LOCALEDIR).
-
-    :param domain: the translation domain
-    :param lazy: indicates whether or not to install the lazy _() function.
-                 The lazy _() introduces a way to do deferred translation
-                 of messages by installing a _ that builds Message objects,
-                 instead of strings, which can then be lazily translated into
-                 any available locale.
-    """
-    if lazy:
-        from six import moves
-        tf = TranslatorFactory(domain, lazy=True)
-        moves.builtins.__dict__['_'] = tf.primary
-    else:
-        localedir = '%s_LOCALEDIR' % domain.upper()
-        if six.PY3:
-            gettext.install(domain,
-                            localedir=os.environ.get(localedir))
-        else:
-            gettext.install(domain,
-                            localedir=os.environ.get(localedir),
-                            unicode=True)
-
-
-class Message(six.text_type):
-    """A Message object is a unicode object that can be translated.
-
-    Translation of Message is done explicitly using the translate() method.
-    For all non-translation intents and purposes, a Message is simply unicode,
-    and can be treated as such.
-    """
-
-    def __new__(cls, msgid, msgtext=None, params=None,
-                domain='novaclient', *args):
-        """Create a new Message object.
-
-        In order for translation to work gettext requires a message ID, this
-        msgid will be used as the base unicode text. It is also possible
-        for the msgid and the base unicode text to be different by passing
-        the msgtext parameter.
-        """
-        # If the base msgtext is not given, we use the default translation
-        # of the msgid (which is in English) just in case the system locale is
-        # not English, so that the base text will be in that locale by default.
-        if not msgtext:
-            msgtext = Message._translate_msgid(msgid, domain)
-        # We want to initialize the parent unicode with the actual object that
-        # would have been plain unicode if 'Message' was not enabled.
-        msg = super(Message, cls).__new__(cls, msgtext)
-        msg.msgid = msgid
-        msg.domain = domain
-        msg.params = params
-        return msg
-
-    def translate(self, desired_locale=None):
-        """Translate this message to the desired locale.
-
-        :param desired_locale: The desired locale to translate the message to,
-                               if no locale is provided the message will be
-                               translated to the system's default locale.
-
-        :returns: the translated message in unicode
-        """
-
-        translated_message = Message._translate_msgid(self.msgid,
-                                                      self.domain,
-                                                      desired_locale)
-        if self.params is None:
-            # No need for more translation
-            return translated_message
-
-        # This Message object may have been formatted with one or more
-        # Message objects as substitution arguments, given either as a single
-        # argument, part of a tuple, or as one or more values in a dictionary.
-        # When translating this Message we need to translate those Messages too
-        translated_params = _translate_args(self.params, desired_locale)
-
-        translated_message = translated_message % translated_params
-
-        return translated_message
-
-    @staticmethod
-    def _translate_msgid(msgid, domain, desired_locale=None):
-        if not desired_locale:
-            system_locale = locale.getdefaultlocale()
-            # If the system locale is not available to the runtime use English
-            if not system_locale[0]:
-                desired_locale = 'en_US'
-            else:
-                desired_locale = system_locale[0]
-
-        locale_dir = os.environ.get(domain.upper() + '_LOCALEDIR')
-        lang = gettext.translation(domain,
-                                   localedir=locale_dir,
-                                   languages=[desired_locale],
-                                   fallback=True)
-        if six.PY3:
-            translator = lang.gettext
-        else:
-            translator = lang.ugettext
-
-        translated_message = translator(msgid)
-        return translated_message
-
-    def __mod__(self, other):
-        # When we mod a Message we want the actual operation to be performed
-        # by the parent class (i.e. unicode()), the only thing  we do here is
-        # save the original msgid and the parameters in case of a translation
-        params = self._sanitize_mod_params(other)
-        unicode_mod = super(Message, self).__mod__(params)
-        modded = Message(self.msgid,
-                         msgtext=unicode_mod,
-                         params=params,
-                         domain=self.domain)
-        return modded
-
-    def _sanitize_mod_params(self, other):
-        """Sanitize the object being modded with this Message.
-
-        - Add support for modding 'None' so translation supports it
-        - Trim the modded object, which can be a large dictionary, to only
-        those keys that would actually be used in a translation
-        - Snapshot the object being modded, in case the message is
-        translated, it will be used as it was when the Message was created
-        """
-        if other is None:
-            params = (other,)
-        elif isinstance(other, dict):
-            # Merge the dictionaries
-            # Copy each item in case one does not support deep copy.
-            params = {}
-            if isinstance(self.params, dict):
-                for key, val in self.params.items():
-                    params[key] = self._copy_param(val)
-            for key, val in other.items():
-                params[key] = self._copy_param(val)
-        else:
-            params = self._copy_param(other)
-        return params
-
-    def _copy_param(self, param):
-        try:
-            return copy.deepcopy(param)
-        except Exception:
-            # Fallback to casting to unicode this will handle the
-            # python code-like objects that can't be deep-copied
-            return six.text_type(param)
-
-    def __add__(self, other):
-        msg = _('Message objects do not support addition.')
-        raise TypeError(msg)
-
-    def __radd__(self, other):
-        return self.__add__(other)
-
-    if six.PY2:
-        def __str__(self):
-            # NOTE(luisg): Logging in python 2.6 tries to str() log records,
-            # and it expects specifically a UnicodeError in order to proceed.
-            msg = _('Message objects do not support str() because they may '
-                    'contain non-ascii characters. '
-                    'Please use unicode() or translate() instead.')
-            raise UnicodeError(msg)
-
-
-def get_available_languages(domain):
-    """Lists the available languages for the given translation domain.
-
-    :param domain: the domain to get languages for
-    """
-    if domain in _AVAILABLE_LANGUAGES:
-        return copy.copy(_AVAILABLE_LANGUAGES[domain])
-
-    localedir = '%s_LOCALEDIR' % domain.upper()
-    find = lambda x: gettext.find(domain,
-                                  localedir=os.environ.get(localedir),
-                                  languages=[x])
-
-    # NOTE(mrodden): en_US should always be available (and first in case
-    # order matters) since our in-line message strings are en_US
-    language_list = ['en_US']
-    # NOTE(luisg): Babel <1.0 used a function called list(), which was
-    # renamed to locale_identifiers() in >=1.0, the requirements master list
-    # requires >=0.9.6, uncapped, so defensively work with both. We can remove
-    # this check when the master list updates to >=1.0, and update all projects
-    list_identifiers = (getattr(localedata, 'list', None) or
-                        getattr(localedata, 'locale_identifiers'))
-    locale_identifiers = list_identifiers()
-
-    for i in locale_identifiers:
-        if find(i) is not None:
-            language_list.append(i)
-
-    # NOTE(luisg): Babel>=1.0,<1.3 has a bug where some OpenStack supported
-    # locales (e.g. 'zh_CN', and 'zh_TW') aren't supported even though they
-    # are perfectly legitimate locales:
-    #     https://github.com/mitsuhiko/babel/issues/37
-    # In Babel 1.3 they fixed the bug and they support these locales, but
-    # they are still not explicitly "listed" by locale_identifiers().
-    # That is  why we add the locales here explicitly if necessary so that
-    # they are listed as supported.
-    aliases = {'zh': 'zh_CN',
-               'zh_Hant_HK': 'zh_HK',
-               'zh_Hant': 'zh_TW',
-               'fil': 'tl_PH'}
-    for (locale_, alias) in six.iteritems(aliases):
-        if locale_ in language_list and alias not in language_list:
-            language_list.append(alias)
-
-    _AVAILABLE_LANGUAGES[domain] = language_list
-    return copy.copy(language_list)
-
-
-def translate(obj, desired_locale=None):
-    """Gets the translated unicode representation of the given object.
-
-    If the object is not translatable it is returned as-is.
-    If the locale is None the object is translated to the system locale.
-
-    :param obj: the object to translate
-    :param desired_locale: the locale to translate the message to, if None the
-                           default system locale will be used
-    :returns: the translated object in unicode, or the original object if
-              it could not be translated
-    """
-    message = obj
-    if not isinstance(message, Message):
-        # If the object to translate is not already translatable,
-        # let's first get its unicode representation
-        message = six.text_type(obj)
-    if isinstance(message, Message):
-        # Even after unicoding() we still need to check if we are
-        # running with translatable unicode before translating
-        return message.translate(desired_locale)
-    return obj
-
-
-def _translate_args(args, desired_locale=None):
-    """Translates all the translatable elements of the given arguments object.
-
-    This method is used for translating the translatable values in method
-    arguments which include values of tuples or dictionaries.
-    If the object is not a tuple or a dictionary the object itself is
-    translated if it is translatable.
-
-    If the locale is None the object is translated to the system locale.
-
-    :param args: the args to translate
-    :param desired_locale: the locale to translate the args to, if None the
-                           default system locale will be used
-    :returns: a new args object with the translated contents of the original
-    """
-    if isinstance(args, tuple):
-        return tuple(translate(v, desired_locale) for v in args)
-    if isinstance(args, dict):
-        translated_dict = {}
-        for (k, v) in six.iteritems(args):
-            translated_v = translate(v, desired_locale)
-            translated_dict[k] = translated_v
-        return translated_dict
-    return translate(args, desired_locale)
-
-
-class TranslationHandler(handlers.MemoryHandler):
-    """Handler that translates records before logging them.
-
-    The TranslationHandler takes a locale and a target logging.Handler object
-    to forward LogRecord objects to after translating them. This handler
-    depends on Message objects being logged, instead of regular strings.
-
-    The handler can be configured declaratively in the logging.conf as follows:
-
-        [handlers]
-        keys = translatedlog, translator
-
-        [handler_translatedlog]
-        class = handlers.WatchedFileHandler
-        args = ('/var/log/api-localized.log',)
-        formatter = context
-
-        [handler_translator]
-        class = openstack.common.log.TranslationHandler
-        target = translatedlog
-        args = ('zh_CN',)
-
-    If the specified locale is not available in the system, the handler will
-    log in the default locale.
-    """
-
-    def __init__(self, locale=None, target=None):
-        """Initialize a TranslationHandler
-
-        :param locale: locale to use for translating messages
-        :param target: logging.Handler object to forward
-                       LogRecord objects to after translation
-        """
-        # NOTE(luisg): In order to allow this handler to be a wrapper for
-        # other handlers, such as a FileHandler, and still be able to
-        # configure it using logging.conf, this handler has to extend
-        # MemoryHandler because only the MemoryHandlers' logging.conf
-        # parsing is implemented such that it accepts a target handler.
-        handlers.MemoryHandler.__init__(self, capacity=0, target=target)
-        self.locale = locale
-
-    def setFormatter(self, fmt):
-        self.target.setFormatter(fmt)
-
-    def emit(self, record):
-        # We save the message from the original record to restore it
-        # after translation, so other handlers are not affected by this
-        original_msg = record.msg
-        original_args = record.args
-
-        try:
-            self._translate_and_log_record(record)
-        finally:
-            record.msg = original_msg
-            record.args = original_args
-
-    def _translate_and_log_record(self, record):
-        record.msg = translate(record.msg, self.locale)
-
-        # In addition to translating the message, we also need to translate
-        # arguments that were passed to the log method that were not part
-        # of the main message e.g., log.info(_('Some message %s'), this_one))
-        record.args = _translate_args(record.args, self.locale)
-
-        self.target.emit(record)
diff --git a/novaclient/openstack/common/importutils.py b/novaclient/openstack/common/importutils.py
deleted file mode 100644
index 863255db3..000000000
--- a/novaclient/openstack/common/importutils.py
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright 2011 OpenStack Foundation.
-# 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.
-
-"""
-Import related utilities and helper functions.
-"""
-
-import sys
-import traceback
-
-
-def import_class(import_str):
-    """Returns a class from a string including module and class."""
-    mod_str, _sep, class_str = import_str.rpartition('.')
-    __import__(mod_str)
-    try:
-        return getattr(sys.modules[mod_str], class_str)
-    except AttributeError:
-        raise ImportError('Class %s cannot be found (%s)' %
-                          (class_str,
-                           traceback.format_exception(*sys.exc_info())))
-
-
-def import_object(import_str, *args, **kwargs):
-    """Import a class and return an instance of it."""
-    return import_class(import_str)(*args, **kwargs)
-
-
-def import_object_ns(name_space, import_str, *args, **kwargs):
-    """Tries to import object from default namespace.
-
-    Imports a class and return an instance of it, first by trying
-    to find the class in a default namespace, then failing back to
-    a full path if not found in the default namespace.
-    """
-    import_value = "%s.%s" % (name_space, import_str)
-    try:
-        return import_class(import_value)(*args, **kwargs)
-    except ImportError:
-        return import_class(import_str)(*args, **kwargs)
-
-
-def import_module(import_str):
-    """Import a module."""
-    __import__(import_str)
-    return sys.modules[import_str]
-
-
-def import_versioned_module(version, submodule=None):
-    module = 'novaclient.v%s' % version
-    if submodule:
-        module = '.'.join((module, submodule))
-    return import_module(module)
-
-
-def try_import(import_str, default=None):
-    """Try to import a module and if it fails return default."""
-    try:
-        return import_module(import_str)
-    except ImportError:
-        return default
diff --git a/novaclient/openstack/common/strutils.py b/novaclient/openstack/common/strutils.py
deleted file mode 100644
index c22063d90..000000000
--- a/novaclient/openstack/common/strutils.py
+++ /dev/null
@@ -1,245 +0,0 @@
-# Copyright 2011 OpenStack Foundation.
-# 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.
-
-"""
-System-level utilities and helper functions.
-"""
-
-import math
-import re
-import sys
-import unicodedata
-
-import six
-
-from novaclient.openstack.common.gettextutils import _
-
-
-UNIT_PREFIX_EXPONENT = {
-    'k': 1,
-    'K': 1,
-    'Ki': 1,
-    'M': 2,
-    'Mi': 2,
-    'G': 3,
-    'Gi': 3,
-    'T': 4,
-    'Ti': 4,
-}
-UNIT_SYSTEM_INFO = {
-    'IEC': (1024, re.compile(r'(^[-+]?\d*\.?\d+)([KMGT]i?)?(b|bit|B)$')),
-    'SI': (1000, re.compile(r'(^[-+]?\d*\.?\d+)([kMGT])?(b|bit|B)$')),
-}
-
-TRUE_STRINGS = ('1', 't', 'true', 'on', 'y', 'yes')
-FALSE_STRINGS = ('0', 'f', 'false', 'off', 'n', 'no')
-
-SLUGIFY_STRIP_RE = re.compile(r"[^\w\s-]")
-SLUGIFY_HYPHENATE_RE = re.compile(r"[-\s]+")
-
-
-def int_from_bool_as_string(subject):
-    """Interpret a string as a boolean and return either 1 or 0.
-
-    Any string value in:
-
-        ('True', 'true', 'On', 'on', '1')
-
-    is interpreted as a boolean True.
-
-    Useful for JSON-decoded stuff and config file parsing
-    """
-    return bool_from_string(subject) and 1 or 0
-
-
-def bool_from_string(subject, strict=False, default=False):
-    """Interpret a string as a boolean.
-
-    A case-insensitive match is performed such that strings matching 't',
-    'true', 'on', 'y', 'yes', or '1' are considered True and, when
-    `strict=False`, anything else returns the value specified by 'default'.
-
-    Useful for JSON-decoded stuff and config file parsing.
-
-    If `strict=True`, unrecognized values, including None, will raise a
-    ValueError which is useful when parsing values passed in from an API call.
-    Strings yielding False are 'f', 'false', 'off', 'n', 'no', or '0'.
-    """
-    if not isinstance(subject, six.string_types):
-        subject = str(subject)
-
-    lowered = subject.strip().lower()
-
-    if lowered in TRUE_STRINGS:
-        return True
-    elif lowered in FALSE_STRINGS:
-        return False
-    elif strict:
-        acceptable = ', '.join(
-            "'%s'" % s for s in sorted(TRUE_STRINGS + FALSE_STRINGS))
-        msg = _("Unrecognized value '%(val)s', acceptable values are:"
-                " %(acceptable)s") % {'val': subject,
-                                      'acceptable': acceptable}
-        raise ValueError(msg)
-    else:
-        return default
-
-
-def safe_decode(text, incoming=None, errors='strict'):
-    """Decodes incoming text/bytes string using `incoming` if they're not
-       already unicode.
-
-    :param incoming: Text's current encoding
-    :param errors: Errors handling policy. See here for valid
-        values http://docs.python.org/2/library/codecs.html
-    :returns: text or a unicode `incoming` encoded
-                representation of it.
-    :raises TypeError: If text is not an instance of str
-    """
-    if not isinstance(text, (six.string_types, six.binary_type)):
-        raise TypeError("%s can't be decoded" % type(text))
-
-    if isinstance(text, six.text_type):
-        return text
-
-    if not incoming:
-        incoming = (sys.stdin.encoding or
-                    sys.getdefaultencoding())
-
-    try:
-        return text.decode(incoming, errors)
-    except UnicodeDecodeError:
-        # Note(flaper87) If we get here, it means that
-        # sys.stdin.encoding / sys.getdefaultencoding
-        # didn't return a suitable encoding to decode
-        # text. This happens mostly when global LANG
-        # var is not set correctly and there's no
-        # default encoding. In this case, most likely
-        # python will use ASCII or ANSI encoders as
-        # default encodings but they won't be capable
-        # of decoding non-ASCII characters.
-        #
-        # Also, UTF-8 is being used since it's an ASCII
-        # extension.
-        return text.decode('utf-8', errors)
-
-
-def safe_encode(text, incoming=None,
-                encoding='utf-8', errors='strict'):
-    """Encodes incoming text/bytes string using `encoding`.
-
-    If incoming is not specified, text is expected to be encoded with
-    current python's default encoding. (`sys.getdefaultencoding`)
-
-    :param incoming: Text's current encoding
-    :param encoding: Expected encoding for text (Default UTF-8)
-    :param errors: Errors handling policy. See here for valid
-        values http://docs.python.org/2/library/codecs.html
-    :returns: text or a bytestring `encoding` encoded
-                representation of it.
-    :raises TypeError: If text is not an instance of str
-    """
-    if not isinstance(text, (six.string_types, six.binary_type)):
-        raise TypeError("%s can't be encoded" % type(text))
-
-    if not incoming:
-        incoming = (sys.stdin.encoding or
-                    sys.getdefaultencoding())
-
-    if isinstance(text, six.text_type):
-        if six.PY3:
-            return text.encode(encoding, errors).decode(incoming)
-        else:
-            return text.encode(encoding, errors)
-    elif text and encoding != incoming:
-        # Decode text before encoding it with `encoding`
-        text = safe_decode(text, incoming, errors)
-        if six.PY3:
-            return text.encode(encoding, errors).decode(incoming)
-        else:
-            return text.encode(encoding, errors)
-
-    return text
-
-
-def string_to_bytes(text, unit_system='IEC', return_int=False):
-    """Converts a string into an float representation of bytes.
-
-    The units supported for IEC ::
-
-        Kb(it), Kib(it), Mb(it), Mib(it), Gb(it), Gib(it), Tb(it), Tib(it)
-        KB, KiB, MB, MiB, GB, GiB, TB, TiB
-
-    The units supported for SI ::
-
-        kb(it), Mb(it), Gb(it), Tb(it)
-        kB, MB, GB, TB
-
-    Note that the SI unit system does not support capital letter 'K'
-
-    :param text: String input for bytes size conversion.
-    :param unit_system: Unit system for byte size conversion.
-    :param return_int: If True, returns integer representation of text
-                       in bytes. (default: decimal)
-    :returns: Numerical representation of text in bytes.
-    :raises ValueError: If text has an invalid value.
-
-    """
-    try:
-        base, reg_ex = UNIT_SYSTEM_INFO[unit_system]
-    except KeyError:
-        msg = _('Invalid unit system: "%s"') % unit_system
-        raise ValueError(msg)
-    match = reg_ex.match(text)
-    if match:
-        magnitude = float(match.group(1))
-        unit_prefix = match.group(2)
-        if match.group(3) in ['b', 'bit']:
-            magnitude /= 8
-    else:
-        msg = _('Invalid string format: %s') % text
-        raise ValueError(msg)
-    if not unit_prefix:
-        res = magnitude
-    else:
-        res = magnitude * pow(base, UNIT_PREFIX_EXPONENT[unit_prefix])
-    if return_int:
-        return int(math.ceil(res))
-    return res
-
-
-def to_slug(value, incoming=None, errors="strict"):
-    """Normalize string.
-
-    Convert to lowercase, remove non-word characters, and convert spaces
-    to hyphens.
-
-    Inspired by Django's `slugify` filter.
-
-    :param value: Text to slugify
-    :param incoming: Text's current encoding
-    :param errors: Errors handling policy. See here for valid
-        values http://docs.python.org/2/library/codecs.html
-    :returns: slugified unicode representation of `value`
-    :raises TypeError: If text is not an instance of str
-    """
-    value = safe_decode(value, incoming, errors)
-    # NOTE(aababilov): no need to use safe_(encode|decode) here:
-    # encodings are always "ascii", error handling is always "ignore"
-    # and types are always known (first: unicode; second: str)
-    value = unicodedata.normalize("NFKD", value).encode(
-        "ascii", "ignore").decode("ascii")
-    value = SLUGIFY_STRIP_RE.sub("", value).strip().lower()
-    return SLUGIFY_HYPHENATE_RE.sub("-", value)
diff --git a/tools/install_venv_common.py b/tools/install_venv_common.py
index 46822e329..e279159ab 100644
--- a/tools/install_venv_common.py
+++ b/tools/install_venv_common.py
@@ -125,7 +125,7 @@ class InstallVenv(object):
         parser.add_option('-n', '--no-site-packages',
                           action='store_true',
                           help="Do not inherit packages from global Python "
-                               "install")
+                               "install.")
         return parser.parse_args(argv[1:])[0]