diff -pruN 2.6.2-1/AUTHORS 2.9.0-0ubuntu4/AUTHORS
--- 2.6.2-1/AUTHORS	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/AUTHORS	2017-06-12 13:27:21.000000000 +0000
@@ -0,0 +1,129 @@
+Aleksey Ripinen <aripinen@mirantis.com>
+Alex Gaynor <alex.gaynor@gmail.com>
+Andreas Jaeger <aj@suse.com>
+Andreas Jaeger <aj@suse.de>
+Andrey Kurilin <akurilin@mirantis.com>
+Angus Salkeld <asalkeld@redhat.com>
+Anh Tran <anhtt@vn.fujitsu.com>
+Artur Svechnikov <asvechnikov@mirantis.com>
+Atsushi SAKAI <sakaia@jp.fujitsu.com>
+Balazs Gibizer <balazs.gibizer@ericsson.com>
+Bartosz Górski <bartosz.gorski@ntti3.com>
+Boris Pavlovic <boris@pavlovic.me>
+Brian Waldon <bcwaldon@gmail.com>
+Chaozhe.Chen <chaozhe.chen@easystack.cn>
+ChenZheng <czheng@cn.ibm.com>
+Chmouel Boudjnah <chmouel@enovance.com>
+Chris Dent <chdent@redhat.com>
+Christian Berendt <berendt@b1-systems.de>
+Chuck Short <chuck.short@canonical.com>
+Clenimar Filemon <clenimar.filemon@gmail.com>
+Cyril Roelandt <cyril.roelandt@enovance.com>
+Dan Florea <dflorea@cisco.com>
+Davanum Srinivas <davanum@gmail.com>
+Dina Belova <dbelova@mirantis.com>
+Dirk Mueller <dirk@dmllr.de>
+Doug Hellmann <doug@doughellmann.com>
+Ekaterina Khripunova <e.khripunova@gmail.com>
+Enol Fernandez <enolfc@ifca.unican.es>
+Eoghan Glynn <eglynn@redhat.com>
+Eric Pendergrass <eap@hp.com>
+Eugeniya Kudryashova <ekudryashova@mirantis.com>
+Fabio Giannetti <fabio.giannetti@hp.com>
+ForestLee <lichl@hotmail.com>
+Gordon Chung <chungg@ca.ibm.com>
+Guangyu Suo <guangyu@unitedstack.com>
+Gábor Antal <antal@inf.u-szeged.hu>
+Hanxi Liu <hanxi.liu@easystack.cn>
+Igor Degtiarov <idegtiarov@mirantis.com>
+Ildiko Vancsa <ildiko.vancsa@ericsson.com>
+Ilya Tyaptin <ityaptin@mirantis.com>
+Jake Yip <waipengyip@gmail.com>
+James E. Blair <jeblair@hp.com>
+Jason Zhang <zhesen@nttmcl.com>
+Jeremy Liu <liujiong@gohighsec.com>
+Jeremy Stanley <fungi@yuggoth.org>
+Jia Dong <jiadong.jia@huawei.com>
+Jiří Suchomel <jsuchome@suse.cz>
+John Herndon <john.herndon@hp.com>
+Juan Antonio Osorio Robles <juan.osorio.robles@ericsson.com>
+Julien Danjou <julien@danjou.info>
+Kieran Spear <kispear@gmail.com>
+Kui Shi <skuicloud@gmail.com>
+Lan Qi song <lqslan@cn.ibm.com>
+Lena Novokshonova <enovokshonova@mirantis.com>
+Lianhao Lu <lianhao.lu@intel.com>
+LiuNanke <nanke.liu@easystack.cn>
+Luong Anh Tuan <tuanla@vn.fujitsu.com>
+Marc Solanas <msolanas@cisco.com>
+Martin Geisler <martin@geisler.net>
+Matthew Edmonds <edmondsw@us.ibm.com>
+Mehdi Abaakouk <mehdi.abaakouk@enovance.com>
+Mehdi Abaakouk <sileht@redhat.com>
+Michał Jastrzębski <inc007@gmail.com>
+Monty Taylor <mordred@inaugust.com>
+Nejc Saje <nejc.saje@xlab.si>
+Nejc Saje <nsaje@redhat.com>
+Noorul Islam K M <noorul@noorul.com>
+Ondřej Nový <ondrej.novy@firma.seznam.cz>
+OpenStack Release Bot <infra-root@openstack.org>
+Pavlo Shchelokovskyy <pshchelokovskyy@mirantis.com>
+Pradeep Kilambi <pkilambi@cisco.com>
+Pradeep Kilambi <pkilambi@redhat.com>
+Prateek Khushalani <prateek.khushalani@gmail.com>
+Rafael Rivero <rafael@cloudscaling.com>
+Rohit Jaiswal <rohit.jaiswal@hp.com>
+Roman Vasilets <rvasilets@mirantis.com>
+Rui Chen <chenrui.momo@gmail.com>
+Ryota MIBU <r-mibu@cq.jp.nec.com>
+Sanjana Pai <sanjana@hitachi.co.in>
+Sascha Peilicke <speilicke@suse.com>
+Shuquan Huang <huang.shuquan@99cloud.net>
+Srinivas Sakhamuri <srinivas.sakhamuri@hp.com>
+Stefano Zilli <stefano.zilli@cern.ch>
+Steve Martinelli <s.martinelli@gmail.com>
+Steve Martinelli <stevemar@ca.ibm.com>
+Steve Wilkerson <sw5822@att.com>
+Stéphane Albert <stephane.albert@objectif-libre.com>
+Sushil Kumar <sushil.kumar2@globallogic.com>
+Swapnil Kulkarni (coolsvap) <me@coolsvap.net>
+Thomas Herve <thomas.herve@enovance.com>
+Tong Li <litong01@us.ibm.com>
+Tony Breeds <tony@bakeyournoodle.com>
+Uros Jovanovic <uros.jovanovic@gmail.com>
+Victor Morales <victor.morales@intel.com>
+Wu Wenxiang <wu.wenxiang@99cloud.net>
+Zhi Kun Liu <zhikunli@cn.ibm.com>
+ZhiQiang Fan <aji.zqfan@gmail.com>
+ZhiQiang Fan <zhiqiang.fan@huawei.com>
+akanksha <akanksha.mehrotra@hpe.com>
+april <xiaolixu@cn.ibm.com>
+aviau <alexandre.viau@savoirfairelinux.com>
+chenxiao <chenxiao@cn.ibm.com>
+ekudryashova <ekudryashova@mirantis.com>
+fujioka yuuichi <fujioka-yuuichi@zx.mxh.nes.nec.co.jp>
+gecong1973 <ge.cong@zte.com.cn>
+gord chung <gord@live.ca>
+gordon chung <gord@live.ca>
+hexin <hxhehx@cn.ibm.com>
+joey5678 <jiadong.jia@huawei.com>
+liu-sheng <liusheng@huawei.com>
+liuqing <jing.liuqing@99cloud.net>
+liusheng <liusheng@huawei.com>
+llg8212 <lilinguo@huawei.com>
+ls1175 <liusheng@huawei.com>
+luqitao <qtlu@fiberhome.com>
+rabi <ramishra@redhat.com>
+raiesmh08 <raiesmh08@gmail.com>
+ricolin <rico.l@inwinstack.com>
+sanjana <sanjana@hitachi.co.in>
+shu-mutou <shu-mutou@rf.jp.nec.com>
+tuathail <ciaran.otuathail@hp.com>
+venkatamahesh <venkatamaheshkotha@gmail.com>
+xialinjuan <ljxiash@cn.ibm.com>
+xiangjun li <lixiangjun@cn.fujitsu.com>
+xiaozhuangqing <zhuangqing.xiao@easystack.cn>
+yolanda.robla <yolanda.robla@canonical.com>
+yuyafei <yu.yafei@zte.com.cn>
+zhangguoqing <zhang.guoqing@99cloud.net>
+zhangjianfeng <kill51216@163.com>
diff -pruN 2.6.2-1/ceilometerclient/apiclient/auth.py 2.9.0-0ubuntu4/ceilometerclient/apiclient/auth.py
--- 2.6.2-1/ceilometerclient/apiclient/auth.py	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/apiclient/auth.py	2017-06-12 13:24:31.000000000 +0000
@@ -0,0 +1,231 @@
+# Copyright 2013 OpenStack Foundation
+# Copyright 2013 Spanish National Research Council.
+# 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.
+
+# E0202: An attribute inherited from %s hide this method
+# pylint: disable=E0202
+
+########################################################################
+#
+# THIS MODULE IS DEPRECATED
+#
+# Please refer to
+# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
+# the discussion leading to this deprecation.
+#
+# We recommend checking out the python-openstacksdk project
+# (https://launchpad.net/python-openstacksdk) instead.
+#
+########################################################################
+
+import abc
+import argparse
+import os
+
+import six
+from stevedore import extension
+
+from ceilometerclient.apiclient import exceptions
+
+
+_discovered_plugins = {}
+
+
+def discover_auth_systems():
+    """Discover the available auth-systems.
+
+    This won't take into account the old style auth-systems.
+    """
+    global _discovered_plugins
+    _discovered_plugins = {}
+
+    def add_plugin(ext):
+        _discovered_plugins[ext.name] = ext.plugin
+
+    ep_namespace = "ceilometerclient.apiclient.auth"
+    mgr = extension.ExtensionManager(ep_namespace)
+    mgr.map(add_plugin)
+
+
+def load_auth_system_opts(parser):
+    """Load options needed by the available auth-systems into a parser.
+
+    This function will try to populate the parser with options from the
+    available plugins.
+    """
+    group = parser.add_argument_group("Common auth options")
+    BaseAuthPlugin.add_common_opts(group)
+    for name, auth_plugin in six.iteritems(_discovered_plugins):
+        group = parser.add_argument_group(
+            "Auth-system '%s' options" % name,
+            conflict_handler="resolve")
+        auth_plugin.add_opts(group)
+
+
+def load_plugin(auth_system):
+    try:
+        plugin_class = _discovered_plugins[auth_system]
+    except KeyError:
+        raise exceptions.AuthSystemNotFound(auth_system)
+    return plugin_class(auth_system=auth_system)
+
+
+def load_plugin_from_args(args):
+    """Load required plugin and populate it with options.
+
+    Try to guess auth system if it is not specified. Systems are tried in
+    alphabetical order.
+
+    :type args: argparse.Namespace
+    :raises: AuthPluginOptionsMissing
+    """
+    auth_system = args.os_auth_system
+    if auth_system:
+        plugin = load_plugin(auth_system)
+        plugin.parse_opts(args)
+        plugin.sufficient_options()
+        return plugin
+
+    for plugin_auth_system in sorted(six.iterkeys(_discovered_plugins)):
+        plugin_class = _discovered_plugins[plugin_auth_system]
+        plugin = plugin_class()
+        plugin.parse_opts(args)
+        try:
+            plugin.sufficient_options()
+        except exceptions.AuthPluginOptionsMissing:
+            continue
+        return plugin
+    raise exceptions.AuthPluginOptionsMissing(["auth_system"])
+
+
+@six.add_metaclass(abc.ABCMeta)
+class BaseAuthPlugin(object):
+    """Base class for authentication plugins.
+
+    An authentication plugin needs to override at least the authenticate
+    method to be a valid plugin.
+    """
+
+    auth_system = None
+    opt_names = []
+    common_opt_names = [
+        "auth_system",
+        "username",
+        "password",
+        "tenant_name",
+        "token",
+        "auth_url",
+    ]
+
+    def __init__(self, auth_system=None, **kwargs):
+        self.auth_system = auth_system or self.auth_system
+        self.opts = dict((name, kwargs.get(name))
+                         for name in self.opt_names)
+
+    @staticmethod
+    def _parser_add_opt(parser, opt):
+        """Add an option to parser in two variants.
+
+        :param opt: option name (with underscores)
+        """
+        dashed_opt = opt.replace("_", "-")
+        env_var = "OS_%s" % opt.upper()
+        arg_default = os.environ.get(env_var, "")
+        arg_help = "Defaults to env[%s]." % env_var
+        parser.add_argument(
+            "--os-%s" % dashed_opt,
+            metavar="<%s>" % dashed_opt,
+            default=arg_default,
+            help=arg_help)
+        parser.add_argument(
+            "--os_%s" % opt,
+            metavar="<%s>" % dashed_opt,
+            help=argparse.SUPPRESS)
+
+    @classmethod
+    def add_opts(cls, parser):
+        """Populate the parser with the options for this plugin."""
+        for opt in cls.opt_names:
+            # use `BaseAuthPlugin.common_opt_names` since it is never
+            # changed in child classes
+            if opt not in BaseAuthPlugin.common_opt_names:
+                cls._parser_add_opt(parser, opt)
+
+    @classmethod
+    def add_common_opts(cls, parser):
+        """Add options that are common for several plugins."""
+        for opt in cls.common_opt_names:
+            cls._parser_add_opt(parser, opt)
+
+    @staticmethod
+    def get_opt(opt_name, args):
+        """Return option name and value.
+
+        :param opt_name: name of the option, e.g., "username"
+        :param args: parsed arguments
+        """
+        return (opt_name, getattr(args, "os_%s" % opt_name, None))
+
+    def parse_opts(self, args):
+        """Parse the actual auth-system options if any.
+
+        This method is expected to populate the attribute `self.opts` with a
+        dict containing the options and values needed to make authentication.
+        """
+        self.opts.update(dict(self.get_opt(opt_name, args)
+                              for opt_name in self.opt_names))
+
+    def authenticate(self, http_client):
+        """Authenticate using plugin defined method.
+
+        The method usually analyses `self.opts` and performs
+        a request to authentication server.
+
+        :param http_client: client object that needs authentication
+        :type http_client: HTTPClient
+        :raises: AuthorizationFailure
+        """
+        self.sufficient_options()
+        self._do_authenticate(http_client)
+
+    @abc.abstractmethod
+    def _do_authenticate(self, http_client):
+        """Protected method for authentication."""
+
+    def sufficient_options(self):
+        """Check if all required options are present.
+
+        :raises: AuthPluginOptionsMissing
+        """
+        missing = [opt
+                   for opt in self.opt_names
+                   if not self.opts.get(opt)]
+        if missing:
+            raise exceptions.AuthPluginOptionsMissing(missing)
+
+    @abc.abstractmethod
+    def token_and_endpoint(self, endpoint_type, service_type):
+        """Return token and endpoint.
+
+        :param service_type: Service type of the endpoint
+        :type service_type: string
+        :param endpoint_type: Type of endpoint.
+                              Possible values: public or publicURL,
+                              internal or internalURL,
+                              admin or adminURL
+        :type endpoint_type: string
+        :returns: tuple of token and endpoint strings
+        :raises: EndpointException
+        """
diff -pruN 2.6.2-1/ceilometerclient/apiclient/base.py 2.9.0-0ubuntu4/ceilometerclient/apiclient/base.py
--- 2.6.2-1/ceilometerclient/apiclient/base.py	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/apiclient/base.py	2017-06-12 13:24:31.000000000 +0000
@@ -0,0 +1,535 @@
+# Copyright 2010 Jacob Kaplan-Moss
+# Copyright 2011 OpenStack Foundation
+# Copyright 2012 Grid Dynamics
+# Copyright 2013 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.
+
+"""
+Base utilities to build API operation managers and objects on top of.
+"""
+
+########################################################################
+#
+# THIS MODULE IS DEPRECATED
+#
+# Please refer to
+# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
+# the discussion leading to this deprecation.
+#
+# We recommend checking out the python-openstacksdk project
+# (https://launchpad.net/python-openstacksdk) instead.
+#
+########################################################################
+
+
+# E1102: %s is not callable
+# pylint: disable=E1102
+
+import abc
+import copy
+
+from oslo_utils import reflection
+from oslo_utils import strutils
+import six
+from six.moves.urllib import parse
+
+from ceilometerclient.apiclient import exceptions
+from ceilometerclient.i18n import _
+
+
+def getid(obj):
+    """Return id if argument is a Resource.
+
+    Abstracts the common pattern of allowing both an object or an object's ID
+    (UUID) as a parameter when dealing with relationships.
+    """
+    try:
+        if obj.uuid:
+            return obj.uuid
+    except AttributeError:
+        pass
+    try:
+        return obj.id
+    except AttributeError:
+        return obj
+
+
+# TODO(aababilov): call run_hooks() in HookableMixin's child classes
+class HookableMixin(object):
+    """Mixin so classes can register and run hooks."""
+    _hooks_map = {}
+
+    @classmethod
+    def add_hook(cls, hook_type, hook_func):
+        """Add a new hook of specified type.
+
+        :param cls: class that registers hooks
+        :param hook_type: hook type, e.g., '__pre_parse_args__'
+        :param hook_func: hook function
+        """
+        if hook_type not in cls._hooks_map:
+            cls._hooks_map[hook_type] = []
+
+        cls._hooks_map[hook_type].append(hook_func)
+
+    @classmethod
+    def run_hooks(cls, hook_type, *args, **kwargs):
+        """Run all hooks of specified type.
+
+        :param cls: class that registers hooks
+        :param hook_type: hook type, e.g., '__pre_parse_args__'
+        :param args: args to be passed to every hook function
+        :param kwargs: kwargs to be passed to every hook function
+        """
+        hook_funcs = cls._hooks_map.get(hook_type) or []
+        for hook_func in hook_funcs:
+            hook_func(*args, **kwargs)
+
+
+class BaseManager(HookableMixin):
+    """Basic manager type providing common operations.
+
+    Managers interact with a particular type of API (servers, flavors, images,
+    etc.) and provide CRUD operations for them.
+    """
+    resource_class = None
+
+    def __init__(self, client):
+        """Initializes BaseManager with `client`.
+
+        :param client: instance of BaseClient descendant for HTTP requests
+        """
+        super(BaseManager, self).__init__()
+        self.client = client
+
+    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'. 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
+            request (GET will be sent by default)
+        """
+        if json:
+            body = self.client.post(url, json=json).json()
+        else:
+            body = self.client.get(url).json()
+
+        if obj_class is None:
+            obj_class = self.resource_class
+
+        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:
+            data = data['values']
+        except (KeyError, TypeError):
+            pass
+
+        return [obj_class(self, res, loaded=True) for res in data if res]
+
+    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'. If response_key is None - all response body
+            will be used.
+        """
+        body = self.client.get(url).json()
+        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.
+
+        :param url: a partial URL, e.g., '/servers'
+        """
+        resp = self.client.head(url)
+        return resp.status_code == 204
+
+    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., '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 data
+        return self.resource_class(self, data)
+
+    def _put(self, url, json=None, response_key=None):
+        """Update an object with PUT method.
+
+        :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'. 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
+        if resp.content:
+            body = resp.json()
+            if response_key is not None:
+                return self.resource_class(self, body[response_key])
+            else:
+                return self.resource_class(self, body)
+
+    def _patch(self, url, json=None, response_key=None):
+        """Update an object with PATCH method.
+
+        :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'. 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:
+            return self.resource_class(self, body[response_key])
+        else:
+            return self.resource_class(self, body)
+
+    def _delete(self, url):
+        """Delete an object.
+
+        :param url: a partial URL, e.g., '/servers/my-server'
+        """
+        return self.client.delete(url)
+
+
+@six.add_metaclass(abc.ABCMeta)
+class ManagerWithFind(BaseManager):
+    """Manager with additional `find()`/`findall()` methods."""
+
+    @abc.abstractmethod
+    def list(self):
+        pass
+
+    def find(self, **kwargs):
+        """Find a single item with attributes matching ``**kwargs``.
+
+        This isn't very efficient: it loads the entire list then filters on
+        the Python side.
+        """
+        matches = self.findall(**kwargs)
+        num_matches = len(matches)
+        if num_matches == 0:
+            msg = _("No %(name)s matching %(args)s.") % {
+                'name': self.resource_class.__name__,
+                'args': kwargs
+            }
+            raise exceptions.NotFound(msg)
+        elif num_matches > 1:
+            raise exceptions.NoUniqueMatch()
+        else:
+            return matches[0]
+
+    def findall(self, **kwargs):
+        """Find all items with attributes matching ``**kwargs``.
+
+        This isn't very efficient: it loads the entire list then filters on
+        the Python side.
+        """
+        found = []
+        searches = kwargs.items()
+
+        for obj in self.list():
+            try:
+                if all(getattr(obj, attr) == value
+                       for (attr, value) in searches):
+                    found.append(obj)
+            except AttributeError:
+                continue
+
+        return found
+
+
+class CrudManager(BaseManager):
+    """Base manager class for manipulating entities.
+
+    Children of this class are expected to define a `collection_key` and `key`.
+
+    - `collection_key`: Usually a plural noun by convention (e.g. `entities`);
+      used to refer collections in both URL's (e.g.  `/v3/entities`) and JSON
+      objects containing a list of member resources (e.g. `{'entities': [{},
+      {}, {}]}`).
+    - `key`: Usually a singular noun by convention (e.g. `entity`); used to
+      refer to an individual member of the collection.
+
+    """
+    collection_key = None
+    key = None
+
+    def build_url(self, base_url=None, **kwargs):
+        """Builds a resource URL for the given kwargs.
+
+        Given an example collection where `collection_key = 'entities'` and
+        `key = 'entity'`, the following URL's could be generated.
+
+        By default, the URL will represent a collection of entities, e.g.::
+
+            /entities
+
+        If kwargs contains an `entity_id`, then the URL will represent a
+        specific member, e.g.::
+
+            /entities/{entity_id}
+
+        :param base_url: if provided, the generated URL will be appended to it
+        """
+        url = base_url if base_url is not None else ''
+
+        url += '/%s' % self.collection_key
+
+        # do we have a specific entity?
+        entity_id = kwargs.get('%s_id' % self.key)
+        if entity_id is not None:
+            url += '/%s' % entity_id
+
+        return url
+
+    def _filter_kwargs(self, kwargs):
+        """Drop null values and handle ids."""
+        for key, ref in six.iteritems(kwargs.copy()):
+            if ref is None:
+                kwargs.pop(key)
+            else:
+                if isinstance(ref, Resource):
+                    kwargs.pop(key)
+                    kwargs['%s_id' % key] = getid(ref)
+        return kwargs
+
+    def create(self, **kwargs):
+        kwargs = self._filter_kwargs(kwargs)
+        return self._post(
+            self.build_url(**kwargs),
+            {self.key: kwargs},
+            self.key)
+
+    def get(self, **kwargs):
+        kwargs = self._filter_kwargs(kwargs)
+        return self._get(
+            self.build_url(**kwargs),
+            self.key)
+
+    def head(self, **kwargs):
+        kwargs = self._filter_kwargs(kwargs)
+        return self._head(self.build_url(**kwargs))
+
+    def list(self, base_url=None, **kwargs):
+        """List the collection.
+
+        :param base_url: if provided, the generated URL will be appended to it
+        """
+        kwargs = self._filter_kwargs(kwargs)
+
+        return self._list(
+            '%(base_url)s%(query)s' % {
+                'base_url': self.build_url(base_url=base_url, **kwargs),
+                'query': '?%s' % parse.urlencode(kwargs) if kwargs else '',
+            },
+            self.collection_key)
+
+    def put(self, base_url=None, **kwargs):
+        """Update an element.
+
+        :param base_url: if provided, the generated URL will be appended to it
+        """
+        kwargs = self._filter_kwargs(kwargs)
+
+        return self._put(self.build_url(base_url=base_url, **kwargs))
+
+    def update(self, **kwargs):
+        kwargs = self._filter_kwargs(kwargs)
+        params = kwargs.copy()
+        params.pop('%s_id' % self.key)
+
+        return self._patch(
+            self.build_url(**kwargs),
+            {self.key: params},
+            self.key)
+
+    def delete(self, **kwargs):
+        kwargs = self._filter_kwargs(kwargs)
+
+        return self._delete(
+            self.build_url(**kwargs))
+
+    def find(self, base_url=None, **kwargs):
+        """Find a single item with attributes matching ``**kwargs``.
+
+        :param base_url: if provided, the generated URL will be appended to it
+        """
+        kwargs = self._filter_kwargs(kwargs)
+
+        rl = self._list(
+            '%(base_url)s%(query)s' % {
+                'base_url': self.build_url(base_url=base_url, **kwargs),
+                'query': '?%s' % parse.urlencode(kwargs) if kwargs else '',
+            },
+            self.collection_key)
+        num = len(rl)
+
+        if num == 0:
+            msg = _("No %(name)s matching %(args)s.") % {
+                'name': self.resource_class.__name__,
+                'args': kwargs
+            }
+            raise exceptions.NotFound(404, msg)
+        elif num > 1:
+            raise exceptions.NoUniqueMatch
+        else:
+            return rl[0]
+
+
+class Extension(HookableMixin):
+    """Extension descriptor."""
+
+    SUPPORTED_HOOKS = ('__pre_parse_args__', '__post_parse_args__')
+    manager_class = None
+
+    def __init__(self, name, module):
+        super(Extension, self).__init__()
+        self.name = name
+        self.module = module
+        self._parse_extension_module()
+
+    def _parse_extension_module(self):
+        self.manager_class = None
+        for attr_name, attr_value in self.module.__dict__.items():
+            if attr_name in self.SUPPORTED_HOOKS:
+                self.add_hook(attr_name, attr_value)
+            else:
+                try:
+                    if issubclass(attr_value, BaseManager):
+                        self.manager_class = attr_value
+                except TypeError:
+                    pass
+
+    def __repr__(self):
+        return "<Extension '%s'>" % self.name
+
+
+class Resource(object):
+    """Base class for OpenStack resources (tenant, user, etc.).
+
+    This is pretty much just a bag for attributes.
+    """
+
+    HUMAN_ID = False
+    NAME_ATTR = 'name'
+
+    def __init__(self, manager, info, loaded=False):
+        """Populate and bind to a manager.
+
+        :param manager: BaseManager object
+        :param info: dictionary representing resource attributes
+        :param loaded: prevent lazy-loading if set to True
+        """
+        self.manager = manager
+        self._info = info
+        self._add_details(info)
+        self._loaded = loaded
+
+    def __repr__(self):
+        reprkeys = sorted(k
+                          for k in self.__dict__.keys()
+                          if k[0] != '_' and k != 'manager')
+        info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys)
+        self_cls_name = reflection.get_class_name(self,
+                                                  fully_qualified=False)
+        return "<%s %s>" % (self_cls_name, info)
+
+    @property
+    def human_id(self):
+        """Human-readable ID which can be used for bash completion."""
+        if self.HUMAN_ID:
+            name = getattr(self, self.NAME_ATTR, None)
+            if name is not None:
+                return strutils.to_slug(name)
+        return None
+
+    def _add_details(self, info):
+        for (k, v) in six.iteritems(info):
+            try:
+                setattr(self, k, v)
+                self._info[k] = v
+            except AttributeError:
+                # In this case we already defined the attribute on the class
+                pass
+
+    def __getattr__(self, k):
+        if k not in self.__dict__:
+            # NOTE(bcwaldon): disallow lazy-loading if already loaded once
+            if not self.is_loaded():
+                self.get()
+                return self.__getattr__(k)
+
+            raise AttributeError(k)
+        else:
+            return self.__dict__[k]
+
+    def get(self):
+        """Support for lazy loading details.
+
+        Some clients, such as novaclient have the option to lazy load the
+        details, details which can be loaded with this function.
+        """
+        # set_loaded() first ... so if we have to bail, we know we tried.
+        self.set_loaded(True)
+        if not hasattr(self.manager, 'get'):
+            return
+
+        new = self.manager.get(self.id)
+        if new:
+            self._add_details(new._info)
+            self._add_details(
+                {'x_request_id': self.manager.client.last_request_id})
+
+    def __eq__(self, other):
+        if not isinstance(other, Resource):
+            return NotImplemented
+        # two resources of different types are not equal
+        if not isinstance(other, self.__class__):
+            return False
+        return self._info == other._info
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def is_loaded(self):
+        return self._loaded
+
+    def set_loaded(self, val):
+        self._loaded = val
+
+    def to_dict(self):
+        return copy.deepcopy(self._info)
diff -pruN 2.6.2-1/ceilometerclient/apiclient/client.py 2.9.0-0ubuntu4/ceilometerclient/apiclient/client.py
--- 2.6.2-1/ceilometerclient/apiclient/client.py	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/apiclient/client.py	2017-06-12 13:24:31.000000000 +0000
@@ -0,0 +1,388 @@
+# Copyright 2010 Jacob Kaplan-Moss
+# Copyright 2011 OpenStack Foundation
+# Copyright 2011 Piston Cloud Computing, Inc.
+# Copyright 2013 Alessio Ababilov
+# Copyright 2013 Grid Dynamics
+# Copyright 2013 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.
+
+"""
+OpenStack Client interface. Handles the REST calls and responses.
+"""
+
+# E0202: An attribute inherited from %s hide this method
+# pylint: disable=E0202
+
+import hashlib
+import logging
+import time
+
+try:
+    import simplejson as json
+except ImportError:
+    import json
+
+from oslo_utils import encodeutils
+from oslo_utils import importutils
+import requests
+
+from ceilometerclient.apiclient import exceptions
+from ceilometerclient.i18n import _
+
+_logger = logging.getLogger(__name__)
+SENSITIVE_HEADERS = ('X-Auth-Token', 'X-Subject-Token',)
+
+
+class HTTPClient(object):
+    """This client handles sending HTTP requests to OpenStack servers.
+
+    Features:
+
+    - share authentication information between several clients to different
+      services (e.g., for compute and image clients);
+    - reissue authentication request for expired tokens;
+    - encode/decode JSON bodies;
+    - raise exceptions on HTTP errors;
+    - pluggable authentication;
+    - store authentication information in a keyring;
+    - store time spent for requests;
+    - register clients for particular services, so one can use
+      `http_client.identity` or `http_client.compute`;
+    - log requests and responses in a format that is easy to copy-and-paste
+      into terminal and send the same request with curl.
+    """
+
+    user_agent = "ceilometerclient.apiclient"
+
+    def __init__(self,
+                 auth_plugin,
+                 region_name=None,
+                 endpoint_type="publicURL",
+                 original_ip=None,
+                 verify=True,
+                 cert=None,
+                 timeout=None,
+                 timings=False,
+                 keyring_saver=None,
+                 debug=False,
+                 user_agent=None,
+                 http=None):
+        self.auth_plugin = auth_plugin
+
+        self.endpoint_type = endpoint_type
+        self.region_name = region_name
+
+        self.original_ip = original_ip
+        self.timeout = timeout
+        self.verify = verify
+        self.cert = cert
+
+        self.keyring_saver = keyring_saver
+        self.debug = debug
+        self.user_agent = user_agent or self.user_agent
+
+        self.times = []  # [("item", starttime, endtime), ...]
+        self.timings = timings
+
+        # requests within the same session can reuse TCP connections from pool
+        self.http = http or requests.Session()
+
+        self.cached_token = None
+        self.last_request_id = None
+
+    def _safe_header(self, name, value):
+        if name in SENSITIVE_HEADERS:
+            # because in python3 byte string handling is ... ug
+            v = value.encode('utf-8')
+            h = hashlib.sha1(v)
+            d = h.hexdigest()
+            return encodeutils.safe_decode(name), "{SHA1}%s" % d
+        else:
+            return (encodeutils.safe_decode(name),
+                    encodeutils.safe_decode(value))
+
+    def _http_log_req(self, method, url, kwargs):
+        if not self.debug:
+            return
+
+        string_parts = [
+            "curl -g -i",
+            "-X '%s'" % method,
+            "'%s'" % url,
+        ]
+
+        for element in kwargs['headers']:
+            header = ("-H '%s: %s'" %
+                      self._safe_header(element, kwargs['headers'][element]))
+            string_parts.append(header)
+
+        _logger.debug("REQ: %s", " ".join(string_parts))
+        if 'data' in kwargs:
+            _logger.debug("REQ BODY: %s\n", kwargs['data'])
+
+    def _http_log_resp(self, resp):
+        if not self.debug:
+            return
+        _logger.debug(
+            "RESP: [%s] %s\n",
+            resp.status_code,
+            resp.headers)
+        if resp._content_consumed:
+            _logger.debug(
+                "RESP BODY: %s\n",
+                resp.text)
+
+    def serialize(self, kwargs):
+        if kwargs.get('json') is not None:
+            kwargs['headers']['Content-Type'] = 'application/json'
+            kwargs['data'] = json.dumps(kwargs['json'])
+        try:
+            del kwargs['json']
+        except KeyError:
+            pass
+
+    def get_timings(self):
+        return self.times
+
+    def reset_timings(self):
+        self.times = []
+
+    def request(self, method, url, **kwargs):
+        """Send an http request with the specified characteristics.
+
+        Wrapper around `requests.Session.request` to handle tasks such as
+        setting headers, JSON encoding/decoding, and error handling.
+
+        :param method: method of HTTP request
+        :param url: URL of HTTP request
+        :param kwargs: any other parameter that can be passed to
+             requests.Session.request (such as `headers`) or `json`
+             that will be encoded as JSON and used as `data` argument
+        """
+        kwargs.setdefault("headers", {})
+        kwargs["headers"]["User-Agent"] = self.user_agent
+        if self.original_ip:
+            kwargs["headers"]["Forwarded"] = "for=%s;by=%s" % (
+                self.original_ip, self.user_agent)
+        if self.timeout is not None:
+            kwargs.setdefault("timeout", self.timeout)
+        kwargs.setdefault("verify", self.verify)
+        if self.cert is not None:
+            kwargs.setdefault("cert", self.cert)
+        self.serialize(kwargs)
+
+        self._http_log_req(method, url, kwargs)
+        if self.timings:
+            start_time = time.time()
+        resp = self.http.request(method, url, **kwargs)
+        if self.timings:
+            self.times.append(("%s %s" % (method, url),
+                               start_time, time.time()))
+        self._http_log_resp(resp)
+
+        self.last_request_id = resp.headers.get('x-openstack-request-id')
+
+        if resp.status_code >= 400:
+            _logger.debug(
+                "Request returned failure status: %s",
+                resp.status_code)
+            raise exceptions.from_response(resp, method, url)
+
+        return resp
+
+    @staticmethod
+    def concat_url(endpoint, url):
+        """Concatenate endpoint and final URL.
+
+        E.g., "http://keystone/v2.0/" and "/tokens" are concatenated to
+        "http://keystone/v2.0/tokens".
+
+        :param endpoint: the base URL
+        :param url: the final URL
+        """
+        return "%s/%s" % (endpoint.rstrip("/"), url.strip("/"))
+
+    def client_request(self, client, method, url, **kwargs):
+        """Send an http request using `client`'s endpoint and specified `url`.
+
+        If request was rejected as unauthorized (possibly because the token is
+        expired), issue one authorization attempt and send the request once
+        again.
+
+        :param client: instance of BaseClient descendant
+        :param method: method of HTTP request
+        :param url: URL of HTTP request
+        :param kwargs: any other parameter that can be passed to
+            `HTTPClient.request`
+        """
+
+        filter_args = {
+            "endpoint_type": client.endpoint_type or self.endpoint_type,
+            "service_type": client.service_type,
+        }
+        token, endpoint = (self.cached_token, client.cached_endpoint)
+        just_authenticated = False
+        if not (token and endpoint):
+            try:
+                token, endpoint = self.auth_plugin.token_and_endpoint(
+                    **filter_args)
+            except exceptions.EndpointException:
+                pass
+            if not (token and endpoint):
+                self.authenticate()
+                just_authenticated = True
+                token, endpoint = self.auth_plugin.token_and_endpoint(
+                    **filter_args)
+                if not (token and endpoint):
+                    raise exceptions.AuthorizationFailure(
+                        _("Cannot find endpoint or token for request"))
+
+        old_token_endpoint = (token, endpoint)
+        kwargs.setdefault("headers", {})["X-Auth-Token"] = token
+        self.cached_token = token
+        client.cached_endpoint = endpoint
+        # Perform the request once. If we get Unauthorized, then it
+        # might be because the auth token expired, so try to
+        # re-authenticate and try again. If it still fails, bail.
+        try:
+            return self.request(
+                method, self.concat_url(endpoint, url), **kwargs)
+        except exceptions.Unauthorized as unauth_ex:
+            if just_authenticated:
+                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(
+                    **filter_args)
+            except exceptions.EndpointException:
+                raise unauth_ex
+            if (not (token and endpoint) or
+                    old_token_endpoint == (token, endpoint)):
+                raise unauth_ex
+            self.cached_token = token
+            client.cached_endpoint = endpoint
+            kwargs["headers"]["X-Auth-Token"] = token
+            return self.request(
+                method, self.concat_url(endpoint, url), **kwargs)
+
+    def add_client(self, base_client_instance):
+        """Add a new instance of :class:`BaseClient` descendant.
+
+        `self` will store a reference to `base_client_instance`.
+
+        Example:
+
+        >>> def test_clients():
+        ...     from keystoneclient.auth import keystone
+        ...     from openstack.common.apiclient import client
+        ...     auth = keystone.KeystoneAuthPlugin(
+        ...         username="user", password="pass", tenant_name="tenant",
+        ...         auth_url="http://auth:5000/v2.0")
+        ...     openstack_client = client.HTTPClient(auth)
+        ...     # create nova client
+        ...     from novaclient.v1_1 import client
+        ...     client.Client(openstack_client)
+        ...     # create keystone client
+        ...     from keystoneclient.v2_0 import client
+        ...     client.Client(openstack_client)
+        ...     # use them
+        ...     openstack_client.identity.tenants.list()
+        ...     openstack_client.compute.servers.list()
+        """
+        service_type = base_client_instance.service_type
+        if service_type and not hasattr(self, service_type):
+            setattr(self, service_type, base_client_instance)
+
+    def authenticate(self):
+        self.auth_plugin.authenticate(self)
+        # Store the authentication results in the keyring for later requests
+        if self.keyring_saver:
+            self.keyring_saver.save(self)
+
+
+class BaseClient(object):
+    """Top-level object to access the OpenStack API.
+
+    This client uses :class:`HTTPClient` to send requests. :class:`HTTPClient`
+    will handle a bunch of issues such as authentication.
+    """
+
+    service_type = None
+    endpoint_type = None  # "publicURL" will be used
+    cached_endpoint = None
+
+    def __init__(self, http_client, extensions=None):
+        self.http_client = http_client
+        http_client.add_client(self)
+
+        # Add in any extensions...
+        if extensions:
+            for extension in extensions:
+                if extension.manager_class:
+                    setattr(self, extension.name,
+                            extension.manager_class(self))
+
+    def client_request(self, method, url, **kwargs):
+        return self.http_client.client_request(
+            self, method, url, **kwargs)
+
+    @property
+    def last_request_id(self):
+        return self.http_client.last_request_id
+
+    def head(self, url, **kwargs):
+        return self.client_request("HEAD", url, **kwargs)
+
+    def get(self, url, **kwargs):
+        return self.client_request("GET", url, **kwargs)
+
+    def post(self, url, **kwargs):
+        return self.client_request("POST", url, **kwargs)
+
+    def put(self, url, **kwargs):
+        return self.client_request("PUT", url, **kwargs)
+
+    def delete(self, url, **kwargs):
+        return self.client_request("DELETE", url, **kwargs)
+
+    def patch(self, url, **kwargs):
+        return self.client_request("PATCH", url, **kwargs)
+
+    @staticmethod
+    def get_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 %(api_name)s client version '%(version)s'. "
+                    "Must be one of: %(version_map)s") % {
+                        'api_name': api_name,
+                        'version': version,
+                        'version_map': ', '.join(version_map.keys())}
+            raise exceptions.UnsupportedVersion(msg)
+
+        return importutils.import_class(client_path)
diff -pruN 2.6.2-1/ceilometerclient/apiclient/exceptions.py 2.9.0-0ubuntu4/ceilometerclient/apiclient/exceptions.py
--- 2.6.2-1/ceilometerclient/apiclient/exceptions.py	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/apiclient/exceptions.py	2017-06-12 13:24:31.000000000 +0000
@@ -0,0 +1,477 @@
+# Copyright 2010 Jacob Kaplan-Moss
+# Copyright 2011 Nebula, Inc.
+# Copyright 2013 Alessio Ababilov
+# Copyright 2013 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.
+
+"""
+Exception definitions.
+"""
+
+########################################################################
+#
+# THIS MODULE IS DEPRECATED
+#
+# Please refer to
+# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
+# the discussion leading to this deprecation.
+#
+# We recommend checking out the python-openstacksdk project
+# (https://launchpad.net/python-openstacksdk) instead.
+#
+########################################################################
+
+import inspect
+import sys
+
+import six
+
+from ceilometerclient.i18n import _
+
+
+class ClientException(Exception):
+    """The base exception class for all exceptions this library raises."""
+    pass
+
+
+class ValidationError(ClientException):
+    """Error in validation on API client side."""
+    pass
+
+
+class UnsupportedVersion(ClientException):
+    """User is trying to use an unsupported version of the API."""
+    pass
+
+
+class CommandError(ClientException):
+    """Error in CLI tool."""
+    pass
+
+
+class AuthorizationFailure(ClientException):
+    """Cannot authorize API client."""
+    pass
+
+
+class ConnectionError(ClientException):
+    """Cannot connect to API service."""
+    pass
+
+
+class ConnectionRefused(ConnectionError):
+    """Connection refused while trying to connect to API service."""
+    pass
+
+
+class AuthPluginOptionsMissing(AuthorizationFailure):
+    """Auth plugin misses some options."""
+    def __init__(self, opt_names):
+        super(AuthPluginOptionsMissing, self).__init__(
+            _("Authentication failed. Missing options: %s") %
+            ", ".join(opt_names))
+        self.opt_names = opt_names
+
+
+class AuthSystemNotFound(AuthorizationFailure):
+    """User has specified an AuthSystem that is not installed."""
+    def __init__(self, auth_system):
+        super(AuthSystemNotFound, self).__init__(
+            _("AuthSystemNotFound: %s") % repr(auth_system))
+        self.auth_system = auth_system
+
+
+class NoUniqueMatch(ClientException):
+    """Multiple entities found instead of one."""
+    pass
+
+
+class EndpointException(ClientException):
+    """Something is rotten in Service Catalog."""
+    pass
+
+
+class EndpointNotFound(EndpointException):
+    """Could not find requested endpoint in Service Catalog."""
+    pass
+
+
+class AmbiguousEndpoints(EndpointException):
+    """Found more than one matching endpoint in Service Catalog."""
+    def __init__(self, endpoints=None):
+        super(AmbiguousEndpoints, self).__init__(
+            _("AmbiguousEndpoints: %s") % repr(endpoints))
+        self.endpoints = endpoints
+
+
+class HttpError(ClientException):
+    """The base exception class for all HTTP exceptions."""
+    http_status = 0
+    message = _("HTTP Error")
+
+    def __init__(self, message=None, details=None,
+                 response=None, request_id=None,
+                 url=None, method=None, http_status=None):
+        self.http_status = http_status or self.http_status
+        self.message = message or self.message
+        self.details = details
+        self.request_id = request_id
+        self.response = response
+        self.url = url
+        self.method = method
+        formatted_string = "%s (HTTP %s)" % (self.message, self.http_status)
+        if request_id:
+            formatted_string += " (Request-ID: %s)" % request_id
+        super(HttpError, self).__init__(formatted_string)
+
+
+class HTTPRedirection(HttpError):
+    """HTTP Redirection."""
+    message = _("HTTP Redirection")
+
+
+class HTTPClientError(HttpError):
+    """Client-side HTTP error.
+
+    Exception for cases in which the client seems to have erred.
+    """
+    message = _("HTTP Client Error")
+
+
+class HttpServerError(HttpError):
+    """Server-side HTTP error.
+
+    Exception for cases in which the server is aware that it has
+    erred or is incapable of performing the request.
+    """
+    message = _("HTTP Server Error")
+
+
+class MultipleChoices(HTTPRedirection):
+    """HTTP 300 - Multiple Choices.
+
+    Indicates multiple options for the resource that the client may follow.
+    """
+
+    http_status = 300
+    message = _("Multiple Choices")
+
+
+class BadRequest(HTTPClientError):
+    """HTTP 400 - Bad Request.
+
+    The request cannot be fulfilled due to bad syntax.
+    """
+    http_status = 400
+    message = _("Bad Request")
+
+
+class Unauthorized(HTTPClientError):
+    """HTTP 401 - Unauthorized.
+
+    Similar to 403 Forbidden, but specifically for use when authentication
+    is required and has failed or has not yet been provided.
+    """
+    http_status = 401
+    message = _("Unauthorized")
+
+
+class PaymentRequired(HTTPClientError):
+    """HTTP 402 - Payment Required.
+
+    Reserved for future use.
+    """
+    http_status = 402
+    message = _("Payment Required")
+
+
+class Forbidden(HTTPClientError):
+    """HTTP 403 - Forbidden.
+
+    The request was a valid request, but the server is refusing to respond
+    to it.
+    """
+    http_status = 403
+    message = _("Forbidden")
+
+
+class NotFound(HTTPClientError):
+    """HTTP 404 - Not Found.
+
+    The requested resource could not be found but may be available again
+    in the future.
+    """
+    http_status = 404
+    message = _("Not Found")
+
+
+class MethodNotAllowed(HTTPClientError):
+    """HTTP 405 - Method Not Allowed.
+
+    A request was made of a resource using a request method not supported
+    by that resource.
+    """
+    http_status = 405
+    message = _("Method Not Allowed")
+
+
+class NotAcceptable(HTTPClientError):
+    """HTTP 406 - Not Acceptable.
+
+    The requested resource is only capable of generating content not
+    acceptable according to the Accept headers sent in the request.
+    """
+    http_status = 406
+    message = _("Not Acceptable")
+
+
+class ProxyAuthenticationRequired(HTTPClientError):
+    """HTTP 407 - Proxy Authentication Required.
+
+    The client must first authenticate itself with the proxy.
+    """
+    http_status = 407
+    message = _("Proxy Authentication Required")
+
+
+class RequestTimeout(HTTPClientError):
+    """HTTP 408 - Request Timeout.
+
+    The server timed out waiting for the request.
+    """
+    http_status = 408
+    message = _("Request Timeout")
+
+
+class Conflict(HTTPClientError):
+    """HTTP 409 - Conflict.
+
+    Indicates that the request could not be processed because of conflict
+    in the request, such as an edit conflict.
+    """
+    http_status = 409
+    message = _("Conflict")
+
+
+class Gone(HTTPClientError):
+    """HTTP 410 - Gone.
+
+    Indicates that the resource requested is no longer available and will
+    not be available again.
+    """
+    http_status = 410
+    message = _("Gone")
+
+
+class LengthRequired(HTTPClientError):
+    """HTTP 411 - Length Required.
+
+    The request did not specify the length of its content, which is
+    required by the requested resource.
+    """
+    http_status = 411
+    message = _("Length Required")
+
+
+class PreconditionFailed(HTTPClientError):
+    """HTTP 412 - Precondition Failed.
+
+    The server does not meet one of the preconditions that the requester
+    put on the request.
+    """
+    http_status = 412
+    message = _("Precondition Failed")
+
+
+class RequestEntityTooLarge(HTTPClientError):
+    """HTTP 413 - Request Entity Too Large.
+
+    The request is larger than the server is willing or able to process.
+    """
+    http_status = 413
+    message = _("Request Entity Too Large")
+
+    def __init__(self, *args, **kwargs):
+        try:
+            self.retry_after = int(kwargs.pop('retry_after'))
+        except (KeyError, ValueError):
+            self.retry_after = 0
+
+        super(RequestEntityTooLarge, self).__init__(*args, **kwargs)
+
+
+class RequestUriTooLong(HTTPClientError):
+    """HTTP 414 - Request-URI Too Long.
+
+    The URI provided was too long for the server to process.
+    """
+    http_status = 414
+    message = _("Request-URI Too Long")
+
+
+class UnsupportedMediaType(HTTPClientError):
+    """HTTP 415 - Unsupported Media Type.
+
+    The request entity has a media type which the server or resource does
+    not support.
+    """
+    http_status = 415
+    message = _("Unsupported Media Type")
+
+
+class RequestedRangeNotSatisfiable(HTTPClientError):
+    """HTTP 416 - Requested Range Not Satisfiable.
+
+    The client has asked for a portion of the file, but the server cannot
+    supply that portion.
+    """
+    http_status = 416
+    message = _("Requested Range Not Satisfiable")
+
+
+class ExpectationFailed(HTTPClientError):
+    """HTTP 417 - Expectation Failed.
+
+    The server cannot meet the requirements of the Expect request-header field.
+    """
+    http_status = 417
+    message = _("Expectation Failed")
+
+
+class UnprocessableEntity(HTTPClientError):
+    """HTTP 422 - Unprocessable Entity.
+
+    The request was well-formed but was unable to be followed due to semantic
+    errors.
+    """
+    http_status = 422
+    message = _("Unprocessable Entity")
+
+
+class InternalServerError(HttpServerError):
+    """HTTP 500 - Internal Server Error.
+
+    A generic error message, given when no more specific message is suitable.
+    """
+    http_status = 500
+    message = _("Internal Server Error")
+
+
+# NotImplemented is a python keyword.
+class HttpNotImplemented(HttpServerError):
+    """HTTP 501 - Not Implemented.
+
+    The server either does not recognize the request method, or it lacks
+    the ability to fulfill the request.
+    """
+    http_status = 501
+    message = _("Not Implemented")
+
+
+class BadGateway(HttpServerError):
+    """HTTP 502 - Bad Gateway.
+
+    The server was acting as a gateway or proxy and received an invalid
+    response from the upstream server.
+    """
+    http_status = 502
+    message = _("Bad Gateway")
+
+
+class ServiceUnavailable(HttpServerError):
+    """HTTP 503 - Service Unavailable.
+
+    The server is currently unavailable.
+    """
+    http_status = 503
+    message = _("Service Unavailable")
+
+
+class GatewayTimeout(HttpServerError):
+    """HTTP 504 - Gateway Timeout.
+
+    The server was acting as a gateway or proxy and did not receive a timely
+    response from the upstream server.
+    """
+    http_status = 504
+    message = _("Gateway Timeout")
+
+
+class HttpVersionNotSupported(HttpServerError):
+    """HTTP 505 - HttpVersion Not Supported.
+
+    The server does not support the HTTP protocol version used in the request.
+    """
+    http_status = 505
+    message = _("HTTP Version Not Supported")
+
+
+# _code_map contains all the classes that have http_status attribute.
+_code_map = dict(
+    (getattr(obj, 'http_status', None), obj)
+    for name, obj in six.iteritems(vars(sys.modules[__name__]))
+    if inspect.isclass(obj) and getattr(obj, 'http_status', False)
+)
+
+
+def from_response(response, method, url):
+    """Returns an instance of :class:`HttpError` or subclass based on response.
+
+    :param response: instance of `requests.Response` class
+    :param method: HTTP method used for request
+    :param url: URL used for request
+    """
+
+    req_id = response.headers.get("x-openstack-request-id")
+    # NOTE(hdd) true for older versions of nova and cinder
+    if not req_id:
+        req_id = response.headers.get("x-compute-request-id")
+    kwargs = {
+        "http_status": response.status_code,
+        "response": response,
+        "method": method,
+        "url": url,
+        "request_id": req_id,
+    }
+    if "retry-after" in response.headers:
+        kwargs["retry_after"] = response.headers["retry-after"]
+
+    content_type = response.headers.get("Content-Type", "")
+    if content_type.startswith("application/json"):
+        try:
+            body = response.json()
+        except ValueError:
+            pass
+        else:
+            if isinstance(body, dict):
+                error = body.get(list(body)[0])
+                if isinstance(error, dict):
+                    kwargs["message"] = (error.get("message") or
+                                         error.get("faultstring"))
+                    kwargs["details"] = (error.get("details") or
+                                         six.text_type(body))
+    elif content_type.startswith("text/"):
+        kwargs["details"] = response.text
+
+    try:
+        cls = _code_map[response.status_code]
+    except KeyError:
+        if 500 <= response.status_code < 600:
+            cls = HttpServerError
+        elif 400 <= response.status_code < 500:
+            cls = HTTPClientError
+        else:
+            cls = HttpError
+    return cls(**kwargs)
diff -pruN 2.6.2-1/ceilometerclient/apiclient/fake_client.py 2.9.0-0ubuntu4/ceilometerclient/apiclient/fake_client.py
--- 2.6.2-1/ceilometerclient/apiclient/fake_client.py	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/apiclient/fake_client.py	2017-06-12 13:24:31.000000000 +0000
@@ -0,0 +1,190 @@
+# Copyright 2013 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.
+
+"""
+A fake server that "responds" to API methods with pre-canned responses.
+
+All of these responses come from the spec, so if for some reason the spec's
+wrong the tests might raise AssertionError. I've indicated in comments the
+places where actual behavior differs from the spec.
+"""
+
+########################################################################
+#
+# THIS MODULE IS DEPRECATED
+#
+# Please refer to
+# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
+# the discussion leading to this deprecation.
+#
+# We recommend checking out the python-openstacksdk project
+# (https://launchpad.net/python-openstacksdk) instead.
+#
+########################################################################
+
+# W0102: Dangerous default value %s as argument
+# pylint: disable=W0102
+
+import json
+
+import requests
+import six
+from six.moves.urllib import parse
+
+from ceilometerclient.apiclient import client
+
+
+def assert_has_keys(dct, required=None, optional=None):
+    required = required or []
+    optional = optional or []
+    for k in required:
+        try:
+            assert k in dct
+        except AssertionError:
+            extra_keys = set(dct.keys()).difference(set(required + optional))
+            raise AssertionError("found unexpected keys: %s" %
+                                 list(extra_keys))
+
+
+class TestResponse(requests.Response):
+    """Wrap requests.Response and provide a convenient initialization."""
+
+    def __init__(self, data):
+        super(TestResponse, self).__init__()
+        self._content_consumed = True
+        if isinstance(data, dict):
+            self.status_code = data.get('status_code', 200)
+            # Fake the text attribute to streamline Response creation
+            text = data.get('text', "")
+            if isinstance(text, (dict, list)):
+                self._content = json.dumps(text)
+                default_headers = {
+                    "Content-Type": "application/json",
+                }
+            else:
+                self._content = text
+                default_headers = {}
+            if six.PY3 and isinstance(self._content, six.string_types):
+                self._content = self._content.encode('utf-8', 'strict')
+            self.headers = data.get('headers') or default_headers
+        else:
+            self.status_code = data
+
+    def __eq__(self, other):
+        return (self.status_code == other.status_code and
+                self.headers == other.headers and
+                self._content == other._content)
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+
+class FakeHTTPClient(client.HTTPClient):
+
+    def __init__(self, *args, **kwargs):
+        self.callstack = []
+        self.fixtures = kwargs.pop("fixtures", None) or {}
+        if not args and "auth_plugin" not in kwargs:
+            args = (None, )
+        super(FakeHTTPClient, self).__init__(*args, **kwargs)
+
+    def assert_called(self, method, url, body=None, pos=-1):
+        """Assert than an API method was just called."""
+        expected = (method, url)
+        called = self.callstack[pos][0:2]
+        assert self.callstack, \
+            "Expected %s %s but no calls were made." % expected
+
+        assert expected == called, 'Expected %s %s; got %s %s' % \
+            (expected + called)
+
+        if body is not None:
+            if self.callstack[pos][3] != body:
+                raise AssertionError('%r != %r' %
+                                     (self.callstack[pos][3], body))
+
+    def assert_called_anytime(self, method, url, body=None):
+        """Assert than an API method was called anytime in the test."""
+        expected = (method, url)
+
+        assert self.callstack, \
+            "Expected %s %s but no calls were made." % expected
+
+        found = False
+        entry = None
+        for entry in self.callstack:
+            if expected == entry[0:2]:
+                found = True
+                break
+
+        assert found, 'Expected %s %s; got %s' % \
+            (method, url, self.callstack)
+        if body is not None:
+            assert entry[3] == body, "%s != %s" % (entry[3], body)
+
+        self.callstack = []
+
+    def clear_callstack(self):
+        self.callstack = []
+
+    def authenticate(self):
+        pass
+
+    def client_request(self, client, method, url, **kwargs):
+        # Check that certain things are called correctly
+        if method in ["GET", "DELETE"]:
+            assert "json" not in kwargs
+
+        # Note the call
+        self.callstack.append(
+            (method,
+             url,
+             kwargs.get("headers") or {},
+             kwargs.get("json") or kwargs.get("data")))
+        try:
+            fixture = self.fixtures[url][method]
+        except KeyError:
+            pass
+        else:
+            return TestResponse({"headers": fixture[0],
+                                 "text": fixture[1]})
+
+        # Call the method
+        args = parse.parse_qsl(parse.urlparse(url)[4])
+        kwargs.update(args)
+        munged_url = url.rsplit('?', 1)[0]
+        munged_url = munged_url.strip('/').replace('/', '_').replace('.', '_')
+        munged_url = munged_url.replace('-', '_')
+
+        callback = "%s_%s" % (method.lower(), munged_url)
+
+        if not hasattr(self, callback):
+            raise AssertionError('Called unknown API method: %s %s, '
+                                 'expected fakes method name: %s' %
+                                 (method, url, callback))
+
+        resp = getattr(self, callback)(**kwargs)
+        if len(resp) == 3:
+            status, headers, body = resp
+        else:
+            status, body = resp
+            headers = {}
+        self.last_request_id = headers.get('x-openstack-request-id',
+                                           'req-test')
+        return TestResponse({
+            "status_code": status,
+            "text": body,
+            "headers": headers,
+        })
diff -pruN 2.6.2-1/ceilometerclient/apiclient/utils.py 2.9.0-0ubuntu4/ceilometerclient/apiclient/utils.py
--- 2.6.2-1/ceilometerclient/apiclient/utils.py	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/apiclient/utils.py	2017-06-12 13:24:31.000000000 +0000
@@ -0,0 +1,100 @@
+#
+#    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.
+
+########################################################################
+#
+# THIS MODULE IS DEPRECATED
+#
+# Please refer to
+# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
+# the discussion leading to this deprecation.
+#
+# We recommend checking out the python-openstacksdk project
+# (https://launchpad.net/python-openstacksdk) instead.
+#
+########################################################################
+
+from oslo_utils import encodeutils
+from oslo_utils import uuidutils
+import six
+
+from ceilometerclient.apiclient import exceptions
+from ceilometerclient.i18n import _
+
+
+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 -pruN 2.6.2-1/ceilometerclient/client.py 2.9.0-0ubuntu4/ceilometerclient/client.py
--- 2.6.2-1/ceilometerclient/client.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/client.py	2017-06-12 13:24:31.000000000 +0000
@@ -19,14 +19,14 @@ from keystoneauth1 import exceptions as
 from keystoneauth1.identity import v2 as v2_auth
 from keystoneauth1.identity import v3 as v3_auth
 from keystoneauth1 import session
+from oslo_utils import importutils
 from oslo_utils import strutils
 import six.moves.urllib.parse as urlparse
 
-from ceilometerclient.common import utils
+from ceilometerclient.apiclient import auth
+from ceilometerclient.apiclient import client
+from ceilometerclient.apiclient import exceptions
 from ceilometerclient import exc
-from ceilometerclient.openstack.common.apiclient import auth
-from ceilometerclient.openstack.common.apiclient import client
-from ceilometerclient.openstack.common.apiclient import exceptions
 
 
 def _discover_auth_versions(session, auth_url):
@@ -87,13 +87,17 @@ def _get_keystone_session(**kwargs):
     # create the keystone client session
     ks_session = session.Session(verify=verify, cert=cert, timeout=timeout)
     v2_auth_url, v3_auth_url = _discover_auth_versions(ks_session, auth_url)
-
     username = kwargs.pop('username', None)
     user_id = kwargs.pop('user_id', None)
     user_domain_name = kwargs.pop('user_domain_name', None)
     user_domain_id = kwargs.pop('user_domain_id', None)
     project_domain_name = kwargs.pop('project_domain_name', None)
     project_domain_id = kwargs.pop('project_domain_id', None)
+    if v3_auth_url:
+        if not user_domain_name:
+            user_domain_name = 'Default'
+        if not project_domain_name:
+            project_domain_name = 'Default'
     auth = None
 
     use_domain = (user_domain_id or user_domain_name or
@@ -288,7 +292,7 @@ def _adjust_kwargs(kwargs):
         if timeout <= 0:
             timeout = None
 
-    insecure = strutils.bool_from_string(kwargs.get('insecure'))
+    insecure = strutils.bool_from_string(client_kwargs.get('insecure'))
     verify = kwargs.get('verify')
     if verify is None:
         if insecure:
@@ -308,7 +312,8 @@ def _adjust_kwargs(kwargs):
 def Client(version, *args, **kwargs):
     client_kwargs = _adjust_kwargs(kwargs)
 
-    module = utils.import_versioned_module(version, 'client')
+    module = importutils.import_versioned_module('ceilometerclient',
+                                                 version, 'client')
     client_class = getattr(module, 'Client')
     return client_class(*args, **client_kwargs)
 
@@ -379,7 +384,7 @@ def get_auth_plugin(endpoint, **kwargs):
         endpoint=endpoint,
         username=kwargs.get('username'),
         password=kwargs.get('password'),
-        tenant_name=kwargs.get('tenant_name') or kwargs.get('project_name'),
+        tenant_name=kwargs.get('project_name') or kwargs.get('tenant_name'),
         user_domain_name=kwargs.get('user_domain_name'),
         user_domain_id=kwargs.get('user_domain_id'),
         project_domain_name=kwargs.get('project_domain_name'),
@@ -388,7 +393,7 @@ def get_auth_plugin(endpoint, **kwargs):
     return auth_plugin
 
 
-LEGACY_OPTS = ('auth_plugin', 'auth_url', 'token', 'insecure',  'cacert',
+LEGACY_OPTS = ('auth_plugin', 'auth_url', 'token', 'insecure', 'cacert',
                'tenant_id', 'project_id', 'username', 'password',
                'project_name', 'tenant_name',
                'user_domain_name', 'user_domain_id',
@@ -402,8 +407,9 @@ def _construct_http_client(**kwargs):
         # Drop legacy options
         for opt in LEGACY_OPTS:
             kwargs.pop(opt, None)
-        # Drop aodh_endpoint from kwargs
+        # Drop redirect endpoints from kwargs
         kwargs.pop('aodh_endpoint', None)
+        kwargs.pop('panko_endpoint', None)
 
         return SessionClient(
             session=kwargs.pop('session'),
diff -pruN 2.6.2-1/ceilometerclient/common/base.py 2.9.0-0ubuntu4/ceilometerclient/common/base.py
--- 2.6.2-1/ceilometerclient/common/base.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/common/base.py	2017-06-12 13:24:31.000000000 +0000
@@ -19,9 +19,9 @@ Base utilities to build API operation ma
 
 import copy
 
+from ceilometerclient.apiclient import base
+from ceilometerclient.apiclient import exceptions
 from ceilometerclient import exc
-from ceilometerclient.openstack.common.apiclient import base
-from ceilometerclient.openstack.common.apiclient import exceptions
 
 
 def getid(obj):
diff -pruN 2.6.2-1/ceilometerclient/common/utils.py 2.9.0-0ubuntu4/ceilometerclient/common/utils.py
--- 2.6.2-1/ceilometerclient/common/utils.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/common/utils.py	2017-06-12 13:24:31.000000000 +0000
@@ -20,7 +20,6 @@ import textwrap
 
 from oslo_serialization import jsonutils
 from oslo_utils import encodeutils
-from oslo_utils import importutils
 import prettytable
 import six
 
@@ -140,13 +139,6 @@ def print_dict(d, dict_property="Propert
     print(encoded)
 
 
-def import_versioned_module(version, submodule=None):
-    module = 'ceilometerclient.v%s' % version
-    if submodule:
-        module = '.'.join((module, submodule))
-    return importutils.import_module(module)
-
-
 def args_array_to_dict(kwargs, key_to_convert):
     values_to_convert = kwargs.get(key_to_convert)
     if values_to_convert:
diff -pruN 2.6.2-1/ceilometerclient/i18n.py 2.9.0-0ubuntu4/ceilometerclient/i18n.py
--- 2.6.2-1/ceilometerclient/i18n.py	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/i18n.py	2017-06-12 13:24:31.000000000 +0000
@@ -0,0 +1,27 @@
+# Copyright 2014 IBM Corp.
+#
+# 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
+
+
+_translators = oslo_i18n.TranslatorFactory(domain='ceilometerclient')
+
+# The primary translation function using the well-known name "_"
+_ = _translators.primary
diff -pruN 2.6.2-1/ceilometerclient/openstack/common/apiclient/auth.py 2.9.0-0ubuntu4/ceilometerclient/openstack/common/apiclient/auth.py
--- 2.6.2-1/ceilometerclient/openstack/common/apiclient/auth.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/openstack/common/apiclient/auth.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,234 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# Copyright 2013 Spanish National Research Council.
-# 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.
-
-# E0202: An attribute inherited from %s hide this method
-# pylint: disable=E0202
-
-########################################################################
-#
-# THIS MODULE IS DEPRECATED
-#
-# Please refer to
-# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
-# the discussion leading to this deprecation.
-#
-# We recommend checking out the python-openstacksdk project
-# (https://launchpad.net/python-openstacksdk) instead.
-#
-########################################################################
-
-import abc
-import argparse
-import os
-
-import six
-from stevedore import extension
-
-from ceilometerclient.openstack.common.apiclient import exceptions
-
-
-_discovered_plugins = {}
-
-
-def discover_auth_systems():
-    """Discover the available auth-systems.
-
-    This won't take into account the old style auth-systems.
-    """
-    global _discovered_plugins
-    _discovered_plugins = {}
-
-    def add_plugin(ext):
-        _discovered_plugins[ext.name] = ext.plugin
-
-    ep_namespace = "ceilometerclient.openstack.common.apiclient.auth"
-    mgr = extension.ExtensionManager(ep_namespace)
-    mgr.map(add_plugin)
-
-
-def load_auth_system_opts(parser):
-    """Load options needed by the available auth-systems into a parser.
-
-    This function will try to populate the parser with options from the
-    available plugins.
-    """
-    group = parser.add_argument_group("Common auth options")
-    BaseAuthPlugin.add_common_opts(group)
-    for name, auth_plugin in six.iteritems(_discovered_plugins):
-        group = parser.add_argument_group(
-            "Auth-system '%s' options" % name,
-            conflict_handler="resolve")
-        auth_plugin.add_opts(group)
-
-
-def load_plugin(auth_system):
-    try:
-        plugin_class = _discovered_plugins[auth_system]
-    except KeyError:
-        raise exceptions.AuthSystemNotFound(auth_system)
-    return plugin_class(auth_system=auth_system)
-
-
-def load_plugin_from_args(args):
-    """Load required plugin and populate it with options.
-
-    Try to guess auth system if it is not specified. Systems are tried in
-    alphabetical order.
-
-    :type args: argparse.Namespace
-    :raises: AuthPluginOptionsMissing
-    """
-    auth_system = args.os_auth_system
-    if auth_system:
-        plugin = load_plugin(auth_system)
-        plugin.parse_opts(args)
-        plugin.sufficient_options()
-        return plugin
-
-    for plugin_auth_system in sorted(six.iterkeys(_discovered_plugins)):
-        plugin_class = _discovered_plugins[plugin_auth_system]
-        plugin = plugin_class()
-        plugin.parse_opts(args)
-        try:
-            plugin.sufficient_options()
-        except exceptions.AuthPluginOptionsMissing:
-            continue
-        return plugin
-    raise exceptions.AuthPluginOptionsMissing(["auth_system"])
-
-
-@six.add_metaclass(abc.ABCMeta)
-class BaseAuthPlugin(object):
-    """Base class for authentication plugins.
-
-    An authentication plugin needs to override at least the authenticate
-    method to be a valid plugin.
-    """
-
-    auth_system = None
-    opt_names = []
-    common_opt_names = [
-        "auth_system",
-        "username",
-        "password",
-        "tenant_name",
-        "token",
-        "auth_url",
-    ]
-
-    def __init__(self, auth_system=None, **kwargs):
-        self.auth_system = auth_system or self.auth_system
-        self.opts = dict((name, kwargs.get(name))
-                         for name in self.opt_names)
-
-    @staticmethod
-    def _parser_add_opt(parser, opt):
-        """Add an option to parser in two variants.
-
-        :param opt: option name (with underscores)
-        """
-        dashed_opt = opt.replace("_", "-")
-        env_var = "OS_%s" % opt.upper()
-        arg_default = os.environ.get(env_var, "")
-        arg_help = "Defaults to env[%s]." % env_var
-        parser.add_argument(
-            "--os-%s" % dashed_opt,
-            metavar="<%s>" % dashed_opt,
-            default=arg_default,
-            help=arg_help)
-        parser.add_argument(
-            "--os_%s" % opt,
-            metavar="<%s>" % dashed_opt,
-            help=argparse.SUPPRESS)
-
-    @classmethod
-    def add_opts(cls, parser):
-        """Populate the parser with the options for this plugin.
-        """
-        for opt in cls.opt_names:
-            # use `BaseAuthPlugin.common_opt_names` since it is never
-            # changed in child classes
-            if opt not in BaseAuthPlugin.common_opt_names:
-                cls._parser_add_opt(parser, opt)
-
-    @classmethod
-    def add_common_opts(cls, parser):
-        """Add options that are common for several plugins.
-        """
-        for opt in cls.common_opt_names:
-            cls._parser_add_opt(parser, opt)
-
-    @staticmethod
-    def get_opt(opt_name, args):
-        """Return option name and value.
-
-        :param opt_name: name of the option, e.g., "username"
-        :param args: parsed arguments
-        """
-        return (opt_name, getattr(args, "os_%s" % opt_name, None))
-
-    def parse_opts(self, args):
-        """Parse the actual auth-system options if any.
-
-        This method is expected to populate the attribute `self.opts` with a
-        dict containing the options and values needed to make authentication.
-        """
-        self.opts.update(dict(self.get_opt(opt_name, args)
-                              for opt_name in self.opt_names))
-
-    def authenticate(self, http_client):
-        """Authenticate using plugin defined method.
-
-        The method usually analyses `self.opts` and performs
-        a request to authentication server.
-
-        :param http_client: client object that needs authentication
-        :type http_client: HTTPClient
-        :raises: AuthorizationFailure
-        """
-        self.sufficient_options()
-        self._do_authenticate(http_client)
-
-    @abc.abstractmethod
-    def _do_authenticate(self, http_client):
-        """Protected method for authentication.
-        """
-
-    def sufficient_options(self):
-        """Check if all required options are present.
-
-        :raises: AuthPluginOptionsMissing
-        """
-        missing = [opt
-                   for opt in self.opt_names
-                   if not self.opts.get(opt)]
-        if missing:
-            raise exceptions.AuthPluginOptionsMissing(missing)
-
-    @abc.abstractmethod
-    def token_and_endpoint(self, endpoint_type, service_type):
-        """Return token and endpoint.
-
-        :param service_type: Service type of the endpoint
-        :type service_type: string
-        :param endpoint_type: Type of endpoint.
-                              Possible values: public or publicURL,
-                              internal or internalURL,
-                              admin or adminURL
-        :type endpoint_type: string
-        :returns: tuple of token and endpoint strings
-        :raises: EndpointException
-        """
diff -pruN 2.6.2-1/ceilometerclient/openstack/common/apiclient/base.py 2.9.0-0ubuntu4/ceilometerclient/openstack/common/apiclient/base.py
--- 2.6.2-1/ceilometerclient/openstack/common/apiclient/base.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/openstack/common/apiclient/base.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,536 +0,0 @@
-# Copyright 2010 Jacob Kaplan-Moss
-# Copyright 2011 OpenStack Foundation
-# Copyright 2012 Grid Dynamics
-# Copyright 2013 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.
-
-"""
-Base utilities to build API operation managers and objects on top of.
-"""
-
-########################################################################
-#
-# THIS MODULE IS DEPRECATED
-#
-# Please refer to
-# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
-# the discussion leading to this deprecation.
-#
-# We recommend checking out the python-openstacksdk project
-# (https://launchpad.net/python-openstacksdk) instead.
-#
-########################################################################
-
-
-# E1102: %s is not callable
-# pylint: disable=E1102
-
-import abc
-import copy
-
-from oslo_utils import strutils
-import six
-from six.moves.urllib import parse
-from oslo_utils import reflection
-
-from ceilometerclient.openstack.common._i18n import _
-from ceilometerclient.openstack.common.apiclient import exceptions
-
-
-def getid(obj):
-    """Return id if argument is a Resource.
-
-    Abstracts the common pattern of allowing both an object or an object's ID
-    (UUID) as a parameter when dealing with relationships.
-    """
-    try:
-        if obj.uuid:
-            return obj.uuid
-    except AttributeError:
-        pass
-    try:
-        return obj.id
-    except AttributeError:
-        return obj
-
-
-# TODO(aababilov): call run_hooks() in HookableMixin's child classes
-class HookableMixin(object):
-    """Mixin so classes can register and run hooks."""
-    _hooks_map = {}
-
-    @classmethod
-    def add_hook(cls, hook_type, hook_func):
-        """Add a new hook of specified type.
-
-        :param cls: class that registers hooks
-        :param hook_type: hook type, e.g., '__pre_parse_args__'
-        :param hook_func: hook function
-        """
-        if hook_type not in cls._hooks_map:
-            cls._hooks_map[hook_type] = []
-
-        cls._hooks_map[hook_type].append(hook_func)
-
-    @classmethod
-    def run_hooks(cls, hook_type, *args, **kwargs):
-        """Run all hooks of specified type.
-
-        :param cls: class that registers hooks
-        :param hook_type: hook type, e.g., '__pre_parse_args__'
-        :param args: args to be passed to every hook function
-        :param kwargs: kwargs to be passed to every hook function
-        """
-        hook_funcs = cls._hooks_map.get(hook_type) or []
-        for hook_func in hook_funcs:
-            hook_func(*args, **kwargs)
-
-
-class BaseManager(HookableMixin):
-    """Basic manager type providing common operations.
-
-    Managers interact with a particular type of API (servers, flavors, images,
-    etc.) and provide CRUD operations for them.
-    """
-    resource_class = None
-
-    def __init__(self, client):
-        """Initializes BaseManager with `client`.
-
-        :param client: instance of BaseClient descendant for HTTP requests
-        """
-        super(BaseManager, self).__init__()
-        self.client = client
-
-    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'. 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
-            request (GET will be sent by default)
-        """
-        if json:
-            body = self.client.post(url, json=json).json()
-        else:
-            body = self.client.get(url).json()
-
-        if obj_class is None:
-            obj_class = self.resource_class
-
-        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:
-            data = data['values']
-        except (KeyError, TypeError):
-            pass
-
-        return [obj_class(self, res, loaded=True) for res in data if res]
-
-    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'. If response_key is None - all response body
-            will be used.
-        """
-        body = self.client.get(url).json()
-        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.
-
-        :param url: a partial URL, e.g., '/servers'
-        """
-        resp = self.client.head(url)
-        return resp.status_code == 204
-
-    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., '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 data
-        return self.resource_class(self, data)
-
-    def _put(self, url, json=None, response_key=None):
-        """Update an object with PUT method.
-
-        :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'. 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
-        if resp.content:
-            body = resp.json()
-            if response_key is not None:
-                return self.resource_class(self, body[response_key])
-            else:
-                return self.resource_class(self, body)
-
-    def _patch(self, url, json=None, response_key=None):
-        """Update an object with PATCH method.
-
-        :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'. 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:
-            return self.resource_class(self, body[response_key])
-        else:
-            return self.resource_class(self, body)
-
-    def _delete(self, url):
-        """Delete an object.
-
-        :param url: a partial URL, e.g., '/servers/my-server'
-        """
-        return self.client.delete(url)
-
-
-@six.add_metaclass(abc.ABCMeta)
-class ManagerWithFind(BaseManager):
-    """Manager with additional `find()`/`findall()` methods."""
-
-    @abc.abstractmethod
-    def list(self):
-        pass
-
-    def find(self, **kwargs):
-        """Find a single item with attributes matching ``**kwargs``.
-
-        This isn't very efficient: it loads the entire list then filters on
-        the Python side.
-        """
-        matches = self.findall(**kwargs)
-        num_matches = len(matches)
-        if num_matches == 0:
-            msg = _("No %(name)s matching %(args)s.") % {
-                'name': self.resource_class.__name__,
-                'args': kwargs
-            }
-            raise exceptions.NotFound(msg)
-        elif num_matches > 1:
-            raise exceptions.NoUniqueMatch()
-        else:
-            return matches[0]
-
-    def findall(self, **kwargs):
-        """Find all items with attributes matching ``**kwargs``.
-
-        This isn't very efficient: it loads the entire list then filters on
-        the Python side.
-        """
-        found = []
-        searches = kwargs.items()
-
-        for obj in self.list():
-            try:
-                if all(getattr(obj, attr) == value
-                       for (attr, value) in searches):
-                    found.append(obj)
-            except AttributeError:
-                continue
-
-        return found
-
-
-class CrudManager(BaseManager):
-    """Base manager class for manipulating entities.
-
-    Children of this class are expected to define a `collection_key` and `key`.
-
-    - `collection_key`: Usually a plural noun by convention (e.g. `entities`);
-      used to refer collections in both URL's (e.g.  `/v3/entities`) and JSON
-      objects containing a list of member resources (e.g. `{'entities': [{},
-      {}, {}]}`).
-    - `key`: Usually a singular noun by convention (e.g. `entity`); used to
-      refer to an individual member of the collection.
-
-    """
-    collection_key = None
-    key = None
-
-    def build_url(self, base_url=None, **kwargs):
-        """Builds a resource URL for the given kwargs.
-
-        Given an example collection where `collection_key = 'entities'` and
-        `key = 'entity'`, the following URL's could be generated.
-
-        By default, the URL will represent a collection of entities, e.g.::
-
-            /entities
-
-        If kwargs contains an `entity_id`, then the URL will represent a
-        specific member, e.g.::
-
-            /entities/{entity_id}
-
-        :param base_url: if provided, the generated URL will be appended to it
-        """
-        url = base_url if base_url is not None else ''
-
-        url += '/%s' % self.collection_key
-
-        # do we have a specific entity?
-        entity_id = kwargs.get('%s_id' % self.key)
-        if entity_id is not None:
-            url += '/%s' % entity_id
-
-        return url
-
-    def _filter_kwargs(self, kwargs):
-        """Drop null values and handle ids."""
-        for key, ref in six.iteritems(kwargs.copy()):
-            if ref is None:
-                kwargs.pop(key)
-            else:
-                if isinstance(ref, Resource):
-                    kwargs.pop(key)
-                    kwargs['%s_id' % key] = getid(ref)
-        return kwargs
-
-    def create(self, **kwargs):
-        kwargs = self._filter_kwargs(kwargs)
-        return self._post(
-            self.build_url(**kwargs),
-            {self.key: kwargs},
-            self.key)
-
-    def get(self, **kwargs):
-        kwargs = self._filter_kwargs(kwargs)
-        return self._get(
-            self.build_url(**kwargs),
-            self.key)
-
-    def head(self, **kwargs):
-        kwargs = self._filter_kwargs(kwargs)
-        return self._head(self.build_url(**kwargs))
-
-    def list(self, base_url=None, **kwargs):
-        """List the collection.
-
-        :param base_url: if provided, the generated URL will be appended to it
-        """
-        kwargs = self._filter_kwargs(kwargs)
-
-        return self._list(
-            '%(base_url)s%(query)s' % {
-                'base_url': self.build_url(base_url=base_url, **kwargs),
-                'query': '?%s' % parse.urlencode(kwargs) if kwargs else '',
-            },
-            self.collection_key)
-
-    def put(self, base_url=None, **kwargs):
-        """Update an element.
-
-        :param base_url: if provided, the generated URL will be appended to it
-        """
-        kwargs = self._filter_kwargs(kwargs)
-
-        return self._put(self.build_url(base_url=base_url, **kwargs))
-
-    def update(self, **kwargs):
-        kwargs = self._filter_kwargs(kwargs)
-        params = kwargs.copy()
-        params.pop('%s_id' % self.key)
-
-        return self._patch(
-            self.build_url(**kwargs),
-            {self.key: params},
-            self.key)
-
-    def delete(self, **kwargs):
-        kwargs = self._filter_kwargs(kwargs)
-
-        return self._delete(
-            self.build_url(**kwargs))
-
-    def find(self, base_url=None, **kwargs):
-        """Find a single item with attributes matching ``**kwargs``.
-
-        :param base_url: if provided, the generated URL will be appended to it
-        """
-        kwargs = self._filter_kwargs(kwargs)
-
-        rl = self._list(
-            '%(base_url)s%(query)s' % {
-                'base_url': self.build_url(base_url=base_url, **kwargs),
-                'query': '?%s' % parse.urlencode(kwargs) if kwargs else '',
-            },
-            self.collection_key)
-        num = len(rl)
-
-        if num == 0:
-            msg = _("No %(name)s matching %(args)s.") % {
-                'name': self.resource_class.__name__,
-                'args': kwargs
-            }
-            raise exceptions.NotFound(404, msg)
-        elif num > 1:
-            raise exceptions.NoUniqueMatch
-        else:
-            return rl[0]
-
-
-class Extension(HookableMixin):
-    """Extension descriptor."""
-
-    SUPPORTED_HOOKS = ('__pre_parse_args__', '__post_parse_args__')
-    manager_class = None
-
-    def __init__(self, name, module):
-        super(Extension, self).__init__()
-        self.name = name
-        self.module = module
-        self._parse_extension_module()
-
-    def _parse_extension_module(self):
-        self.manager_class = None
-        for attr_name, attr_value in self.module.__dict__.items():
-            if attr_name in self.SUPPORTED_HOOKS:
-                self.add_hook(attr_name, attr_value)
-            else:
-                try:
-                    if issubclass(attr_value, BaseManager):
-                        self.manager_class = attr_value
-                except TypeError:
-                    pass
-
-    def __repr__(self):
-        return "<Extension '%s'>" % self.name
-
-
-class Resource(object):
-    """Base class for OpenStack resources (tenant, user, etc.).
-
-    This is pretty much just a bag for attributes.
-    """
-
-    HUMAN_ID = False
-    NAME_ATTR = 'name'
-
-    def __init__(self, manager, info, loaded=False):
-        """Populate and bind to a manager.
-
-        :param manager: BaseManager object
-        :param info: dictionary representing resource attributes
-        :param loaded: prevent lazy-loading if set to True
-        """
-        self.manager = manager
-        self._info = info
-        self._add_details(info)
-        self._loaded = loaded
-
-    def __repr__(self):
-        reprkeys = sorted(k
-                          for k in self.__dict__.keys()
-                          if k[0] != '_' and k != 'manager')
-        info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys)
-        self_cls_name = reflection.get_class_name(self,
-                                                  fully_qualified=False)
-        return "<%s %s>" % (self_cls_name, info)
-
-    @property
-    def human_id(self):
-        """Human-readable ID which can be used for bash completion.
-        """
-        if self.HUMAN_ID:
-            name = getattr(self, self.NAME_ATTR, None)
-            if name is not None:
-                return strutils.to_slug(name)
-        return None
-
-    def _add_details(self, info):
-        for (k, v) in six.iteritems(info):
-            try:
-                setattr(self, k, v)
-                self._info[k] = v
-            except AttributeError:
-                # In this case we already defined the attribute on the class
-                pass
-
-    def __getattr__(self, k):
-        if k not in self.__dict__:
-            # NOTE(bcwaldon): disallow lazy-loading if already loaded once
-            if not self.is_loaded():
-                self.get()
-                return self.__getattr__(k)
-
-            raise AttributeError(k)
-        else:
-            return self.__dict__[k]
-
-    def get(self):
-        """Support for lazy loading details.
-
-        Some clients, such as novaclient have the option to lazy load the
-        details, details which can be loaded with this function.
-        """
-        # set_loaded() first ... so if we have to bail, we know we tried.
-        self.set_loaded(True)
-        if not hasattr(self.manager, 'get'):
-            return
-
-        new = self.manager.get(self.id)
-        if new:
-            self._add_details(new._info)
-            self._add_details(
-                {'x_request_id': self.manager.client.last_request_id})
-
-    def __eq__(self, other):
-        if not isinstance(other, Resource):
-            return NotImplemented
-        # two resources of different types are not equal
-        if not isinstance(other, self.__class__):
-            return False
-        return self._info == other._info
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-
-    def is_loaded(self):
-        return self._loaded
-
-    def set_loaded(self, val):
-        self._loaded = val
-
-    def to_dict(self):
-        return copy.deepcopy(self._info)
diff -pruN 2.6.2-1/ceilometerclient/openstack/common/apiclient/client.py 2.9.0-0ubuntu4/ceilometerclient/openstack/common/apiclient/client.py
--- 2.6.2-1/ceilometerclient/openstack/common/apiclient/client.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/openstack/common/apiclient/client.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,388 +0,0 @@
-# Copyright 2010 Jacob Kaplan-Moss
-# Copyright 2011 OpenStack Foundation
-# Copyright 2011 Piston Cloud Computing, Inc.
-# Copyright 2013 Alessio Ababilov
-# Copyright 2013 Grid Dynamics
-# Copyright 2013 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.
-
-"""
-OpenStack Client interface. Handles the REST calls and responses.
-"""
-
-# E0202: An attribute inherited from %s hide this method
-# pylint: disable=E0202
-
-import hashlib
-import logging
-import time
-
-try:
-    import simplejson as json
-except ImportError:
-    import json
-
-from oslo_utils import encodeutils
-from oslo_utils import importutils
-import requests
-
-from ceilometerclient.openstack.common._i18n import _
-from ceilometerclient.openstack.common.apiclient import exceptions
-
-_logger = logging.getLogger(__name__)
-SENSITIVE_HEADERS = ('X-Auth-Token', 'X-Subject-Token',)
-
-
-class HTTPClient(object):
-    """This client handles sending HTTP requests to OpenStack servers.
-
-    Features:
-
-    - share authentication information between several clients to different
-      services (e.g., for compute and image clients);
-    - reissue authentication request for expired tokens;
-    - encode/decode JSON bodies;
-    - raise exceptions on HTTP errors;
-    - pluggable authentication;
-    - store authentication information in a keyring;
-    - store time spent for requests;
-    - register clients for particular services, so one can use
-      `http_client.identity` or `http_client.compute`;
-    - log requests and responses in a format that is easy to copy-and-paste
-      into terminal and send the same request with curl.
-    """
-
-    user_agent = "ceilometerclient.openstack.common.apiclient"
-
-    def __init__(self,
-                 auth_plugin,
-                 region_name=None,
-                 endpoint_type="publicURL",
-                 original_ip=None,
-                 verify=True,
-                 cert=None,
-                 timeout=None,
-                 timings=False,
-                 keyring_saver=None,
-                 debug=False,
-                 user_agent=None,
-                 http=None):
-        self.auth_plugin = auth_plugin
-
-        self.endpoint_type = endpoint_type
-        self.region_name = region_name
-
-        self.original_ip = original_ip
-        self.timeout = timeout
-        self.verify = verify
-        self.cert = cert
-
-        self.keyring_saver = keyring_saver
-        self.debug = debug
-        self.user_agent = user_agent or self.user_agent
-
-        self.times = []  # [("item", starttime, endtime), ...]
-        self.timings = timings
-
-        # requests within the same session can reuse TCP connections from pool
-        self.http = http or requests.Session()
-
-        self.cached_token = None
-        self.last_request_id = None
-
-    def _safe_header(self, name, value):
-        if name in SENSITIVE_HEADERS:
-            # because in python3 byte string handling is ... ug
-            v = value.encode('utf-8')
-            h = hashlib.sha1(v)
-            d = h.hexdigest()
-            return encodeutils.safe_decode(name), "{SHA1}%s" % d
-        else:
-            return (encodeutils.safe_decode(name),
-                    encodeutils.safe_decode(value))
-
-    def _http_log_req(self, method, url, kwargs):
-        if not self.debug:
-            return
-
-        string_parts = [
-            "curl -g -i",
-            "-X '%s'" % method,
-            "'%s'" % url,
-        ]
-
-        for element in kwargs['headers']:
-            header = ("-H '%s: %s'" %
-                      self._safe_header(element, kwargs['headers'][element]))
-            string_parts.append(header)
-
-        _logger.debug("REQ: %s" % " ".join(string_parts))
-        if 'data' in kwargs:
-            _logger.debug("REQ BODY: %s\n" % (kwargs['data']))
-
-    def _http_log_resp(self, resp):
-        if not self.debug:
-            return
-        _logger.debug(
-            "RESP: [%s] %s\n",
-            resp.status_code,
-            resp.headers)
-        if resp._content_consumed:
-            _logger.debug(
-                "RESP BODY: %s\n",
-                resp.text)
-
-    def serialize(self, kwargs):
-        if kwargs.get('json') is not None:
-            kwargs['headers']['Content-Type'] = 'application/json'
-            kwargs['data'] = json.dumps(kwargs['json'])
-        try:
-            del kwargs['json']
-        except KeyError:
-            pass
-
-    def get_timings(self):
-        return self.times
-
-    def reset_timings(self):
-        self.times = []
-
-    def request(self, method, url, **kwargs):
-        """Send an http request with the specified characteristics.
-
-        Wrapper around `requests.Session.request` to handle tasks such as
-        setting headers, JSON encoding/decoding, and error handling.
-
-        :param method: method of HTTP request
-        :param url: URL of HTTP request
-        :param kwargs: any other parameter that can be passed to
-             requests.Session.request (such as `headers`) or `json`
-             that will be encoded as JSON and used as `data` argument
-        """
-        kwargs.setdefault("headers", {})
-        kwargs["headers"]["User-Agent"] = self.user_agent
-        if self.original_ip:
-            kwargs["headers"]["Forwarded"] = "for=%s;by=%s" % (
-                self.original_ip, self.user_agent)
-        if self.timeout is not None:
-            kwargs.setdefault("timeout", self.timeout)
-        kwargs.setdefault("verify", self.verify)
-        if self.cert is not None:
-            kwargs.setdefault("cert", self.cert)
-        self.serialize(kwargs)
-
-        self._http_log_req(method, url, kwargs)
-        if self.timings:
-            start_time = time.time()
-        resp = self.http.request(method, url, **kwargs)
-        if self.timings:
-            self.times.append(("%s %s" % (method, url),
-                               start_time, time.time()))
-        self._http_log_resp(resp)
-
-        self.last_request_id = resp.headers.get('x-openstack-request-id')
-
-        if resp.status_code >= 400:
-            _logger.debug(
-                "Request returned failure status: %s",
-                resp.status_code)
-            raise exceptions.from_response(resp, method, url)
-
-        return resp
-
-    @staticmethod
-    def concat_url(endpoint, url):
-        """Concatenate endpoint and final URL.
-
-        E.g., "http://keystone/v2.0/" and "/tokens" are concatenated to
-        "http://keystone/v2.0/tokens".
-
-        :param endpoint: the base URL
-        :param url: the final URL
-        """
-        return "%s/%s" % (endpoint.rstrip("/"), url.strip("/"))
-
-    def client_request(self, client, method, url, **kwargs):
-        """Send an http request using `client`'s endpoint and specified `url`.
-
-        If request was rejected as unauthorized (possibly because the token is
-        expired), issue one authorization attempt and send the request once
-        again.
-
-        :param client: instance of BaseClient descendant
-        :param method: method of HTTP request
-        :param url: URL of HTTP request
-        :param kwargs: any other parameter that can be passed to
-            `HTTPClient.request`
-        """
-
-        filter_args = {
-            "endpoint_type": client.endpoint_type or self.endpoint_type,
-            "service_type": client.service_type,
-        }
-        token, endpoint = (self.cached_token, client.cached_endpoint)
-        just_authenticated = False
-        if not (token and endpoint):
-            try:
-                token, endpoint = self.auth_plugin.token_and_endpoint(
-                    **filter_args)
-            except exceptions.EndpointException:
-                pass
-            if not (token and endpoint):
-                self.authenticate()
-                just_authenticated = True
-                token, endpoint = self.auth_plugin.token_and_endpoint(
-                    **filter_args)
-                if not (token and endpoint):
-                    raise exceptions.AuthorizationFailure(
-                        _("Cannot find endpoint or token for request"))
-
-        old_token_endpoint = (token, endpoint)
-        kwargs.setdefault("headers", {})["X-Auth-Token"] = token
-        self.cached_token = token
-        client.cached_endpoint = endpoint
-        # Perform the request once. If we get Unauthorized, then it
-        # might be because the auth token expired, so try to
-        # re-authenticate and try again. If it still fails, bail.
-        try:
-            return self.request(
-                method, self.concat_url(endpoint, url), **kwargs)
-        except exceptions.Unauthorized as unauth_ex:
-            if just_authenticated:
-                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(
-                    **filter_args)
-            except exceptions.EndpointException:
-                raise unauth_ex
-            if (not (token and endpoint) or
-                    old_token_endpoint == (token, endpoint)):
-                raise unauth_ex
-            self.cached_token = token
-            client.cached_endpoint = endpoint
-            kwargs["headers"]["X-Auth-Token"] = token
-            return self.request(
-                method, self.concat_url(endpoint, url), **kwargs)
-
-    def add_client(self, base_client_instance):
-        """Add a new instance of :class:`BaseClient` descendant.
-
-        `self` will store a reference to `base_client_instance`.
-
-        Example:
-
-        >>> def test_clients():
-        ...     from keystoneclient.auth import keystone
-        ...     from openstack.common.apiclient import client
-        ...     auth = keystone.KeystoneAuthPlugin(
-        ...         username="user", password="pass", tenant_name="tenant",
-        ...         auth_url="http://auth:5000/v2.0")
-        ...     openstack_client = client.HTTPClient(auth)
-        ...     # create nova client
-        ...     from novaclient.v1_1 import client
-        ...     client.Client(openstack_client)
-        ...     # create keystone client
-        ...     from keystoneclient.v2_0 import client
-        ...     client.Client(openstack_client)
-        ...     # use them
-        ...     openstack_client.identity.tenants.list()
-        ...     openstack_client.compute.servers.list()
-        """
-        service_type = base_client_instance.service_type
-        if service_type and not hasattr(self, service_type):
-            setattr(self, service_type, base_client_instance)
-
-    def authenticate(self):
-        self.auth_plugin.authenticate(self)
-        # Store the authentication results in the keyring for later requests
-        if self.keyring_saver:
-            self.keyring_saver.save(self)
-
-
-class BaseClient(object):
-    """Top-level object to access the OpenStack API.
-
-    This client uses :class:`HTTPClient` to send requests. :class:`HTTPClient`
-    will handle a bunch of issues such as authentication.
-    """
-
-    service_type = None
-    endpoint_type = None  # "publicURL" will be used
-    cached_endpoint = None
-
-    def __init__(self, http_client, extensions=None):
-        self.http_client = http_client
-        http_client.add_client(self)
-
-        # Add in any extensions...
-        if extensions:
-            for extension in extensions:
-                if extension.manager_class:
-                    setattr(self, extension.name,
-                            extension.manager_class(self))
-
-    def client_request(self, method, url, **kwargs):
-        return self.http_client.client_request(
-            self, method, url, **kwargs)
-
-    @property
-    def last_request_id(self):
-        return self.http_client.last_request_id
-
-    def head(self, url, **kwargs):
-        return self.client_request("HEAD", url, **kwargs)
-
-    def get(self, url, **kwargs):
-        return self.client_request("GET", url, **kwargs)
-
-    def post(self, url, **kwargs):
-        return self.client_request("POST", url, **kwargs)
-
-    def put(self, url, **kwargs):
-        return self.client_request("PUT", url, **kwargs)
-
-    def delete(self, url, **kwargs):
-        return self.client_request("DELETE", url, **kwargs)
-
-    def patch(self, url, **kwargs):
-        return self.client_request("PATCH", url, **kwargs)
-
-    @staticmethod
-    def get_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 %(api_name)s client version '%(version)s'. "
-                    "Must be one of: %(version_map)s") % {
-                        'api_name': api_name,
-                        'version': version,
-                        'version_map': ', '.join(version_map.keys())}
-            raise exceptions.UnsupportedVersion(msg)
-
-        return importutils.import_class(client_path)
diff -pruN 2.6.2-1/ceilometerclient/openstack/common/apiclient/exceptions.py 2.9.0-0ubuntu4/ceilometerclient/openstack/common/apiclient/exceptions.py
--- 2.6.2-1/ceilometerclient/openstack/common/apiclient/exceptions.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/openstack/common/apiclient/exceptions.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,479 +0,0 @@
-# Copyright 2010 Jacob Kaplan-Moss
-# Copyright 2011 Nebula, Inc.
-# Copyright 2013 Alessio Ababilov
-# Copyright 2013 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.
-
-"""
-Exception definitions.
-"""
-
-########################################################################
-#
-# THIS MODULE IS DEPRECATED
-#
-# Please refer to
-# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
-# the discussion leading to this deprecation.
-#
-# We recommend checking out the python-openstacksdk project
-# (https://launchpad.net/python-openstacksdk) instead.
-#
-########################################################################
-
-import inspect
-import sys
-
-import six
-
-from ceilometerclient.openstack.common._i18n import _
-
-
-class ClientException(Exception):
-    """The base exception class for all exceptions this library raises.
-    """
-    pass
-
-
-class ValidationError(ClientException):
-    """Error in validation on API client side."""
-    pass
-
-
-class UnsupportedVersion(ClientException):
-    """User is trying to use an unsupported version of the API."""
-    pass
-
-
-class CommandError(ClientException):
-    """Error in CLI tool."""
-    pass
-
-
-class AuthorizationFailure(ClientException):
-    """Cannot authorize API client."""
-    pass
-
-
-class ConnectionError(ClientException):
-    """Cannot connect to API service."""
-    pass
-
-
-class ConnectionRefused(ConnectionError):
-    """Connection refused while trying to connect to API service."""
-    pass
-
-
-class AuthPluginOptionsMissing(AuthorizationFailure):
-    """Auth plugin misses some options."""
-    def __init__(self, opt_names):
-        super(AuthPluginOptionsMissing, self).__init__(
-            _("Authentication failed. Missing options: %s") %
-            ", ".join(opt_names))
-        self.opt_names = opt_names
-
-
-class AuthSystemNotFound(AuthorizationFailure):
-    """User has specified an AuthSystem that is not installed."""
-    def __init__(self, auth_system):
-        super(AuthSystemNotFound, self).__init__(
-            _("AuthSystemNotFound: %s") % repr(auth_system))
-        self.auth_system = auth_system
-
-
-class NoUniqueMatch(ClientException):
-    """Multiple entities found instead of one."""
-    pass
-
-
-class EndpointException(ClientException):
-    """Something is rotten in Service Catalog."""
-    pass
-
-
-class EndpointNotFound(EndpointException):
-    """Could not find requested endpoint in Service Catalog."""
-    pass
-
-
-class AmbiguousEndpoints(EndpointException):
-    """Found more than one matching endpoint in Service Catalog."""
-    def __init__(self, endpoints=None):
-        super(AmbiguousEndpoints, self).__init__(
-            _("AmbiguousEndpoints: %s") % repr(endpoints))
-        self.endpoints = endpoints
-
-
-class HttpError(ClientException):
-    """The base exception class for all HTTP exceptions.
-    """
-    http_status = 0
-    message = _("HTTP Error")
-
-    def __init__(self, message=None, details=None,
-                 response=None, request_id=None,
-                 url=None, method=None, http_status=None):
-        self.http_status = http_status or self.http_status
-        self.message = message or self.message
-        self.details = details
-        self.request_id = request_id
-        self.response = response
-        self.url = url
-        self.method = method
-        formatted_string = "%s (HTTP %s)" % (self.message, self.http_status)
-        if request_id:
-            formatted_string += " (Request-ID: %s)" % request_id
-        super(HttpError, self).__init__(formatted_string)
-
-
-class HTTPRedirection(HttpError):
-    """HTTP Redirection."""
-    message = _("HTTP Redirection")
-
-
-class HTTPClientError(HttpError):
-    """Client-side HTTP error.
-
-    Exception for cases in which the client seems to have erred.
-    """
-    message = _("HTTP Client Error")
-
-
-class HttpServerError(HttpError):
-    """Server-side HTTP error.
-
-    Exception for cases in which the server is aware that it has
-    erred or is incapable of performing the request.
-    """
-    message = _("HTTP Server Error")
-
-
-class MultipleChoices(HTTPRedirection):
-    """HTTP 300 - Multiple Choices.
-
-    Indicates multiple options for the resource that the client may follow.
-    """
-
-    http_status = 300
-    message = _("Multiple Choices")
-
-
-class BadRequest(HTTPClientError):
-    """HTTP 400 - Bad Request.
-
-    The request cannot be fulfilled due to bad syntax.
-    """
-    http_status = 400
-    message = _("Bad Request")
-
-
-class Unauthorized(HTTPClientError):
-    """HTTP 401 - Unauthorized.
-
-    Similar to 403 Forbidden, but specifically for use when authentication
-    is required and has failed or has not yet been provided.
-    """
-    http_status = 401
-    message = _("Unauthorized")
-
-
-class PaymentRequired(HTTPClientError):
-    """HTTP 402 - Payment Required.
-
-    Reserved for future use.
-    """
-    http_status = 402
-    message = _("Payment Required")
-
-
-class Forbidden(HTTPClientError):
-    """HTTP 403 - Forbidden.
-
-    The request was a valid request, but the server is refusing to respond
-    to it.
-    """
-    http_status = 403
-    message = _("Forbidden")
-
-
-class NotFound(HTTPClientError):
-    """HTTP 404 - Not Found.
-
-    The requested resource could not be found but may be available again
-    in the future.
-    """
-    http_status = 404
-    message = _("Not Found")
-
-
-class MethodNotAllowed(HTTPClientError):
-    """HTTP 405 - Method Not Allowed.
-
-    A request was made of a resource using a request method not supported
-    by that resource.
-    """
-    http_status = 405
-    message = _("Method Not Allowed")
-
-
-class NotAcceptable(HTTPClientError):
-    """HTTP 406 - Not Acceptable.
-
-    The requested resource is only capable of generating content not
-    acceptable according to the Accept headers sent in the request.
-    """
-    http_status = 406
-    message = _("Not Acceptable")
-
-
-class ProxyAuthenticationRequired(HTTPClientError):
-    """HTTP 407 - Proxy Authentication Required.
-
-    The client must first authenticate itself with the proxy.
-    """
-    http_status = 407
-    message = _("Proxy Authentication Required")
-
-
-class RequestTimeout(HTTPClientError):
-    """HTTP 408 - Request Timeout.
-
-    The server timed out waiting for the request.
-    """
-    http_status = 408
-    message = _("Request Timeout")
-
-
-class Conflict(HTTPClientError):
-    """HTTP 409 - Conflict.
-
-    Indicates that the request could not be processed because of conflict
-    in the request, such as an edit conflict.
-    """
-    http_status = 409
-    message = _("Conflict")
-
-
-class Gone(HTTPClientError):
-    """HTTP 410 - Gone.
-
-    Indicates that the resource requested is no longer available and will
-    not be available again.
-    """
-    http_status = 410
-    message = _("Gone")
-
-
-class LengthRequired(HTTPClientError):
-    """HTTP 411 - Length Required.
-
-    The request did not specify the length of its content, which is
-    required by the requested resource.
-    """
-    http_status = 411
-    message = _("Length Required")
-
-
-class PreconditionFailed(HTTPClientError):
-    """HTTP 412 - Precondition Failed.
-
-    The server does not meet one of the preconditions that the requester
-    put on the request.
-    """
-    http_status = 412
-    message = _("Precondition Failed")
-
-
-class RequestEntityTooLarge(HTTPClientError):
-    """HTTP 413 - Request Entity Too Large.
-
-    The request is larger than the server is willing or able to process.
-    """
-    http_status = 413
-    message = _("Request Entity Too Large")
-
-    def __init__(self, *args, **kwargs):
-        try:
-            self.retry_after = int(kwargs.pop('retry_after'))
-        except (KeyError, ValueError):
-            self.retry_after = 0
-
-        super(RequestEntityTooLarge, self).__init__(*args, **kwargs)
-
-
-class RequestUriTooLong(HTTPClientError):
-    """HTTP 414 - Request-URI Too Long.
-
-    The URI provided was too long for the server to process.
-    """
-    http_status = 414
-    message = _("Request-URI Too Long")
-
-
-class UnsupportedMediaType(HTTPClientError):
-    """HTTP 415 - Unsupported Media Type.
-
-    The request entity has a media type which the server or resource does
-    not support.
-    """
-    http_status = 415
-    message = _("Unsupported Media Type")
-
-
-class RequestedRangeNotSatisfiable(HTTPClientError):
-    """HTTP 416 - Requested Range Not Satisfiable.
-
-    The client has asked for a portion of the file, but the server cannot
-    supply that portion.
-    """
-    http_status = 416
-    message = _("Requested Range Not Satisfiable")
-
-
-class ExpectationFailed(HTTPClientError):
-    """HTTP 417 - Expectation Failed.
-
-    The server cannot meet the requirements of the Expect request-header field.
-    """
-    http_status = 417
-    message = _("Expectation Failed")
-
-
-class UnprocessableEntity(HTTPClientError):
-    """HTTP 422 - Unprocessable Entity.
-
-    The request was well-formed but was unable to be followed due to semantic
-    errors.
-    """
-    http_status = 422
-    message = _("Unprocessable Entity")
-
-
-class InternalServerError(HttpServerError):
-    """HTTP 500 - Internal Server Error.
-
-    A generic error message, given when no more specific message is suitable.
-    """
-    http_status = 500
-    message = _("Internal Server Error")
-
-
-# NotImplemented is a python keyword.
-class HttpNotImplemented(HttpServerError):
-    """HTTP 501 - Not Implemented.
-
-    The server either does not recognize the request method, or it lacks
-    the ability to fulfill the request.
-    """
-    http_status = 501
-    message = _("Not Implemented")
-
-
-class BadGateway(HttpServerError):
-    """HTTP 502 - Bad Gateway.
-
-    The server was acting as a gateway or proxy and received an invalid
-    response from the upstream server.
-    """
-    http_status = 502
-    message = _("Bad Gateway")
-
-
-class ServiceUnavailable(HttpServerError):
-    """HTTP 503 - Service Unavailable.
-
-    The server is currently unavailable.
-    """
-    http_status = 503
-    message = _("Service Unavailable")
-
-
-class GatewayTimeout(HttpServerError):
-    """HTTP 504 - Gateway Timeout.
-
-    The server was acting as a gateway or proxy and did not receive a timely
-    response from the upstream server.
-    """
-    http_status = 504
-    message = _("Gateway Timeout")
-
-
-class HttpVersionNotSupported(HttpServerError):
-    """HTTP 505 - HttpVersion Not Supported.
-
-    The server does not support the HTTP protocol version used in the request.
-    """
-    http_status = 505
-    message = _("HTTP Version Not Supported")
-
-
-# _code_map contains all the classes that have http_status attribute.
-_code_map = dict(
-    (getattr(obj, 'http_status', None), obj)
-    for name, obj in six.iteritems(vars(sys.modules[__name__]))
-    if inspect.isclass(obj) and getattr(obj, 'http_status', False)
-)
-
-
-def from_response(response, method, url):
-    """Returns an instance of :class:`HttpError` or subclass based on response.
-
-    :param response: instance of `requests.Response` class
-    :param method: HTTP method used for request
-    :param url: URL used for request
-    """
-
-    req_id = response.headers.get("x-openstack-request-id")
-    # NOTE(hdd) true for older versions of nova and cinder
-    if not req_id:
-        req_id = response.headers.get("x-compute-request-id")
-    kwargs = {
-        "http_status": response.status_code,
-        "response": response,
-        "method": method,
-        "url": url,
-        "request_id": req_id,
-    }
-    if "retry-after" in response.headers:
-        kwargs["retry_after"] = response.headers["retry-after"]
-
-    content_type = response.headers.get("Content-Type", "")
-    if content_type.startswith("application/json"):
-        try:
-            body = response.json()
-        except ValueError:
-            pass
-        else:
-            if isinstance(body, dict):
-                error = body.get(list(body)[0])
-                if isinstance(error, dict):
-                    kwargs["message"] = (error.get("message") or
-                                         error.get("faultstring"))
-                    kwargs["details"] = (error.get("details") or
-                                         six.text_type(body))
-    elif content_type.startswith("text/"):
-        kwargs["details"] = response.text
-
-    try:
-        cls = _code_map[response.status_code]
-    except KeyError:
-        if 500 <= response.status_code < 600:
-            cls = HttpServerError
-        elif 400 <= response.status_code < 500:
-            cls = HTTPClientError
-        else:
-            cls = HttpError
-    return cls(**kwargs)
diff -pruN 2.6.2-1/ceilometerclient/openstack/common/apiclient/fake_client.py 2.9.0-0ubuntu4/ceilometerclient/openstack/common/apiclient/fake_client.py
--- 2.6.2-1/ceilometerclient/openstack/common/apiclient/fake_client.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/openstack/common/apiclient/fake_client.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,190 +0,0 @@
-# Copyright 2013 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.
-
-"""
-A fake server that "responds" to API methods with pre-canned responses.
-
-All of these responses come from the spec, so if for some reason the spec's
-wrong the tests might raise AssertionError. I've indicated in comments the
-places where actual behavior differs from the spec.
-"""
-
-########################################################################
-#
-# THIS MODULE IS DEPRECATED
-#
-# Please refer to
-# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
-# the discussion leading to this deprecation.
-#
-# We recommend checking out the python-openstacksdk project
-# (https://launchpad.net/python-openstacksdk) instead.
-#
-########################################################################
-
-# W0102: Dangerous default value %s as argument
-# pylint: disable=W0102
-
-import json
-
-import requests
-import six
-from six.moves.urllib import parse
-
-from ceilometerclient.openstack.common.apiclient import client
-
-
-def assert_has_keys(dct, required=None, optional=None):
-    required = required or []
-    optional = optional or []
-    for k in required:
-        try:
-            assert k in dct
-        except AssertionError:
-            extra_keys = set(dct.keys()).difference(set(required + optional))
-            raise AssertionError("found unexpected keys: %s" %
-                                 list(extra_keys))
-
-
-class TestResponse(requests.Response):
-    """Wrap requests.Response and provide a convenient initialization.
-    """
-
-    def __init__(self, data):
-        super(TestResponse, self).__init__()
-        self._content_consumed = True
-        if isinstance(data, dict):
-            self.status_code = data.get('status_code', 200)
-            # Fake the text attribute to streamline Response creation
-            text = data.get('text', "")
-            if isinstance(text, (dict, list)):
-                self._content = json.dumps(text)
-                default_headers = {
-                    "Content-Type": "application/json",
-                }
-            else:
-                self._content = text
-                default_headers = {}
-            if six.PY3 and isinstance(self._content, six.string_types):
-                self._content = self._content.encode('utf-8', 'strict')
-            self.headers = data.get('headers') or default_headers
-        else:
-            self.status_code = data
-
-    def __eq__(self, other):
-        return (self.status_code == other.status_code and
-                self.headers == other.headers and
-                self._content == other._content)
-
-
-class FakeHTTPClient(client.HTTPClient):
-
-    def __init__(self, *args, **kwargs):
-        self.callstack = []
-        self.fixtures = kwargs.pop("fixtures", None) or {}
-        if not args and "auth_plugin" not in kwargs:
-            args = (None, )
-        super(FakeHTTPClient, self).__init__(*args, **kwargs)
-
-    def assert_called(self, method, url, body=None, pos=-1):
-        """Assert than an API method was just called.
-        """
-        expected = (method, url)
-        called = self.callstack[pos][0:2]
-        assert self.callstack, \
-            "Expected %s %s but no calls were made." % expected
-
-        assert expected == called, 'Expected %s %s; got %s %s' % \
-            (expected + called)
-
-        if body is not None:
-            if self.callstack[pos][3] != body:
-                raise AssertionError('%r != %r' %
-                                     (self.callstack[pos][3], body))
-
-    def assert_called_anytime(self, method, url, body=None):
-        """Assert than an API method was called anytime in the test.
-        """
-        expected = (method, url)
-
-        assert self.callstack, \
-            "Expected %s %s but no calls were made." % expected
-
-        found = False
-        entry = None
-        for entry in self.callstack:
-            if expected == entry[0:2]:
-                found = True
-                break
-
-        assert found, 'Expected %s %s; got %s' % \
-            (method, url, self.callstack)
-        if body is not None:
-            assert entry[3] == body, "%s != %s" % (entry[3], body)
-
-        self.callstack = []
-
-    def clear_callstack(self):
-        self.callstack = []
-
-    def authenticate(self):
-        pass
-
-    def client_request(self, client, method, url, **kwargs):
-        # Check that certain things are called correctly
-        if method in ["GET", "DELETE"]:
-            assert "json" not in kwargs
-
-        # Note the call
-        self.callstack.append(
-            (method,
-             url,
-             kwargs.get("headers") or {},
-             kwargs.get("json") or kwargs.get("data")))
-        try:
-            fixture = self.fixtures[url][method]
-        except KeyError:
-            pass
-        else:
-            return TestResponse({"headers": fixture[0],
-                                 "text": fixture[1]})
-
-        # Call the method
-        args = parse.parse_qsl(parse.urlparse(url)[4])
-        kwargs.update(args)
-        munged_url = url.rsplit('?', 1)[0]
-        munged_url = munged_url.strip('/').replace('/', '_').replace('.', '_')
-        munged_url = munged_url.replace('-', '_')
-
-        callback = "%s_%s" % (method.lower(), munged_url)
-
-        if not hasattr(self, callback):
-            raise AssertionError('Called unknown API method: %s %s, '
-                                 'expected fakes method name: %s' %
-                                 (method, url, callback))
-
-        resp = getattr(self, callback)(**kwargs)
-        if len(resp) == 3:
-            status, headers, body = resp
-        else:
-            status, body = resp
-            headers = {}
-        self.last_request_id = headers.get('x-openstack-request-id',
-                                           'req-test')
-        return TestResponse({
-            "status_code": status,
-            "text": body,
-            "headers": headers,
-        })
diff -pruN 2.6.2-1/ceilometerclient/openstack/common/apiclient/utils.py 2.9.0-0ubuntu4/ceilometerclient/openstack/common/apiclient/utils.py
--- 2.6.2-1/ceilometerclient/openstack/common/apiclient/utils.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/openstack/common/apiclient/utils.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,100 +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.
-
-########################################################################
-#
-# THIS MODULE IS DEPRECATED
-#
-# Please refer to
-# https://etherpad.openstack.org/p/kilo-ceilometerclient-library-proposals for
-# the discussion leading to this deprecation.
-#
-# We recommend checking out the python-openstacksdk project
-# (https://launchpad.net/python-openstacksdk) instead.
-#
-########################################################################
-
-from oslo_utils import encodeutils
-from oslo_utils import uuidutils
-import six
-
-from ceilometerclient.openstack.common._i18n import _
-from ceilometerclient.openstack.common.apiclient import exceptions
-
-
-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 -pruN 2.6.2-1/ceilometerclient/openstack/common/_i18n.py 2.9.0-0ubuntu4/ceilometerclient/openstack/common/_i18n.py
--- 2.6.2-1/ceilometerclient/openstack/common/_i18n.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/openstack/common/_i18n.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,45 +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.
-
-"""oslo.i18n integration module.
-
-See http://docs.openstack.org/developer/oslo.i18n/usage.html
-
-"""
-
-try:
-    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='ceilometerclient')
-
-    # 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
-except ImportError:
-    # NOTE(dims): Support for cases where a project wants to use
-    # code from oslo-incubator, but is not ready to be internationalized
-    # (like tempest)
-    _ = _LI = _LW = _LE = _LC = lambda x: x
diff -pruN 2.6.2-1/ceilometerclient/shell.py 2.9.0-0ubuntu4/ceilometerclient/shell.py
--- 2.6.2-1/ceilometerclient/shell.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/shell.py	2017-06-12 13:24:31.000000000 +0000
@@ -19,8 +19,10 @@ from __future__ import print_function
 import argparse
 import logging
 import sys
+import warnings
 
 from oslo_utils import encodeutils
+from oslo_utils import importutils
 import six
 
 import ceilometerclient
@@ -112,22 +114,13 @@ class CeilometerShell(object):
 
         self.subcommands = {}
         subparsers = parser.add_subparsers(metavar='<subcommand>')
-        submodule = utils.import_versioned_module(version, 'shell')
+        submodule = importutils.import_versioned_module('ceilometerclient',
+                                                        version, 'shell')
         self._find_actions(subparsers, submodule)
         self._find_actions(subparsers, self)
-        self._add_bash_completion_subparser(subparsers)
 
         return parser
 
-    def _add_bash_completion_subparser(self, subparsers):
-        subparser = subparsers.add_parser(
-            'bash_completion',
-            add_help=False,
-            formatter_class=HelpFormatter
-        )
-        self.subcommands['bash_completion'] = subparser
-        subparser.set_defaults(func=self.do_bash_completion)
-
     def _find_actions(self, subparsers, actions_module):
         for attr in (a for a in dir(actions_module) if a.startswith('do_')):
             # I prefer to be hypen-separated instead of underscores.
@@ -179,16 +172,11 @@ class CeilometerShell(object):
         # Return parsed args
         return api_version, subcommand_parser.parse_args(argv)
 
-    @staticmethod
-    def no_project_and_domain_set(args):
-        if not (args.os_project_id or (args.os_project_name and
-                (args.os_user_domain_name or args.os_user_domain_id)) or
-                (args.os_tenant_id or args.os_tenant_name)):
-            return True
-        else:
-            return False
-
     def main(self, argv):
+        warnings.warn(
+            "ceilometerclient is now deprecated as the Ceilometer API has "
+            "been deprecated. Please use either aodhclient, pankoclient or "
+            "gnocchiclient.")
         parsed = self.parse_args(argv)
         if parsed == 0:
             return 0
@@ -215,17 +203,12 @@ class CeilometerShell(object):
                                        "either --os-password or via "
                                        "env[OS_PASSWORD]")
 
-            if self.no_project_and_domain_set(args):
+            if not (args.os_project_id or args.os_project_name
+                    or args.os_tenant_id or args.os_tenant_name):
                 # steer users towards Keystone V3 API
-                raise exc.CommandError("You must provide a project_id via "
-                                       "either --os-project-id or via "
-                                       "env[OS_PROJECT_ID] and "
-                                       "a domain_name via either "
-                                       "--os-user-domain-name or via "
-                                       "env[OS_USER_DOMAIN_NAME] or "
-                                       "a domain_id via either "
-                                       "--os-user-domain-id or via "
-                                       "env[OS_USER_DOMAIN_ID]")
+                raise exc.CommandError("You must provide a project_id "
+                                       "(or name) via either --os-project-id "
+                                       "or via env[OS_PROJECT_ID]")
 
             if not self.auth_plugin.opts['auth_url']:
                 raise exc.CommandError("You must provide an auth url via "
@@ -255,7 +238,6 @@ class CeilometerShell(object):
                 options.add(option)
 
         commands.remove('bash-completion')
-        commands.remove('bash_completion')
         print(' '.join(commands | options))
 
     @utils.arg('command', metavar='<subcommand>', nargs='?',
diff -pruN 2.6.2-1/ceilometerclient/tests/functional/test_readonly_ceilometer.py 2.9.0-0ubuntu4/ceilometerclient/tests/functional/test_readonly_ceilometer.py
--- 2.6.2-1/ceilometerclient/tests/functional/test_readonly_ceilometer.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/functional/test_readonly_ceilometer.py	2017-06-12 13:24:31.000000000 +0000
@@ -63,9 +63,5 @@ class SimpleReadOnlyCeilometerClientTest
 
     # Optional arguments
 
-    def test_ceilometer_version(self):
-        version = self.ceilometer('', flags='--version', merge_stderr=True)
-        self.assertTrue(re.search('^[0-9.]+', version))
-
     def test_ceilometer_debug_list(self):
         self.ceilometer('meter-list', flags='--debug')
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/test_client.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/test_client.py
--- 2.6.2-1/ceilometerclient/tests/unit/test_client.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/test_client.py	2017-06-12 13:24:31.000000000 +0000
@@ -19,9 +19,9 @@ from keystoneauth1 import session as ks_
 import mock
 import requests
 
+from ceilometerclient.apiclient import exceptions
 from ceilometerclient import client
 from ceilometerclient import exc
-from ceilometerclient.openstack.common.apiclient import exceptions
 from ceilometerclient.tests.unit import utils
 from ceilometerclient.v2 import client as v2client
 
@@ -43,8 +43,9 @@ class ClientTest(utils.BaseTestCase):
     def create_client(env, api_version=2, endpoint=None, exclude=[]):
         env = dict((k, v) for k, v in env.items()
                    if k not in exclude)
-        with mock.patch('ceilometerclient.v2.client.Client._get_alarm_client',
-                        return_value=None):
+        with mock.patch(
+                'ceilometerclient.v2.client.Client._get_redirect_client',
+                return_value=None):
             return client.get_client(api_version, **env)
 
     def test_client_v2_with_session(self):
@@ -132,7 +133,7 @@ class ClientTest(utils.BaseTestCase):
             'user_agent': None,
             'debug': None,
         }
-        cls = 'ceilometerclient.openstack.common.apiclient.client.HTTPClient'
+        cls = 'ceilometerclient.apiclient.client.HTTPClient'
         with mock.patch(cls) as mocked:
             self.create_client(env)
             mocked.assert_called_with(**expected)
@@ -173,7 +174,7 @@ class ClientTest(utils.BaseTestCase):
     def test_v2_client_insecure(self):
         env = FAKE_ENV.copy()
         env.pop('auth_plugin')
-        env['insecure'] = 'True'
+        env['os_insecure'] = 'True'
         client = self.create_client(env)
         self.assertIn('insecure', client.auth_plugin.opts)
         self.assertEqual('True', client.auth_plugin.opts['insecure'])
@@ -184,8 +185,9 @@ class ClientTest2(ClientTest):
     def create_client(env, api_version=2, endpoint=None, exclude=[]):
         env = dict((k, v) for k, v in env.items()
                    if k not in exclude)
-        with mock.patch('ceilometerclient.v2.client.Client._get_alarm_client',
-                        return_value=None):
+        with mock.patch(
+                'ceilometerclient.v2.client.Client._get_redirect_client',
+                return_value=None):
             return client.Client(api_version, endpoint, **env)
 
 
@@ -194,7 +196,7 @@ class ClientTestWithAodh(ClientTest):
     def create_client(env, api_version=2, endpoint=None, exclude=[]):
         env = dict((k, v) for k, v in env.items()
                    if k not in exclude)
-        with mock.patch('ceilometerclient.openstack.common.apiclient.client.'
+        with mock.patch('ceilometerclient.apiclient.client.'
                         'HTTPClient.client_request',
                         return_value=mock.MagicMock()):
             return client.get_client(api_version, **env)
@@ -219,7 +221,7 @@ class ClientTestWithAodh(ClientTest):
     def test_ceilometerclient_available_without_aodh_services_running(self):
         env = FAKE_ENV.copy()
         env.pop('auth_plugin', None)
-        with mock.patch('ceilometerclient.openstack.common.apiclient.client.'
+        with mock.patch('ceilometerclient.apiclient.client.'
                         'HTTPClient.client_request') as mocked_request:
             mocked_request.side_effect = requests.exceptions.ConnectionError
             ceiloclient = client.get_client(2, **env)
@@ -250,7 +252,7 @@ class ClientAuthTest(utils.BaseTestCase)
     def create_client(env, api_version=2, endpoint=None, exclude=[]):
         env = dict((k, v) for k, v in env.items()
                    if k not in exclude)
-        with mock.patch('ceilometerclient.openstack.common.apiclient.client.'
+        with mock.patch('ceilometerclient.apiclient.client.'
                         'HTTPClient.client_request',
                         return_value=mock.MagicMock()):
             return client.get_client(api_version, **env)
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/test_shell.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/test_shell.py
--- 2.6.2-1/ceilometerclient/tests/unit/test_shell.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/test_shell.py	2017-06-12 13:24:31.000000000 +0000
@@ -19,9 +19,9 @@ import mock
 import six
 from testtools import matchers
 
+from ceilometerclient.apiclient import client as api_client
 from ceilometerclient import client
 from ceilometerclient import exc
-from ceilometerclient.openstack.common.apiclient import client as api_client
 from ceilometerclient import shell as ceilometer_shell
 from ceilometerclient.tests.unit import utils
 
@@ -112,18 +112,18 @@ class ShellBashCompletionTest(ShellTestB
 class ShellKeystoneV2Test(ShellTestBase):
 
     @mock.patch.object(ks_session, 'Session')
-    @mock.patch('ceilometerclient.v2.client.Client._get_alarm_client',
-                return_value=None)
-    def test_debug_switch_raises_error(self, get_alarm_client, mock_ksclient):
+    @mock.patch('ceilometerclient.v2.client.Client._get_redirect_client',
+                mock.Mock(return_value=None))
+    def test_debug_switch_raises_error(self, mock_ksclient):
         mock_ksclient.side_effect = exc.HTTPUnauthorized
         self.make_env(FAKE_V2_ENV)
         args = ['--debug', 'event-list']
         self.assertRaises(exc.CommandError, ceilometer_shell.main, args)
 
     @mock.patch.object(ks_session, 'Session')
-    @mock.patch('ceilometerclient.v2.client.Client._get_alarm_client',
-                return_value=None)
-    def test_dash_d_switch_raises_error(self, get_alarm_client, mock_ksclient):
+    @mock.patch('ceilometerclient.v2.client.Client._get_redirect_client',
+                mock.Mock(return_value=None))
+    def test_dash_d_switch_raises_error(self, mock_ksclient):
         mock_ksclient.side_effect = exc.CommandError("FAIL")
         self.make_env(FAKE_V2_ENV)
         args = ['-d', 'event-list']
@@ -141,9 +141,9 @@ class ShellKeystoneV2Test(ShellTestBase)
 class ShellKeystoneV3Test(ShellTestBase):
 
     @mock.patch.object(ks_session, 'Session')
-    @mock.patch('ceilometerclient.v2.client.Client._get_alarm_client',
-                return_value=None)
-    def test_debug_switch_raises_error(self, get_alarm_client, mock_ksclient):
+    @mock.patch('ceilometerclient.v2.client.Client._get_redirect_client',
+                mock.Mock(return_value=None))
+    def test_debug_switch_raises_error(self, mock_ksclient):
         mock_ksclient.side_effect = exc.HTTPUnauthorized
         self.make_env(FAKE_V3_ENV)
         args = ['--debug', 'event-list']
@@ -194,9 +194,9 @@ class ShellTimeoutTest(ShellTestBase):
         self._test_timeout('0', expected_msg)
 
     @mock.patch.object(ks_session, 'Session')
-    @mock.patch('ceilometerclient.v2.client.Client._get_alarm_client',
-                return_value=None)
-    def test_timeout_keystone_session(self, get_alarm_client, mocked_session):
+    @mock.patch('ceilometerclient.v2.client.Client._get_redirect_client',
+                mock.Mock(return_value=None))
+    def test_timeout_keystone_session(self, mocked_session):
         mocked_session.side_effect = exc.HTTPUnauthorized("FAIL")
         self.make_env(FAKE_V2_ENV)
         args = ['--debug', '--timeout', '5', 'alarm-list']
@@ -208,9 +208,9 @@ class ShellTimeoutTest(ShellTestBase):
 class ShellInsecureTest(ShellTestBase):
 
     @mock.patch.object(api_client, 'HTTPClient')
-    @mock.patch('ceilometerclient.v2.client.Client._get_alarm_client',
-                return_value=None)
-    def test_insecure_true_ceilometer(self, get_alarm_client, mocked_client):
+    @mock.patch('ceilometerclient.v2.client.Client._get_redirect_client',
+                mock.Mock(return_value=None))
+    def test_insecure_true_ceilometer(self, mocked_client):
         self.make_env(FAKE_V2_ENV)
         args = ['--debug', '--os-insecure', 'true', 'alarm-list']
         self.assertIsNone(ceilometer_shell.main(args))
@@ -218,9 +218,9 @@ class ShellInsecureTest(ShellTestBase):
         self.assertFalse(kwargs.get('verify'))
 
     @mock.patch.object(ks_session, 'Session')
-    @mock.patch('ceilometerclient.v2.client.Client._get_alarm_client',
-                return_value=None)
-    def test_insecure_true_keystone(self, get_alarm_client, mocked_session):
+    @mock.patch('ceilometerclient.v2.client.Client._get_redirect_client',
+                mock.Mock(return_value=None))
+    def test_insecure_true_keystone(self, mocked_session):
         mocked_session.side_effect = exc.HTTPUnauthorized("FAIL")
         self.make_env(FAKE_V2_ENV)
         args = ['--debug', '--os-insecure', 'true', 'alarm-list']
@@ -229,9 +229,9 @@ class ShellInsecureTest(ShellTestBase):
         self.assertFalse(kwargs.get('verify'))
 
     @mock.patch.object(api_client, 'HTTPClient')
-    @mock.patch('ceilometerclient.v2.client.Client._get_alarm_client',
-                return_value=None)
-    def test_insecure_false_ceilometer(self, get_alarm_client, mocked_client):
+    @mock.patch('ceilometerclient.v2.client.Client._get_redirect_client',
+                mock.Mock(return_value=None))
+    def test_insecure_false_ceilometer(self, mocked_client):
         self.make_env(FAKE_V2_ENV)
         args = ['--debug', '--os-insecure', 'false', 'alarm-list']
         self.assertIsNone(ceilometer_shell.main(args))
@@ -239,9 +239,9 @@ class ShellInsecureTest(ShellTestBase):
         self.assertTrue(kwargs.get('verify'))
 
     @mock.patch.object(ks_session, 'Session')
-    @mock.patch('ceilometerclient.v2.client.Client._get_alarm_client',
-                return_value=None)
-    def test_insecure_false_keystone(self, get_alarm_client, mocked_session):
+    @mock.patch('ceilometerclient.v2.client.Client._get_redirect_client',
+                mock.Mock(return_value=None))
+    def test_insecure_false_keystone(self, mocked_session):
         mocked_session.side_effect = exc.HTTPUnauthorized("FAIL")
         self.make_env(FAKE_V2_ENV)
         args = ['--debug', '--os-insecure', 'false', 'alarm-list']
@@ -270,7 +270,7 @@ class ShellEndpointTest(ShellTestBase):
 
 class ShellAlarmUpdateRepeatAction(ShellTestBase):
     @mock.patch('ceilometerclient.v2.alarms.AlarmManager.update')
-    @mock.patch('ceilometerclient.v2.client.Client._get_alarm_client',
+    @mock.patch('ceilometerclient.v2.client.Client._get_redirect_client',
                 mock.Mock())
     def test_repeat_action_not_specified(self, mocked):
         self.make_env(FAKE_V2_ENV)
@@ -279,7 +279,7 @@ class ShellAlarmUpdateRepeatAction(Shell
             args = ['--debug', method, '--state', 'alarm', '123']
             ceilometer_shell.main(args)
             args, kwargs = mocked.call_args
-            self.assertEqual(None, kwargs.get('repeat_actions'))
+            self.assertIsNone(kwargs.get('repeat_actions'))
 
         _test('alarm-update')
         _test('alarm-threshold-update')
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/v2/test_alarms.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_alarms.py
--- 2.6.2-1/ceilometerclient/tests/unit/v2/test_alarms.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_alarms.py	2017-06-12 13:24:31.000000000 +0000
@@ -19,9 +19,9 @@ import six
 from six.moves import xrange  # noqa
 import testtools
 
+from ceilometerclient.apiclient import client
+from ceilometerclient.apiclient import fake_client
 from ceilometerclient import exc
-from ceilometerclient.openstack.common.apiclient import client
-from ceilometerclient.openstack.common.apiclient import fake_client
 from ceilometerclient.v2 import alarms
 
 AN_ALARM = {u'alarm_actions': [u'http://site:8000/alarm'],
@@ -400,7 +400,7 @@ class AlarmManagerTest(testtools.TestCas
             alarm = self.mgr.update(alarm_id='unk-alarm-id', **UPDATE_ALARM)
         except exc.CommandError:
             pass
-        self.assertEqual(alarm, None)
+        self.assertIsNone(alarm)
 
     def test_delete_from_alarm_class(self):
         alarm = self.mgr.get(alarm_id='alarm-id')
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/v2/test_capabilities.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_capabilities.py
--- 2.6.2-1/ceilometerclient/tests/unit/v2/test_capabilities.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_capabilities.py	2017-06-12 13:24:31.000000000 +0000
@@ -14,8 +14,8 @@
 
 import testtools
 
-from ceilometerclient.openstack.common.apiclient import client
-from ceilometerclient.openstack.common.apiclient import fake_client
+from ceilometerclient.apiclient import client
+from ceilometerclient.apiclient import fake_client
 from ceilometerclient.v2 import capabilities
 
 
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/v2/test_events.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_events.py
--- 2.6.2-1/ceilometerclient/tests/unit/v2/test_events.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_events.py	2017-06-12 13:24:31.000000000 +0000
@@ -11,8 +11,8 @@
 #    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 ceilometerclient.openstack.common.apiclient import client
-from ceilometerclient.openstack.common.apiclient import fake_client
+from ceilometerclient.apiclient import client
+from ceilometerclient.apiclient import fake_client
 from ceilometerclient.tests.unit import utils
 import ceilometerclient.v2.events
 
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/v2/test_event_types.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_event_types.py
--- 2.6.2-1/ceilometerclient/tests/unit/v2/test_event_types.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_event_types.py	2017-06-12 13:24:31.000000000 +0000
@@ -13,8 +13,8 @@
 #    under the License.
 
 
-from ceilometerclient.openstack.common.apiclient import client
-from ceilometerclient.openstack.common.apiclient import fake_client
+from ceilometerclient.apiclient import client
+from ceilometerclient.apiclient import fake_client
 from ceilometerclient.tests.unit import utils
 import ceilometerclient.v2.event_types
 
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/v2/test_query_alarm_history.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_query_alarm_history.py
--- 2.6.2-1/ceilometerclient/tests/unit/v2/test_query_alarm_history.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_query_alarm_history.py	2017-06-12 13:24:31.000000000 +0000
@@ -12,8 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from ceilometerclient.openstack.common.apiclient import client
-from ceilometerclient.openstack.common.apiclient import fake_client
+from ceilometerclient.apiclient import client
+from ceilometerclient.apiclient import fake_client
 from ceilometerclient.tests.unit import utils
 from ceilometerclient.v2 import query
 
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/v2/test_query_alarms.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_query_alarms.py
--- 2.6.2-1/ceilometerclient/tests/unit/v2/test_query_alarms.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_query_alarms.py	2017-06-12 13:24:31.000000000 +0000
@@ -12,8 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from ceilometerclient.openstack.common.apiclient import client
-from ceilometerclient.openstack.common.apiclient import fake_client
+from ceilometerclient.apiclient import client
+from ceilometerclient.apiclient import fake_client
 from ceilometerclient.tests.unit import utils
 from ceilometerclient.v2 import query
 
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/v2/test_query_samples.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_query_samples.py
--- 2.6.2-1/ceilometerclient/tests/unit/v2/test_query_samples.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_query_samples.py	2017-06-12 13:24:31.000000000 +0000
@@ -12,8 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from ceilometerclient.openstack.common.apiclient import client
-from ceilometerclient.openstack.common.apiclient import fake_client
+from ceilometerclient.apiclient import client
+from ceilometerclient.apiclient import fake_client
 from ceilometerclient.tests.unit import utils
 from ceilometerclient.v2 import query
 
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/v2/test_resources.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_resources.py
--- 2.6.2-1/ceilometerclient/tests/unit/v2/test_resources.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_resources.py	2017-06-12 13:24:31.000000000 +0000
@@ -12,8 +12,8 @@
 #    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 ceilometerclient.openstack.common.apiclient import client
-from ceilometerclient.openstack.common.apiclient import fake_client
+from ceilometerclient.apiclient import client
+from ceilometerclient.apiclient import fake_client
 from ceilometerclient.tests.unit import utils
 import ceilometerclient.v2.resources
 
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/v2/test_samples.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_samples.py
--- 2.6.2-1/ceilometerclient/tests/unit/v2/test_samples.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_samples.py	2017-06-12 13:24:31.000000000 +0000
@@ -15,8 +15,8 @@
 
 import copy
 
-from ceilometerclient.openstack.common.apiclient import client
-from ceilometerclient.openstack.common.apiclient import fake_client
+from ceilometerclient.apiclient import client
+from ceilometerclient.apiclient import fake_client
 from ceilometerclient.tests.unit import utils
 import ceilometerclient.v2.samples
 
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/v2/test_shell.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_shell.py
--- 2.6.2-1/ceilometerclient/tests/unit/v2/test_shell.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_shell.py	2017-06-12 13:24:31.000000000 +0000
@@ -651,7 +651,7 @@ class ShellAlarmGnocchiCommandTest(test_
     def _test_alarm_gnocchi_resources_arguments(self, action, argv):
         self.make_env(test_shell.FAKE_V2_ENV)
         with mock.patch.object(alarms.AlarmManager, action) as mocked:
-            with mock.patch('ceilometerclient.openstack.common.apiclient.'
+            with mock.patch('ceilometerclient.apiclient.'
                             'client.HTTPClient.client_request') as request:
                 request.site_effect = exceptions.EndpointNotFound
                 base_shell.main(argv)
@@ -673,7 +673,7 @@ class ShellAlarmGnocchiCommandTest(test_
     def _test_alarm_gnocchi_aggr_by_metrics_arguments(self, action, argv):
         self.make_env(test_shell.FAKE_V2_ENV)
         with mock.patch.object(alarms.AlarmManager, action) as mocked:
-            with mock.patch('ceilometerclient.openstack.common.apiclient.'
+            with mock.patch('ceilometerclient.apiclient.'
                             'client.HTTPClient.client_request') as request:
                 request.site_effect = exceptions.EndpointNotFound
                 base_shell.main(argv)
@@ -695,7 +695,7 @@ class ShellAlarmGnocchiCommandTest(test_
     def _test_alarm_gnocchi_aggr_by_resources_arguments(self, action, argv):
         self.make_env(test_shell.FAKE_V2_ENV)
         with mock.patch.object(alarms.AlarmManager, action) as mocked:
-            with mock.patch('ceilometerclient.openstack.common.apiclient.'
+            with mock.patch('ceilometerclient.apiclient.'
                             'client.HTTPClient.client_request') as request:
                 request.site_effect = exceptions.EndpointNotFound
                 base_shell.main(argv)
@@ -1633,7 +1633,7 @@ class ShellShadowedArgsTest(test_shell.S
             '--user-id', 'the-user-id-i-want-to-set',
             '--name', 'project-id-test'] + args
         with mock.patch.object(alarms.AlarmManager, method) as mocked:
-            with mock.patch('ceilometerclient.openstack.common.apiclient.'
+            with mock.patch('ceilometerclient.apiclient.'
                             'client.HTTPClient.client_request') as request:
                 request.site_effect = exceptions.EndpointNotFound
                 base_shell.main(cli_args)
@@ -1724,7 +1724,7 @@ class ShellShadowedArgsTest(test_shell.S
             '--meter-unit', 'ns',
             '--sample-volume', '10086',
         ]
-        with mock.patch('ceilometerclient.openstack.common.apiclient.client.'
+        with mock.patch('ceilometerclient.apiclient.client.'
                         'HTTPClient.client_request') as client_request:
             client_request.site_effect = exceptions.EndpointNotFound
             base_shell.main(cli_args)
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/v2/test_statistics.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_statistics.py
--- 2.6.2-1/ceilometerclient/tests/unit/v2/test_statistics.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_statistics.py	2017-06-12 13:24:31.000000000 +0000
@@ -12,8 +12,8 @@
 #    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 ceilometerclient.openstack.common.apiclient import client
-from ceilometerclient.openstack.common.apiclient import fake_client
+from ceilometerclient.apiclient import client
+from ceilometerclient.apiclient import fake_client
 from ceilometerclient.tests.unit import utils
 import ceilometerclient.v2.statistics
 
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/v2/test_trait_descriptions.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_trait_descriptions.py
--- 2.6.2-1/ceilometerclient/tests/unit/v2/test_trait_descriptions.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_trait_descriptions.py	2017-06-12 13:24:31.000000000 +0000
@@ -11,8 +11,8 @@
 #    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 ceilometerclient.openstack.common.apiclient import client
-from ceilometerclient.openstack.common.apiclient import fake_client
+from ceilometerclient.apiclient import client
+from ceilometerclient.apiclient import fake_client
 from ceilometerclient.tests.unit import utils
 import ceilometerclient.v2.trait_descriptions
 
diff -pruN 2.6.2-1/ceilometerclient/tests/unit/v2/test_traits.py 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_traits.py
--- 2.6.2-1/ceilometerclient/tests/unit/v2/test_traits.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/tests/unit/v2/test_traits.py	2017-06-12 13:24:31.000000000 +0000
@@ -11,8 +11,8 @@
 #    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 ceilometerclient.openstack.common.apiclient import client
-from ceilometerclient.openstack.common.apiclient import fake_client
+from ceilometerclient.apiclient import client
+from ceilometerclient.apiclient import fake_client
 from ceilometerclient.tests.unit import utils
 import ceilometerclient.v2.traits
 
diff -pruN 2.6.2-1/ceilometerclient/v2/alarms.py 2.9.0-0ubuntu4/ceilometerclient/v2/alarms.py
--- 2.6.2-1/ceilometerclient/v2/alarms.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/v2/alarms.py	2017-06-12 13:24:31.000000000 +0000
@@ -70,13 +70,7 @@ class AlarmChange(base.Resource):
 class AlarmManager(base.Manager):
     resource_class = Alarm
 
-    def __init__(self, api, aodh_enabled=False):
-        self.aodh_enabled = aodh_enabled
-        super(AlarmManager, self).__init__(api)
-
     def _path(self, id=None):
-        # TODO(liusheng) if aodh will only have v1 api, we need to change
-        # following path if aodh enabled (self.aodh_enabled)
         return '/v2/alarms/%s' % id if id else '/v2/alarms'
 
     def list(self, q=None):
diff -pruN 2.6.2-1/ceilometerclient/v2/client.py 2.9.0-0ubuntu4/ceilometerclient/v2/client.py
--- 2.6.2-1/ceilometerclient/v2/client.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/v2/client.py	2017-06-12 13:24:31.000000000 +0000
@@ -62,21 +62,28 @@ class Client(object):
         self.auth_plugin = kwargs.get('auth_plugin')
 
         self.http_client = ceiloclient._construct_http_client(**kwargs)
-        self.alarm_client = self._get_alarm_client(**kwargs)
+        self.alarm_client = self._get_redirect_client(
+            'alarming', 'aodh', **kwargs)
         aodh_enabled = self.alarm_client is not None
         if not aodh_enabled:
             self.alarm_client = self.http_client
+        self.event_client = self._get_redirect_client(
+            'event', 'panko', **kwargs)
+        panko_enabled = self.event_client is not None
+        if not panko_enabled:
+            self.event_client = self.http_client
+
         self.meters = meters.MeterManager(self.http_client)
         self.samples = samples.OldSampleManager(self.http_client)
         self.new_samples = samples.SampleManager(self.http_client)
         self.statistics = statistics.StatisticsManager(self.http_client)
         self.resources = resources.ResourceManager(self.http_client)
-        self.alarms = alarms.AlarmManager(self.alarm_client, aodh_enabled)
-        self.events = events.EventManager(self.http_client)
-        self.event_types = event_types.EventTypeManager(self.http_client)
-        self.traits = traits.TraitManager(self.http_client)
+        self.alarms = alarms.AlarmManager(self.alarm_client)
+        self.events = events.EventManager(self.event_client)
+        self.event_types = event_types.EventTypeManager(self.event_client)
+        self.traits = traits.TraitManager(self.event_client)
         self.trait_descriptions = trait_descriptions.\
-            TraitDescriptionManager(self.http_client)
+            TraitDescriptionManager(self.event_client)
 
         self.query_samples = query.QuerySamplesManager(
             self.http_client)
@@ -86,36 +93,36 @@ class Client(object):
         self.capabilities = capabilities.CapabilitiesManager(self.http_client)
 
     @staticmethod
-    def _get_alarm_client(**ceilo_kwargs):
-        """Get client for alarm manager that redirect to aodh."""
+    def _get_redirect_client(new_service_type, new_service, **ceilo_kwargs):
+        """Get client for new service manager to redirect to."""
         # NOTE(sileht): the auth_plugin/keystone session cannot be copied
         # because they rely on threading module.
         auth_plugin = ceilo_kwargs.pop('auth_plugin', None)
         session = ceilo_kwargs.pop('session', None)
 
         kwargs = copy.deepcopy(ceilo_kwargs)
-        kwargs["service_type"] = "alarming"
-        aodh_endpoint = ceilo_kwargs.get('aodh_endpoint')
+        kwargs["service_type"] = new_service_type
+        endpoint = ceilo_kwargs.get('%s_endpoint' % new_service)
 
         if session:
             # keystone session can be shared between client
             ceilo_kwargs['session'] = kwargs['session'] = session
-            if aodh_endpoint:
-                kwargs['endpoint_override'] = aodh_endpoint
+            if endpoint:
+                kwargs['endpoint_override'] = endpoint
         elif auth_plugin and kwargs.get('auth_url'):
             ceilo_kwargs['auth_plugin'] = auth_plugin
             kwargs.pop('endpoint', None)
             kwargs['auth_plugin'] = ceiloclient.get_auth_plugin(
-                aodh_endpoint, **kwargs)
+                endpoint, **kwargs)
         else:
             # Users may just provide ceilometer endpoint and token, and no
             # auth_url, in this case, we need 'aodh_endpoint' also to be
             # provided, otherwise we cannot get aodh endpoint from
-            # keystone, and assume aodh is unavailable.
+            # keystone, and assume aodh is unavailable. Same applies to panko.
             return None
 
         try:
-            # NOTE(sileht): try to use aodh
+            # NOTE(sileht): try to use redirect
             c = ceiloclient._construct_http_client(**kwargs)
             c.get("/")
             return c
diff -pruN 2.6.2-1/ceilometerclient/v2/shell.py 2.9.0-0ubuntu4/ceilometerclient/v2/shell.py
--- 2.6.2-1/ceilometerclient/v2/shell.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/ceilometerclient/v2/shell.py	2017-06-12 13:24:31.000000000 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright 2013 Red Hat, Inc
+# Copyright 2013-2016 Red Hat, Inc
 # Copyright Ericsson AB 2014. All rights reserved
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -17,6 +17,7 @@
 import argparse
 import functools
 import json
+import warnings
 
 from oslo_serialization import jsonutils
 from oslo_utils import strutils
@@ -396,6 +397,7 @@ def alarm_change_detail_formatter(change
                 'but if supplied must be string, integer, float, or boolean.')
 def do_alarm_list(cc, args={}):
     """List the user's alarms."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     alarms = cc.alarms.list(q=options.cli_to_array(args.query))
     _display_alarm_list(alarms, sortby=0)
 
@@ -440,6 +442,7 @@ def _display_alarm(alarm):
            action=NotEmptyAction, help='ID of the alarm to show.')
 def do_alarm_show(cc, args={}):
     """Show an alarm."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     alarm = cc.alarms.get(args.alarm_id)
     # alarm.get actually catches the HTTPNotFound exception and turns the
     # result into None if the alarm wasn't found.
@@ -633,6 +636,7 @@ def common_alarm_event_arguments():
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_create(cc, args={}):
     """Create a new alarm (Deprecated). Use alarm-threshold-create instead."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
     fields = utils.args_array_to_list_of_dicts(fields, "time_constraints")
     fields = utils.args_array_to_dict(fields, "matching_metadata")
@@ -648,6 +652,7 @@ def do_alarm_create(cc, args={}):
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_gnocchi_resources_threshold_create(cc, args={}):
     """Create a new alarm based on computed statistics."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
     fields = utils.args_array_to_list_of_dicts(fields, 'time_constraints')
     fields = utils.key_with_slash_to_nested_dict(fields)
@@ -664,6 +669,7 @@ def do_alarm_gnocchi_resources_threshold
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_gnocchi_aggregation_by_metrics_threshold_create(cc, args={}):
     """Create a new alarm based on computed statistics."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
     fields = utils.args_array_to_list_of_dicts(fields, 'time_constraints')
     fields = utils.key_with_slash_to_nested_dict(fields)
@@ -680,6 +686,7 @@ def do_alarm_gnocchi_aggregation_by_metr
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_gnocchi_aggregation_by_resources_threshold_create(cc, args={}):
     """Create a new alarm based on computed statistics."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
     fields = utils.args_array_to_list_of_dicts(fields, 'time_constraints')
     fields = utils.key_with_slash_to_nested_dict(fields)
@@ -716,6 +723,7 @@ def do_alarm_gnocchi_aggregation_by_reso
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_threshold_create(cc, args={}):
     """Create a new alarm based on computed statistics."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
     fields = utils.args_array_to_list_of_dicts(fields, 'time_constraints')
     fields = utils.key_with_slash_to_nested_dict(fields)
@@ -739,6 +747,7 @@ def do_alarm_threshold_create(cc, args={
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_combination_create(cc, args={}):
     """Create a new alarm based on state of other alarms."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
     fields = utils.args_array_to_list_of_dicts(fields, 'time_constraints')
     fields = utils.key_with_slash_to_nested_dict(fields)
@@ -753,6 +762,7 @@ def do_alarm_combination_create(cc, args
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_event_create(cc, args={}):
     """Create a new alarm based on events."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: x[1] is not None, vars(args).items()))
     fields = utils.key_with_slash_to_nested_dict(fields)
     fields['type'] = 'event'
@@ -795,6 +805,7 @@ def do_alarm_event_create(cc, args={}):
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_update(cc, args={}):
     """Update an existing alarm (Deprecated)."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
     fields = utils.args_array_to_list_of_dicts(fields, "time_constraints")
     fields = utils.args_array_to_dict(fields, "matching_metadata")
@@ -844,6 +855,7 @@ def do_alarm_update(cc, args={}):
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_threshold_update(cc, args={}):
     """Update an existing alarm based on computed statistics."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
     fields = utils.args_array_to_list_of_dicts(fields, 'time_constraints')
     fields = utils.key_with_slash_to_nested_dict(fields)
@@ -875,6 +887,7 @@ def do_alarm_threshold_update(cc, args={
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_gnocchi_resources_threshold_update(cc, args={}):
     """Update an existing alarm based on computed statistics."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
     fields = utils.args_array_to_list_of_dicts(fields, 'time_constraints')
     fields = utils.key_with_slash_to_nested_dict(fields)
@@ -904,6 +917,7 @@ def do_alarm_gnocchi_resources_threshold
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_gnocchi_aggregation_by_metrics_threshold_update(cc, args={}):
     """Update an existing alarm based on computed statistics."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
     fields = utils.args_array_to_list_of_dicts(fields, 'time_constraints')
     fields = utils.key_with_slash_to_nested_dict(fields)
@@ -933,6 +947,7 @@ def do_alarm_gnocchi_aggregation_by_metr
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_gnocchi_aggregation_by_resources_threshold_update(cc, args={}):
     """Update an existing alarm based on computed statistics."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
     fields = utils.args_array_to_list_of_dicts(fields, 'time_constraints')
     fields = utils.key_with_slash_to_nested_dict(fields)
@@ -966,6 +981,7 @@ def do_alarm_gnocchi_aggregation_by_reso
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_combination_update(cc, args={}):
     """Update an existing alarm based on state of other alarms."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: not (x[1] is None), vars(args).items()))
     fields = utils.args_array_to_list_of_dicts(fields, 'time_constraints')
     fields = utils.key_with_slash_to_nested_dict(fields)
@@ -989,6 +1005,7 @@ def do_alarm_combination_update(cc, args
 @_restore_shadowed_arg('user_id', 'alarm_user_id')
 def do_alarm_event_update(cc, args={}):
     """Update an existing alarm based on events."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     fields = dict(filter(lambda x: x[1] is not None, vars(args).items()))
     fields = utils.key_with_slash_to_nested_dict(fields)
     fields.pop('alarm_id')
@@ -1010,6 +1027,7 @@ def do_alarm_event_update(cc, args={}):
            action=NotEmptyAction, help='ID of the alarm to delete.')
 def do_alarm_delete(cc, args={}):
     """Delete an alarm."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     try:
         cc.alarms.delete(args.alarm_id)
     except exc.HTTPNotFound:
@@ -1026,6 +1044,7 @@ def do_alarm_delete(cc, args={}):
            '.')
 def do_alarm_state_set(cc, args={}):
     """Set the state of an alarm."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     try:
         state = cc.alarms.set_state(args.alarm_id, args.state)
     except exc.HTTPNotFound:
@@ -1040,6 +1059,7 @@ def do_alarm_state_set(cc, args={}):
            action=NotEmptyAction, help='ID of the alarm state to show.')
 def do_alarm_state_get(cc, args={}):
     """Get the state of an alarm."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     try:
         state = cc.alarms.get_state(args.alarm_id)
     except exc.HTTPNotFound:
@@ -1057,6 +1077,7 @@ def do_alarm_state_get(cc, args={}):
                 'but if supplied must be string, integer, float, or boolean.')
 def do_alarm_history(cc, args={}):
     """Display the change history of an alarm."""
+    warnings.warn("Alarm commands are deprecated, please use aodhclient")
     kwargs = dict(alarm_id=args.alarm_id,
                   q=options.cli_to_array(args.query))
     try:
diff -pruN 2.6.2-1/ChangeLog 2.9.0-0ubuntu4/ChangeLog
--- 2.6.2-1/ChangeLog	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/ChangeLog	2017-06-12 13:27:21.000000000 +0000
@@ -0,0 +1,573 @@
+CHANGES
+=======
+
+2.9.0
+-----
+
+* Deprecate ceilometerclient
+* [bugfix]with keystone v3 Could not find domain: default
+* delete bash\_completion in subcommand
+* Remove log translations
+* Remove support for py34
+* Handle log message interpolation by the logger
+* Adjust parameters order of tenant\_xxx and project\_xxx
+* Update reno for stable/ocata
+* shell: do not force domain to be present
+
+2.8.0
+-----
+
+* Enable coverage report in console output
+* cleanup aodh redirect
+* panko redirect
+* cleanup aodh mocks
+* [doc] Note lack of constraints is a choice
+* Adding default project and domain if nothing is specified
+* Don't include openstack/common in flake8 exclude list
+* Add \_\_ne\_\_ built-in function
+* Bump hacking to 0.12
+* move old oslo-incubator code out of openstack/common
+* Make method import\_versioned\_module work
+
+2.7.0
+-----
+
+* Fixes SSLError during cclient.meters.list() by https
+* Set code and details on HTTPException
+* Enable release notes translation
+* Using assertIsNone() instead of assertEqual(None)
+* Replace assertEqual(None, ...) with assertIsNone(...)
+* Deprecate alarms commands
+* Update reno for stable/newton
+* Fix from\_response method to process response from requests
+
+2.6.0
+-----
+
+* [trivial] add a blank character
+* Correct the parameters's position of assertEqual
+* Remove keystoneclient dependency
+* Add support for Python 3.5
+* Remove discover from test-requirements
+
+2.5.0
+-----
+
+* tools: remove unused scripts
+* base.Resource not define \_\_ne\_\_() built-in function
+* Ignore aodh\_endpoint argument
+* Switch to keystoneauth
+* Correct the usage of the method assertEqual()
+* Update the home-page with developer documentation
+* Update to hacking 0.11.0
+* Only install hacking in pep8
+* Updated from global requirements
+* Enable releasenotes documentation
+* Updated from global requirements
+* Switch from deprecated tempest-lib to tempest
+* Updated from global requirements
+* Fix the disorder of items of Traits in the output of event-list
+* remove default value of repeat-actions
+* Decouple ceilometerclient without aodh services running
+* Trivial: remove \`None\` as a redundant argument to dict.get()
+* Updated from global requirements
+* Updated from global requirements
+* Enhances client to support unique meter retrieval
+* Fixing a word spelling
+* Updated from global requirements
+* make aggregation-method argument as a mandatory field
+
+2.3.0
+-----
+
+* improve readme contents
+* Remove argparse from requirements
+* drop oslo-incubator modules: cliutils and uuidutils
+* Updated from global requirements
+* remove unused code
+* fix project\_id and user\_id fields not set when create gnocchi alarm
+* Updated from global requirements
+* improve help docs for cli commands
+* change the dict output format to make consistency under py27 and py34
+
+2.2.1
+-----
+
+* Only token or creds are required
+
+2.2.0
+-----
+
+* Fix to disable meter-links from CLI
+* Use the oslo.utils.reflection to extract the class name
+* remove py24 compatible code
+* Don't copy the auth\_plugin for aodh
+* Remove openstack-common.conf
+* Use assertTrue/False instead of assertEqual(T/F)
+* Improve ceilometer alarm enabled input parameter validation
+* Updated from global requirements
+* Replace assertEqual(None, \*) with assertIsNone in tests
+* remove MANIFEST.in
+* Updated from global requirements
+* Restructuring a comment in Python-Ceilometerclient
+* Deprecated tox -downloadcache option removed
+* Revert "Delete python bytecode before every test run"
+* Remove duplicated assert
+* Delete python bytecode before every test run
+* Fix Python 3 version announced in metadata
+* Remove py26 support
+* Fix the parameter order of assertEqual in ceilometerclient
+* Fix Resource.\_\_eq\_\_ mismatch semantics of object equal
+
+2.1.0
+-----
+
+* Updated from global requirements
+* Token will be lost when constructing a ceilometer client
+* Correct an api reference error
+* Ensure metering is the default service\_type
+* Ensure keystoneauth1 exception are raised
+* Ignores endpoint\_type if interface is provided
+* Remove double API requests
+* Catch exception raised by keystoneauth1
+* Updated from global requirements
+* Updated from global requirements
+
+2.0.1
+-----
+
+* Last sync from oslo-incubator
+* fix gnocchi alarm create to use right field name
+
+2.0.0
+-----
+
+* Update help message for alarm-gnocchi-resources-threshold-create
+* Updated from global requirements
+* Fix to enable meter-links on resource-list CLI
+* drop v1 client
+* Updated from global requirements
+* fix typos in docstring
+* print sample id for query-samples
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Move to keystone session object
+* Add statistic in rule information
+* Updated from global requirements
+* Change the word for clarity
+
+1.5.0
+-----
+
+* add limit support
+* do not generate meter links on resource-list
+* refactor: move 'repeat\_actions' to common args
+* Support alarm-event-{create,update}
+* Use new location of subunit2html
+* Updated from global requirements
+* Don't try to get aodh endpoint if auth\_url didn't provided
+* Updated from global requirements
+
+1.4.0
+-----
+
+* tenant\_id not required with keystone v3
+* Updated from global requirements
+* Add support for client redirecting to aodh endpoint if available
+* Updated from global requirements
+* Updated from global requirements
+* Fix unit tests failing caused by new Mock release
+* Updated from global requirements
+* Add ceilometerclient support for api-no-pipeline
+* Change default values from [] to None
+* Typo: Show an sample => Show a sample
+* Add alarm severity in alarm-history output
+* Updated from global requirements
+
+1.3.0
+-----
+
+* Explicit error for wrong resource metadata format
+* Removes whitespace from CLI queries
+* Add capability for creating array of samples
+* Updated from global requirements
+* Drop use of 'oslo' namespace package
+* Pass OS\_\* env vars fix for tox 2.0
+* Catch missing 404 exceptions in client
+* Use oslo\_utils instead of deprecated oslo.utils
+* [unittest] Increase client and shell modules cover
+* Fix alarm-evaluator can't start when ssl was enabled
+* Updated from global requirements
+* Updated from global requirements
+* remove useless event unit test code
+* Allow changing project-id and user-id by alarm-threshold-update
+* move capabilities ut code to unit dir
+* show raw details of event
+
+1.2.0
+-----
+
+* Uncap library requirements for liberty
+* update README.rst to help release process
+
+1.1.0
+-----
+
+* Add timeout for keystoneclient session
+* add region\_name to auth plugin parameters
+* Added missing ceilometer CLI tests
+* Updates examples to reference new sample format
+* ceilometerclient insecure argument no longer works
+* fix client docstring
+* Add CLI for Capabilities REST API
+* print user friendly error message for alarm update time constraints
+* ceilometerclient fails with keystone v3 auth
+* Updated from global requirements
+* Set auth\_plugin in \_\_init\_\_
+* support specify user-id when create sample and alarm
+* add in missing options
+* Add a post\_test\_hook for gate-run functional tests
+* Add cli functional tests from tempest
+* alarm: Use new gnocchi aggregation API
+* Move unit tests into their own subdirectory
+* Add a py34 target for tox
+* Fixes bug with Client function not setting up SSL params
+* Updated from global requirements
+* Enable specified project\_id in CLI commands
+
+1.0.13
+------
+
+* Updated from global requirements
+* Corrected the errors in sample-show and sample-create
+* Allow create/update gnocchi alarm rule
+* Don't enforce a kind of alarm rules
+* Support unicode for alarm
+* Update get\_client() parameters with correct variable names
+* Add Sample API support
+* add --no-traits for event-list
+* Updated from global requirements
+* Add severity field to alarm CLI
+* Updated from global requirements
+* Remove trailing space before , in the help string of --time-constraint
+* Fix improper parameter setup for cacert and client certs
+* Upgrade to hacking 0.10
+* event-list should sort by timestamp, not id
+* Allow all pep8 checks
+* Fix H105 pep8 error
+* Update hacking to global requirements
+* Triple double-quoted strings should be used for docstrings
+* Updated from global requirements
+* Support ceilometer-url and os-endpoint
+* sync to latest oslo-incubator code
+* Add apiclient to openstack-common.conf
+* Add client property for common.base.Manager
+* Allow graceful shutdown on Ctrl+C
+* Updated from global requirements
+* Make methods static where it's possible
+* Fix old-style classes declaration
+* Remove redundant parentheses (except openstack.common)
+* Enable --os-insecure CLI option
+* sync with oslo and use oslo.i18n
+* Workflow documentation is now in infra-manual
+* Updated from global requirements
+* Support os-endpoint-type
+* Alarm TimeConstraint display incorrect
+* Add \`requests\` to requirements
+* Fix timeout argument not treated as integer
+* Refactor tests/test\_shell.py
+* Add --slowest option for testr
+* Fix wrong initialization of AuthPlugin for keystone v3
+* Updated from global requirements
+* Add CONTRIBUTING.rst
+* Updated from global requirements
+* Updated from global requirements
+
+1.0.12
+------
+
+* sync oslo code
+* switch to oslo.utils
+
+1.0.11
+------
+
+* Reduce redundant parameter of some commands in CLI
+* Typo "authtenticated" instead of "authenticated"
+* Fix AuthPlugin authentification
+* Stop using intersphinx
+* Updated from global requirements
+* Fix sample-create in v2 api calls
+* keystone discovery fallback support
+* Fix a help string nit for statistics command
+* Verify alarm found before modifying
+* Revamp documentation, add module references
+* Check if the alarm has time constraints field before displaying
+* Updated from global requirements
+* Removed undefined method in install\_env.py file
+* Replace assertTrue with assertIsNotNone for check an object
+* Add endpoint opt into auth\_plugin
+* Updated from global requirements
+* Use HTTPClient from common Oslo code
+* Update developer docs template
+* Add doc/build to .gitignore
+* Add docs job to tox.ini
+* Don't expose X-Auth-Token in ceilometer CLI
+* Calculate a suitable column width for positional arguments
+* Use suitable assert
+* Improve --debug logging output
+* Update python-ceilometerclient to support Keystone V3 API
+* Updated from global requirements
+* Fix the alarm history order shown to user
+* Provide explicit help string of resource-metadata
+* Add methods to resource classes
+* Improve a bit query API
+* Fix hacking rules: H302,H305,H307,H402
+* Updated from global requirements
+* Fix alarm-threshold-update --query option
+* Refactor split\_by\_op and split\_by\_datatype
+* Remove © and remove unnecessary encoding lines
+* use mock instead of try...finally
+* Avoid unnecessary stderr message when run test
+* Avoid empty entity field in uri path
+* replace dict.iteritems() with six.iteritems(dict)
+* Fix exception handling of CLI
+* fixed several pep8 issues
+* Remove out-dated exceptions
+* extraneous vim editor configuration comments
+* Correct help string about insufficient\_data
+* Avoid dead loop when token is string format
+* Fix some help strings
+* Updated from global requirements
+* Revert "Fix temporary pypy gate issue with setuptools"
+* Display message on HTTPException
+* Update v2.options docstring
+* Correct testcase content
+
+1.0.10
+------
+
+* Ensure statistics aggregates are ordered with parameterized first
+* Statistics groupby handling improvement
+* Implementation of statistics aggregators
+* Adds alarm time constraint support to ceilometer CLI
+* Updated from global requirements
+* Fix temporary pypy gate issue with setuptools
+* Add complex query support for alarm history
+* Add complex query support for alarms
+* Checking the type of auth\_token, and fixing it if necessary
+* Deprecate 'alarm-update'
+* Add complex query support for samples
+* test created virtual env directory should git ignored
+* Updated from global requirements
+* Fix the ceilometer trait-description-list command
+* Updated from global requirements
+* py3kcompat: remove in python-ceilometerclient
+* Python 3 compatibility
+* Fix a typo in a comment in v2 client
+* test\_url\_generation\_with\_proxy: do not use contextlib.nested()
+* Ensure url sent to proxy don't have redundant /
+* Remove unused mock in v2/test\_shell.py
+* fix help message of deprecated command
+* Sync with Oslo
+* Python 3: fix format\_nested\_list\_of\_dict()
+* Remove tox locale overrides
+* Improve help strings
+
+1.0.9
+-----
+
+* Modify ceilometer client cmd line help info
+* Remove unused import for print\_function
+* Remove ununsed httplib2 requirement
+* Updated from global requirements
+* Update client to display data type of traits
+* Using common methods from oslo cliutils
+* Avoid discarding alarm-threshold-create --query option
+* Fix typos picked up by misspellings
+* return sample info when creating sample with CLI
+* Enable hacking H233 rule
+* Using common method 'bool\_from\_string' from oslo strutils
+* Raise traceback on error when using CLI and -debug
+* Remove print debugs statements
+* replace assertTrue(isinstance) to assertIsInstance
+* Add support for groupby in statistics for API v2
+* Remove dependencies on pep8, pyflakes and flake8
+* Replace inheritance hierarchy with composition
+* fix optional parameter of creating sample
+* abbreviating --meter-name to -m in alarm commands
+* Remove unused imports
+* Support the Event API
+* Python 3: fix test\_sample\_list
+* Use Resource() class from common Oslo code
+* client looking at wrong cacert argument name
+* Supports bash\_completion for ceilometerclient
+* Fix the ceilometerlient log curl request incorrectly
+* Python 3: use six.moves.zip() rather than itertools.izip()
+* Display message on HTTP 400
+* Fix alarm-combination-update operator argument
+* Improve description of some commands
+* Updates tox.ini to use new features
+* Updated from global requirements
+
+1.0.8
+-----
+
+* sync with oslo-incubator
+* Change OpenStack Metering to OpenStack Telemetry
+* Update .gitignore
+* Add HTTP proxy support to ceilometer client
+* Encode exception on ceilometer-client for UnicodeDecodeError
+
+1.0.7
+-----
+
+* Allow alarm-threshold-update to upate generic attributes
+* Enable pep8 E711/E712/E721/H302 checking
+* Enable pep8 E128 checking
+* Enable pep8 E121/E122/E123 checking
+* Allow specifying a timestamp when creating a sample
+* Avoid reset of repeat\_actions attribute on alarm update
+* Ensure basic logging config is applied
+* Support building wheels (PEP-427)
+* Add six to requirements.txt
+* Updated from global requirements
+* Ceilometer UnicodeEncodeError when update or show alarm fix
+* Adds the 'limit' parameter to sample list command in V2 API
+* Fix order of sample list
+* add cliutils from oslo-incubator
+* update oslo libraries
+* Updated from global requirements
+* Fix cacert argument to HTTPS connection
+* Updated from global requirements
+* Replace mox3 with mock in unit test
+* Updated from global requirements
+* Fix missed Pep8 error with 1.4.6
+* Updated from global requirements
+* Replace mox with mox3
+* align the order of parameters for urlencode()
+* replace basetring/xrange
+* Replace unicode() with six.u()
+* replace dict.keys() with list(dict)
+* Import urlutils to substitute urllib
+* Use six.iteritems() for dict
+* Translate print statement to print function
+* Fix module importing issues for Python 3
+* Import six.StringIO
+
+1.0.6
+-----
+
+* Add support for new alarm-history command
+* Use standard CLI object-verb ordering for alarm-{g|s}set-state
+* Fix shell.do\_alarm\_get\_state to get as opposed to set
+* Updated from global requirements
+* Allow to update an alarm partially
+* Added support to --os-cacert
+* Help messages: specify which options are required
+* Improve the CM shell client alarm visualisation
+
+1.0.5
+-----
+
+* Use the new alarm format
+* Replace OpenStack LLC with OpenStack Foundation
+* Pass region\_name argument to keystone client
+* Adding missing 'statistic' field to alarm-show
+* Use global openstack requirements
+* Fix a typo in "sample-create" help message
+* Added support for running the tests under PyPy with tox
+* alarm: rename counter\_name to meter\_name
+
+1.0.3
+-----
+
+* Add support for new alarm repeat\_actions attribute
+* Updated from global requirements
+* Handle case where os\_auth\_token is set to ''
+* Ensure keystoneclient.auth\_token is re-evaluated
+* Fix typo in help text
+* Enhance ceilometer statistics command with --period
+
+1.0.2
+-----
+
+* Allow to set matching\_metadata with the cli
+* Add support for creating samples
+* Rename README.md to README.rst
+* Relax OpenStack upper capping of client versions
+* Allow Keystoneclient 0.3.x
+* Sync install\_venv\_common from oslo
+* Add matching\_metadata to the allowed attributes
+* Move tests to ceilometerclient
+
+1.0.1
+-----
+
+* Avoid unnecessary GET of existing alarm for update
+* Make authenticated client easier to consume
+* Add support for specifying statistics period
+* requirements.txt is not configured properly
+* Drop unnecessary arg when instantiating HTTP class
+* Remove explicit distribute depend
+* Start using pyflakes
+* Use Python 3.x compatible except construct
+* Add client support for creating new alarms
+* Add client support for updating alarms
+* Fix install\_venv.py requirements file
+* Enable more pep8 checks
+* Migrate to pbr
+* Rename tools/pip-requires to requirements.txt
+* Fix pep H306 (import order)
+* Fix pep H402 and H401 errors
+* Migrate to flake8
+* Add support for deleting alarms
+* Add support for getting individual alarms
+* Add support for listing alarms
+* Fix mis-scoped Client class breaking CLI
+* Use testr to run tests
+* Add install\_venv\_common from oslo
+* Update oslo code and split the module lines
+* Use the utils.BaseTestCase for all tests
+* Fix pep8 errors in test code
+* Remove unused test code in test\_util.py
+* Fix manifest (README.rst -> README.md)
+* client does not show version
+* Sync requirements with openstack-common/requirements
+* Fix for Bug #1167521, ceilometer client crashes with missing content type response pep8 compliance
+* Restore compatibility with PrettyTable < 0.7.2
+* Change the default API version used by the cli to v2
+* v2 API: added resource-show
+
+1.0.0
+-----
+
+* Make it possible to pass -q "metadata.field=value"
+* Corrected help strings
+* Don't log unneccessarly on each http request
+* Catch KeyError exception as early as possible when there is no matching data on the server
+* Properly removing start and ending slashes
+* Remove warlock from pip-requires as it is not used
+* Add resources and meters to the v2 shell
+* Correct the help info of resource-list sub-command
+* Add shell.py so we can do v2 shell commands
+* Support --os-auth-token
+* v1-api: Added timestamp support
+* v1-api: Adapted resouce/user api
+* Add support for v2 API
+* Update to latest oslo-version
+* Add tests for samples
+* Add a test for list by source
+* fix the fields in v1 do\_meter\_list
+* Add missing dependencies
+* Pin pep8 to 1.3.3
+* Add support for metadata query
+* Fix tests
+* Move repository to openstack org
+* Revert "Remove the event class and use Meter instead."
+* Remove the event class and use Meter instead
+* Make sure the version is prepended
+* Fix the default service\_type
+* Add basic functionality
+* Initial Commit
diff -pruN 2.6.2-1/debian/changelog 2.9.0-0ubuntu4/debian/changelog
--- 2.6.2-1/debian/changelog	2016-12-28 22:53:11.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/changelog	2021-06-23 08:30:55.000000000 +0000
@@ -1,23 +1,63 @@
-python-ceilometerclient (2.6.2-1) unstable; urgency=medium
+python-ceilometerclient (2.9.0-0ubuntu4) impish; urgency=medium
 
-  * Team upload.
-  * New upstream release
-  * Bumped debhelper compat version to 10
+  * d/control: Update VCS paths for move to lp:~ubuntu-openstack-dev.
+  * d/control: Drop python-pbr build-depends and py2 dependencies.
+  * d/rules: migrate to pybuild.
 
- -- Ondřej Nový <onovy@debian.org>  Wed, 28 Dec 2016 23:53:11 +0100
+ -- Chris MacNaughton <chris.macnaughton@ubuntu.com>  Wed, 23 Jun 2021 08:30:55 +0000
 
-python-ceilometerclient (2.6.1-2) unstable; urgency=medium
+python-ceilometerclient (2.9.0-0ubuntu3) eoan; urgency=medium
 
-  [ Ondřej Nový ]
-  * d/s/options: extend-diff-ignore of .gitreview
-  * d/control: Use correct branch in Vcs-* fields
+  * Drop python2 test
+
+ -- Gianfranco Costamagna <locutusofborg@debian.org>  Mon, 29 Jul 2019 16:15:23 +0200
+
+python-ceilometerclient (2.9.0-0ubuntu2) eoan; urgency=medium
+
+  * d/*: wrap-and-sort -bast.
+  * Drop Python 2 support:
+    - d/control: Drop python-ceilometerclient binary package.
+    - d/python{3}-ceilometerclient.{postinst,prerm,postrm}: Drop as no
+      longer need to manage binaries using alternatives.
+    - d/rules: Skip install and test of Python 2 module.
+  * d/rules: General tidy.
+  * d/p/py3-sphinx-compat.patch: Python 3 compath shim for sphinx doc
+    generation.
+
+ -- James Page <james.page@ubuntu.com>  Thu, 11 Jul 2019 06:00:30 +0100
+
+python-ceilometerclient (2.9.0-0ubuntu1) artful; urgency=medium
 
-  [ Thomas Goirand ]
-  * Uploading to unstable.
+  * New upstream release.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Fri, 07 Jul 2017 16:29:04 -0400
+
+python-ceilometerclient (2.8.1-0ubuntu1) artful; urgency=medium
 
- -- Thomas Goirand <zigo@debian.org>  Tue, 04 Oct 2016 10:35:28 +0200
+  * d/watch: Use tarballs.openstack.org for upstream releases.
+  * New upstream release.
+
+ -- James Page <james.page@ubuntu.com>  Fri, 02 Jun 2017 09:21:39 +0100
 
-python-ceilometerclient (2.6.1-1) experimental; urgency=medium
+python-ceilometerclient (2.8.0-0ubuntu1) zesty; urgency=medium
+
+  * New upstream release.
+  * d/control: Align (Build-)Depends with upstream.
+
+ -- Chuck Short <zulcss@ubuntu.com>  Thu, 26 Jan 2017 09:17:54 -0500
+
+python-ceilometerclient (2.7.0-1ubuntu1) zesty; urgency=medium
+
+  [ Corey Bryant ]
+  * d/gbp.conf: Update gbp configuration file.
+  * d/control: Update Vcs-* links and maintainers.
+
+  [ Chuck Short ]
+  * New upstream version. 
+
+ -- Chuck Short <zulcss@ubuntu.com>  Wed, 09 Nov 2016 08:47:31 -0500
+
+python-ceilometerclient (2.6.1-0ubuntu1) yakkety; urgency=medium
 
   [ Ondřej Nový ]
   * Standards-Version is 3.9.8 now (no change)
@@ -29,15 +69,15 @@ python-ceilometerclient (2.6.1-1) experi
   * .gitreview: Copy from orig tar file.
   * d/gbp.conf: Update debian-branch for Newton.
   * d/control: Align (Build-)Depends with upstream.
+  * d/p/skip-tests.patch: Rebased.
   * ceilometerclient/v2/client.py: Copy from orig tar file.
 
-  [ Thomas Goirand ]
+  [ Corey Bryant ]
   * New upstream release.
-  * Using pkgos-dh_auto_{install,test} from openstack-pkg-tools >= 52~.
-  * Using OpenStack's Gerrit as VCS URLs.
-  * d/p/skip-tests.patch: deleted.
+  * d/control: Align (Build-)Depends with upstream.
+  * d/p/skip-tests.patch: Dropped. No longer needed.
 
- -- Thomas Goirand <zigo@debian.org>  Tue, 13 Sep 2016 09:48:32 +0200
+ -- Corey Bryant <corey.bryant@canonical.com>  Thu, 15 Sep 2016 12:27:24 -0400
 
 python-ceilometerclient (2.4.0-2) unstable; urgency=medium
 
diff -pruN 2.6.2-1/debian/compat 2.9.0-0ubuntu4/debian/compat
--- 2.6.2-1/debian/compat	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/compat	2021-06-23 08:30:55.000000000 +0000
@@ -1 +1 @@
-10
+9
diff -pruN 2.6.2-1/debian/control 2.9.0-0ubuntu4/debian/control
--- 2.6.2-1/debian/control	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/control	2021-06-23 08:30:55.000000000 +0000
@@ -1,75 +1,50 @@
 Source: python-ceilometerclient
 Section: python
 Priority: extra
-Maintainer: PKG OpenStack <openstack-devel@lists.alioth.debian.org>
-Uploaders: Thomas Goirand <zigo@debian.org>,
-           Corey Bryant <corey.bryant@canonical.com>,
-Build-Depends: debhelper (>= 10),
-               dh-python,
-               openstack-pkg-tools (>= 52~),
-               python-all,
-               python-pbr (>= 1.8),
-               python-setuptools,
-               python-sphinx,
-               python3-all,
-               python3-pbr (>= 1.8),
-               python3-setuptools,
-Build-Depends-Indep: python-coverage,
-                     python-fixtures,
-                     python-iso8601,
-                     python-keystoneclient (>= 1:1.6.0),
-                     python-mock,
-                     python-oslo.i18n (>= 2.1.0),
-                     python-oslo.serialization (>= 1.10.0),
-                     python-oslo.utils (>= 3.5.0),
-                     python-oslosphinx (>= 2.5.0),
-                     python-prettytable,
-                     python-requests (>= 2.8.1),
-                     python-six (>= 1.9.0),
-                     python-stevedore (>= 1.10.0),
-                     python-tempest (>= 1:11.0.0),
-                     python-testtools,
-                     python-keystoneauth1 (>= 2.1.0),
-                     python3-fixtures,
-                     python3-iso8601,
-                     python3-keystoneclient (>= 1:1.6.0),
-                     python3-mock,
-                     python3-oslo.i18n (>= 2.1.0),
-                     python3-oslo.serialization (>= 1.10.0),
-                     python3-oslo.utils (>= 3.5.0),
-                     python3-prettytable,
-                     python3-requests (>= 2.8.1),
-                     python3-six (>= 1.9.0),
-                     python3-stevedore (>= 1.10.0),
-                     python3-subunit,
-                     python3-tempest (>= 1:11.0.0),
-                     python3-testtools,
-                     python3-keystoneauth1 (>= 2.1.0),
-                     subunit,
-                     testrepository,
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
+XSBC-Original-Maintainer: PKG OpenStack <openstack-devel@lists.alioth.debian.org>
+Uploaders:
+ Thomas Goirand <zigo@debian.org>,
+ Corey Bryant <corey.bryant@canonical.com>,
+Build-Depends:
+ debhelper (>= 9),
+ dh-python,
+ openstack-pkg-tools,
+ python3-all,
+ python3-pbr (>= 1.8),
+ python3-setuptools,
+ python3-sphinx,
+Build-Depends-Indep:
+ python3-coverage (>= 3.6),
+ python3-fixtures (>= 1.3.1),
+ python3-iso8601 (>= 0.1.11),
+ python3-keystoneauth1 (>= 2.1.0),
+ python3-mock (>= 1.2),
+ python3-oslo.i18n (>= 2.1.0),
+ python3-oslo.serialization (>= 1.10.0),
+ python3-oslo.utils (>= 3.17.0),
+ python3-oslosphinx (>= 2.5.0),
+ python3-prettytable (>= 0.7),
+ python3-requests (>= 2.8.1),
+ python3-six (>= 1.9.0),
+ python3-stevedore (>= 1.10.0),
+ python3-subunit,
+ python3-tempest (>= 1:11.0.0),
+ python3-testrepository (>= 0.0.18),
+ python3-testtools (>= 1.4.0),
 Standards-Version: 3.9.8
-Vcs-Browser: https://git.openstack.org/cgit/openstack/deb-python-ceilometerclient?h=debian%2Fnewton
-Vcs-Git: https://git.openstack.org/openstack/deb-python-ceilometerclient -b debian/newton
+Vcs-Browser: https://git.launchpad.net/~ubuntu-openstack-dev/ubuntu/+source/python-ceilometerclient
+Vcs-Git: git://git.launchpad.net/~ubuntu-openstack-dev/ubuntu/+source/python-ceilometerclient
 Homepage: http://www.openstack.org
 XS-Testsuite: autopkgtest
 
-Package: python-ceilometerclient
+Package: python-ceilometerclient-doc
+Section: doc
 Architecture: all
-Depends: python-iso8601,
-         python-keystoneclient (>= 1:1.6.0),
-         python-oslo.i18n (>= 2.1.0),
-         python-oslo.serialization (>= 1.10.0),
-         python-oslo.utils (>= 3.5.0),
-         python-pbr (>= 1.8),
-         python-prettytable,
-         python-requests (>= 2.8.1),
-         python-six (>= 1.9.0),
-         python-stevedore (>= 1.10.0),
-         python-keystoneauth1 (>= 2.1.0),
-         ${misc:Depends},
-         ${python:Depends},
-Suggests: python-ceilometerclient-doc
-Description: Client library for Openstack Ceilometer API server - Python 2.7
+Depends:
+ ${misc:Depends},
+ ${sphinxdoc:Depends},
+Description: Client library for Openstack Ceilometer API server - doc
  Ceilometer aims to deliver a unique point of contact for billing systems to
  acquire all counters they need to establish customer billing, across all
  current and future OpenStack components. The delivery of counters must be
@@ -81,24 +56,25 @@ Description: Client library for Openstac
  There's a Python API (the "ceilometerclient" module), and a command-line
  script ("ceilometer").
  .
- This package contains the Python 2.7 module.
+ This package contains the documentation.
 
 Package: python3-ceilometerclient
 Architecture: all
-Depends: python3-iso8601,
-         python3-keystoneclient (>= 1:1.6.0),
-         python3-oslo.i18n (>= 2.1.0),
-         python3-oslo.serialization (>= 1.10.0),
-         python3-oslo.utils (>= 3.5.0),
-         python3-pbr (>= 1.8),
-         python3-prettytable,
-         python3-requests (>= 2.8.1),
-         python3-six (>= 1.9.0),
-         python3-stevedore (>= 1.10.0),
-         python3-keystoneauth1 (>= 2.1.0),
-         ${misc:Depends},
-         ${python3:Depends},
-Suggests: python-ceilometerclient-doc
+Depends:
+ python3-iso8601,
+ python3-keystoneauth1 (>= 2.1.0),
+ python3-oslo.i18n (>= 2.1.0),
+ python3-oslo.serialization (>= 1.10.0),
+ python3-oslo.utils (>= 3.5.0),
+ python3-pbr (>= 1.8),
+ python3-prettytable,
+ python3-requests (>= 2.8.1),
+ python3-six (>= 1.9.0),
+ python3-stevedore (>= 1.10.0),
+ ${misc:Depends},
+ ${python3:Depends},
+Suggests:
+ python-ceilometerclient-doc,
 Description: Client library for Openstack Ceilometer API server - Python 3.x
  Ceilometer aims to deliver a unique point of contact for billing systems to
  acquire all counters they need to establish customer billing, across all
@@ -112,22 +88,3 @@ Description: Client library for Openstac
  script ("ceilometer").
  .
  This package contains the Python 3.x module.
-
-Package: python-ceilometerclient-doc
-Section: doc
-Architecture: all
-Depends: ${misc:Depends},
-         ${sphinxdoc:Depends},
-Description: Client library for Openstack Ceilometer API server - doc
- Ceilometer aims to deliver a unique point of contact for billing systems to
- acquire all counters they need to establish customer billing, across all
- current and future OpenStack components. The delivery of counters must be
- tracable and auditable, the counters must be easily extensible to support new
- projects, and agents doing data collections should be independent of the
- overall system.
- .
- This is a client for the Ceilometer which uses the OpenStack Image API.
- There's a Python API (the "ceilometerclient" module), and a command-line
- script ("ceilometer").
- .
- This package contains the documentation.
diff -pruN 2.6.2-1/debian/gbp.conf 2.9.0-0ubuntu4/debian/gbp.conf
--- 2.6.2-1/debian/gbp.conf	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/gbp.conf	2021-06-23 08:30:55.000000000 +0000
@@ -1,9 +1,7 @@
 [DEFAULT]
-upstream-branch = master
-debian-branch = debian/newton
+debian-branch = master
 upstream-tag = %(version)s
-compression = xz
+pristine-tar = True
 
 [buildpackage]
-export-dir = ../build-area/
-cleaner = true
+export-dir = ../build-area
diff -pruN 2.6.2-1/debian/patches/py3-sphinx-compat.patch 2.9.0-0ubuntu4/debian/patches/py3-sphinx-compat.patch
--- 2.6.2-1/debian/patches/py3-sphinx-compat.patch	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/patches/py3-sphinx-compat.patch	2021-06-23 08:30:55.000000000 +0000
@@ -0,0 +1,15 @@
+Description: Simple py3 compat shim
+Author: James Page <james.page@ubuntu.com>
+Forwarded: not-needed (project obsolete)
+
+--- a/doc/source/conf.py
++++ b/doc/source/conf.py
+@@ -11,7 +11,7 @@
+ # under the License.
+ 
+ import os
+-execfile(os.path.join("..", "ext", "gen_ref.py"))
++exec(open(os.path.join("..", "ext", "gen_ref.py")).read())
+ 
+ project = 'python-ceilometerclient'
+ 
diff -pruN 2.6.2-1/debian/patches/series 2.9.0-0ubuntu4/debian/patches/series
--- 2.6.2-1/debian/patches/series	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/patches/series	2021-06-23 08:30:55.000000000 +0000
@@ -0,0 +1 @@
+py3-sphinx-compat.patch
diff -pruN 2.6.2-1/debian/python3-ceilometerclient.postinst 2.9.0-0ubuntu4/debian/python3-ceilometerclient.postinst
--- 2.6.2-1/debian/python3-ceilometerclient.postinst	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/python3-ceilometerclient.postinst	1970-01-01 00:00:00.000000000 +0000
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "$1" = "configure" ] ; then
-	update-alternatives --install /usr/bin/ceilometer ceilometer /usr/bin/python3-ceilometer 200
-fi
-
-#DEBHELPER#
-
-exit 0
diff -pruN 2.6.2-1/debian/python3-ceilometerclient.postrm 2.9.0-0ubuntu4/debian/python3-ceilometerclient.postrm
--- 2.6.2-1/debian/python3-ceilometerclient.postrm	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/python3-ceilometerclient.postrm	1970-01-01 00:00:00.000000000 +0000
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "$1" = "remove" ] || [ "$1" = "disappear" ] ; then
-	update-alternatives --remove ceilometer /usr/bin/python3-ceilometer
-fi
-
-#DEBHELPER#
-
-exit 0
diff -pruN 2.6.2-1/debian/python3-ceilometerclient.prerm 2.9.0-0ubuntu4/debian/python3-ceilometerclient.prerm
--- 2.6.2-1/debian/python3-ceilometerclient.prerm	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/python3-ceilometerclient.prerm	1970-01-01 00:00:00.000000000 +0000
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "$1" = "remove" ] ; then
-	update-alternatives --remove ceilometer /usr/bin/python3-ceilometer
-fi
-
-#DEBHELPER#
-
-exit 0
diff -pruN 2.6.2-1/debian/python-ceilometerclient.manpages 2.9.0-0ubuntu4/debian/python-ceilometerclient.manpages
--- 2.6.2-1/debian/python-ceilometerclient.manpages	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/python-ceilometerclient.manpages	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-doc/man/ceilometer.1
diff -pruN 2.6.2-1/debian/python-ceilometerclient.postinst 2.9.0-0ubuntu4/debian/python-ceilometerclient.postinst
--- 2.6.2-1/debian/python-ceilometerclient.postinst	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/python-ceilometerclient.postinst	1970-01-01 00:00:00.000000000 +0000
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "$1" = "configure" ] ; then
-	update-alternatives --install /usr/bin/ceilometer ceilometer /usr/bin/python2-ceilometer 300
-fi
-
-#DEBHELPER#
-
-exit 0
diff -pruN 2.6.2-1/debian/python-ceilometerclient.postrm 2.9.0-0ubuntu4/debian/python-ceilometerclient.postrm
--- 2.6.2-1/debian/python-ceilometerclient.postrm	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/python-ceilometerclient.postrm	1970-01-01 00:00:00.000000000 +0000
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "$1" = "remove" ] || [ "$1" = "disappear" ] ; then
-	update-alternatives --remove ceilometer /usr/bin/python2-ceilometer
-fi
-
-#DEBHELPER#
-
-exit 0
diff -pruN 2.6.2-1/debian/python-ceilometerclient.prerm 2.9.0-0ubuntu4/debian/python-ceilometerclient.prerm
--- 2.6.2-1/debian/python-ceilometerclient.prerm	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/python-ceilometerclient.prerm	1970-01-01 00:00:00.000000000 +0000
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-set -e
-
-if [ "$1" = "remove" ] ; then
-	update-alternatives --remove ceilometer /usr/bin/python2-ceilometer
-fi
-
-#DEBHELPER#
-
-exit 0
diff -pruN 2.6.2-1/debian/rules 2.9.0-0ubuntu4/debian/rules
--- 2.6.2-1/debian/rules	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/rules	2021-06-23 08:30:55.000000000 +0000
@@ -1,32 +1,19 @@
 #!/usr/bin/make -f
 
-MANIFEST_EXCLUDE_STANDARD := ceilometerclient
 include /usr/share/openstack-pkg-tools/pkgos.make
 
 %:
-	dh $@ --buildsystem=python_distutils --with python2,python3,sphinxdoc
+	dh $@ --buildsystem=pybuild --with python3,sphinxdoc
 
 override_dh_auto_install:
-	pkgos-dh_auto_install
+	pkgos-dh_auto_install --no-py2
 
 override_dh_python3:
 	dh_python3 --shebang=/usr/bin/python3
 
 override_dh_auto_test:
 ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
-	pkgos-dh_auto_test
-#	@echo "===> Running tests"
-#	set -e ; set -x ; for i in $(PYTHONS) $(PYTHON3S) ; do \
-#		PYMAJOR=`echo $$i | cut -d'.' -f1` ; \
-#		echo "===> Testing with python$$i (python$$PYMAJOR)" ; \
-#		rm -rf .testrepository ; \
-#		testr-python$$PYMAJOR init ; \
-#		TEMP_REZ=`mktemp -t` ; \
-#		PYTHONPATH=$(CURDIR) PYTHON=python$$i testr-python$$PYMAJOR run --subunit 'ceilometerclient\.tests\.unit\.(?!.*test_client.ClientAuthTest\.test_discover_auth_versions.*)' | tee $$TEMP_REZ | subunit2pyunit ; \
-#		cat $$TEMP_REZ | subunit-filter -s --no-passthrough | subunit-stats ; \
-#		rm -f $$TEMP_REZ ; \
-#		testr-python$$PYMAJOR slowest ; \
-#	done
+	pkgos-dh_auto_test --no-py2 'ceilometerclient\.tests\.unit\.(?!.*test_client.ClientAuthTest\.test_discover_auth_versions.*)'
 endif
 
 override_dh_sphinxdoc:
@@ -36,14 +23,6 @@ ifeq (,$(findstring nodocs, $(DEB_BUILD_
 endif
 
 override_dh_clean:
-	dh_clean -O--buildsystem=python_distutils
+	dh_clean -O--buildsystem=pybuild
 	rm -rf .testrepository
 	rm -rf doc/man
-
-override_dh_installman:
-#ifeq (,$(findstring nodocs, $(DEB_BUILD_OPTIONS)))
-#	sphinx-build -b man doc/source doc/man
-#	mv doc/man/python-ceilometerclient.1 doc/man/ceilometer.1
-#	sed -i s/python-ceilometerclient/python-ceilometerclient/ doc/man/ceilometer.1
-#	dh_installman -O--buildsystem=python_distutils
-#endif
diff -pruN 2.6.2-1/debian/source/options 2.9.0-0ubuntu4/debian/source/options
--- 2.6.2-1/debian/source/options	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/source/options	2021-06-23 08:30:55.000000000 +0000
@@ -1,2 +1 @@
 extend-diff-ignore = "^[^/]*[.]egg-info/"
-extend-diff-ignore = "^[.]gitreview$"
diff -pruN 2.6.2-1/debian/tests/control 2.9.0-0ubuntu4/debian/tests/control
--- 2.6.2-1/debian/tests/control	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/tests/control	2021-06-23 08:30:55.000000000 +0000
@@ -1,8 +1,7 @@
 Tests: client
-Depends: python-ceilometerclient
+Depends:
+ python3-ceilometerclient,
 
-Depends: python-ceilometerclient
-Test-Command: cd "$ADTTMP" ; python -c "import ceilometerclient; print ceilometerclient.__version__"
-
-Depends: python3-ceilometerclient
+Depends:
+ python3-ceilometerclient,
 Test-Command: cd "$ADTTMP" ; python3 -c "import ceilometerclient; print(ceilometerclient.__version__)"
diff -pruN 2.6.2-1/debian/watch 2.9.0-0ubuntu4/debian/watch
--- 2.6.2-1/debian/watch	2016-12-28 22:52:03.000000000 +0000
+++ 2.9.0-0ubuntu4/debian/watch	2021-06-23 08:30:55.000000000 +0000
@@ -1,2 +1,3 @@
 version=3
-https://github.com/openstack/python-ceilometerclient/tags .*/(\d[\d\.]+)\.tar\.gz
+opts="uversionmangle=s/\.(b|rc)/~$1/" \
+    http://tarballs.openstack.org/python-ceilometerclient/ python-ceilometerclient-(\d.*)\.tar\.gz
diff -pruN 2.6.2-1/.gitignore 2.9.0-0ubuntu4/.gitignore
--- 2.6.2-1/.gitignore	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/.gitignore	1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-*.pyc
-*.egg-info
-build
-.coverage
-.tox
-cover
-.testrepository
-.venv
-doc/build
-releasenotes/build
-doc/source/ref
-subunit.log
-AUTHORS
-ChangeLog
-dist
-*.egg
diff -pruN 2.6.2-1/.gitreview 2.9.0-0ubuntu4/.gitreview
--- 2.6.2-1/.gitreview	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/.gitreview	1970-01-01 00:00:00.000000000 +0000
@@ -1,5 +0,0 @@
-[gerrit]
-host=review.openstack.org
-port=29418
-project=openstack/python-ceilometerclient.git
-defaultbranch=stable/newton
diff -pruN 2.6.2-1/PKG-INFO 2.9.0-0ubuntu4/PKG-INFO
--- 2.6.2-1/PKG-INFO	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/PKG-INFO	2017-06-12 13:27:22.000000000 +0000
@@ -0,0 +1,49 @@
+Metadata-Version: 1.1
+Name: python-ceilometerclient
+Version: 2.9.0
+Summary: OpenStack Telemetry API Client Library
+Home-page: http://docs.openstack.org/developer/python-ceilometerclient
+Author: OpenStack
+Author-email: openstack-dev@lists.openstack.org
+License: UNKNOWN
+Description: Python bindings to the Ceilometer API
+        =====================================
+        
+        .. image:: https://img.shields.io/pypi/v/python-ceilometerclient.svg
+            :target: https://pypi.python.org/pypi/python-ceilometerclient/
+            :alt: Latest Version
+        
+        .. image:: https://img.shields.io/pypi/dm/python-ceilometerclient.svg
+            :target: https://pypi.python.org/pypi/python-ceilometerclient/
+            :alt: Downloads
+        
+        This is a client library for Ceilometer built on the Ceilometer API. It
+        provides a Python API (the ``ceilometerclient`` module) and a command-line tool
+        (``ceilometer``).
+        
+        * `PyPi`_ - package installation
+        * `Online Documentation`_
+        * `Launchpad project`_ - release management
+        * `Blueprints`_ - feature specifications
+        * `Bugs`_ - issue tracking
+        * `Source`_
+        
+        .. _PyPi: https://pypi.python.org/pypi/python-ceilometerclient
+        .. _Online Documentation: http://docs.openstack.org/developer/python-ceilometerclient
+        .. _Launchpad project: https://launchpad.net/python-ceilometerclient
+        .. _Blueprints: https://blueprints.launchpad.net/python-ceilometerclient
+        .. _Bugs: https://bugs.launchpad.net/python-ceilometerclient
+        .. _Source: https://git.openstack.org/cgit/openstack/python-ceilometerclient
+        
+        
+Platform: UNKNOWN
+Classifier: Environment :: OpenStack
+Classifier: Intended Audience :: Information Technology
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.5
diff -pruN 2.6.2-1/python_ceilometerclient.egg-info/dependency_links.txt 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/dependency_links.txt
--- 2.6.2-1/python_ceilometerclient.egg-info/dependency_links.txt	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/dependency_links.txt	2017-06-12 13:27:21.000000000 +0000
@@ -0,0 +1 @@
+
diff -pruN 2.6.2-1/python_ceilometerclient.egg-info/entry_points.txt 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/entry_points.txt
--- 2.6.2-1/python_ceilometerclient.egg-info/entry_points.txt	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/entry_points.txt	2017-06-12 13:27:21.000000000 +0000
@@ -0,0 +1,3 @@
+[console_scripts]
+ceilometer = ceilometerclient.shell:main
+
diff -pruN 2.6.2-1/python_ceilometerclient.egg-info/not-zip-safe 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/not-zip-safe
--- 2.6.2-1/python_ceilometerclient.egg-info/not-zip-safe	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/not-zip-safe	2017-06-12 13:27:15.000000000 +0000
@@ -0,0 +1 @@
+
diff -pruN 2.6.2-1/python_ceilometerclient.egg-info/pbr.json 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/pbr.json
--- 2.6.2-1/python_ceilometerclient.egg-info/pbr.json	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/pbr.json	2017-06-12 13:27:21.000000000 +0000
@@ -0,0 +1 @@
+{"git_version": "3b4e35a", "is_release": true}
\ No newline at end of file
diff -pruN 2.6.2-1/python_ceilometerclient.egg-info/PKG-INFO 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/PKG-INFO
--- 2.6.2-1/python_ceilometerclient.egg-info/PKG-INFO	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/PKG-INFO	2017-06-12 13:27:21.000000000 +0000
@@ -0,0 +1,49 @@
+Metadata-Version: 1.1
+Name: python-ceilometerclient
+Version: 2.9.0
+Summary: OpenStack Telemetry API Client Library
+Home-page: http://docs.openstack.org/developer/python-ceilometerclient
+Author: OpenStack
+Author-email: openstack-dev@lists.openstack.org
+License: UNKNOWN
+Description: Python bindings to the Ceilometer API
+        =====================================
+        
+        .. image:: https://img.shields.io/pypi/v/python-ceilometerclient.svg
+            :target: https://pypi.python.org/pypi/python-ceilometerclient/
+            :alt: Latest Version
+        
+        .. image:: https://img.shields.io/pypi/dm/python-ceilometerclient.svg
+            :target: https://pypi.python.org/pypi/python-ceilometerclient/
+            :alt: Downloads
+        
+        This is a client library for Ceilometer built on the Ceilometer API. It
+        provides a Python API (the ``ceilometerclient`` module) and a command-line tool
+        (``ceilometer``).
+        
+        * `PyPi`_ - package installation
+        * `Online Documentation`_
+        * `Launchpad project`_ - release management
+        * `Blueprints`_ - feature specifications
+        * `Bugs`_ - issue tracking
+        * `Source`_
+        
+        .. _PyPi: https://pypi.python.org/pypi/python-ceilometerclient
+        .. _Online Documentation: http://docs.openstack.org/developer/python-ceilometerclient
+        .. _Launchpad project: https://launchpad.net/python-ceilometerclient
+        .. _Blueprints: https://blueprints.launchpad.net/python-ceilometerclient
+        .. _Bugs: https://bugs.launchpad.net/python-ceilometerclient
+        .. _Source: https://git.openstack.org/cgit/openstack/python-ceilometerclient
+        
+        
+Platform: UNKNOWN
+Classifier: Environment :: OpenStack
+Classifier: Intended Audience :: Information Technology
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.5
diff -pruN 2.6.2-1/python_ceilometerclient.egg-info/requires.txt 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/requires.txt
--- 2.6.2-1/python_ceilometerclient.egg-info/requires.txt	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/requires.txt	2017-06-12 13:27:21.000000000 +0000
@@ -0,0 +1,10 @@
+pbr>=1.6
+iso8601>=0.1.11
+keystoneauth1>=2.1.0
+oslo.i18n>=2.1.0
+oslo.serialization>=1.10.0
+oslo.utils>=3.17.0
+PrettyTable<0.8,>=0.7
+requests!=2.9.0,>=2.8.1
+six>=1.9.0
+stevedore>=1.10.0
diff -pruN 2.6.2-1/python_ceilometerclient.egg-info/SOURCES.txt 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/SOURCES.txt
--- 2.6.2-1/python_ceilometerclient.egg-info/SOURCES.txt	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/SOURCES.txt	2017-06-12 13:27:22.000000000 +0000
@@ -0,0 +1,95 @@
+.testr.conf
+AUTHORS
+CONTRIBUTING.rst
+ChangeLog
+LICENSE
+README.rst
+requirements.txt
+setup.cfg
+setup.py
+test-requirements.txt
+tox.ini
+ceilometerclient/__init__.py
+ceilometerclient/client.py
+ceilometerclient/exc.py
+ceilometerclient/i18n.py
+ceilometerclient/shell.py
+ceilometerclient/apiclient/__init__.py
+ceilometerclient/apiclient/auth.py
+ceilometerclient/apiclient/base.py
+ceilometerclient/apiclient/client.py
+ceilometerclient/apiclient/exceptions.py
+ceilometerclient/apiclient/fake_client.py
+ceilometerclient/apiclient/utils.py
+ceilometerclient/common/__init__.py
+ceilometerclient/common/base.py
+ceilometerclient/common/utils.py
+ceilometerclient/tests/__init__.py
+ceilometerclient/tests/functional/__init__.py
+ceilometerclient/tests/functional/base.py
+ceilometerclient/tests/functional/test_readonly_ceilometer.py
+ceilometerclient/tests/functional/hooks/post_test_hook.sh
+ceilometerclient/tests/unit/__init__.py
+ceilometerclient/tests/unit/test_client.py
+ceilometerclient/tests/unit/test_exc.py
+ceilometerclient/tests/unit/test_openstack_common.py
+ceilometerclient/tests/unit/test_shell.py
+ceilometerclient/tests/unit/test_utils.py
+ceilometerclient/tests/unit/utils.py
+ceilometerclient/tests/unit/v2/__init__.py
+ceilometerclient/tests/unit/v2/test_alarms.py
+ceilometerclient/tests/unit/v2/test_capabilities.py
+ceilometerclient/tests/unit/v2/test_event_types.py
+ceilometerclient/tests/unit/v2/test_events.py
+ceilometerclient/tests/unit/v2/test_options.py
+ceilometerclient/tests/unit/v2/test_query_alarm_history.py
+ceilometerclient/tests/unit/v2/test_query_alarms.py
+ceilometerclient/tests/unit/v2/test_query_samples.py
+ceilometerclient/tests/unit/v2/test_resources.py
+ceilometerclient/tests/unit/v2/test_samples.py
+ceilometerclient/tests/unit/v2/test_shell.py
+ceilometerclient/tests/unit/v2/test_statistics.py
+ceilometerclient/tests/unit/v2/test_trait_descriptions.py
+ceilometerclient/tests/unit/v2/test_traits.py
+ceilometerclient/v2/__init__.py
+ceilometerclient/v2/alarms.py
+ceilometerclient/v2/capabilities.py
+ceilometerclient/v2/client.py
+ceilometerclient/v2/event_types.py
+ceilometerclient/v2/events.py
+ceilometerclient/v2/meters.py
+ceilometerclient/v2/options.py
+ceilometerclient/v2/query.py
+ceilometerclient/v2/resources.py
+ceilometerclient/v2/samples.py
+ceilometerclient/v2/shell.py
+ceilometerclient/v2/statistics.py
+ceilometerclient/v2/trait_descriptions.py
+ceilometerclient/v2/traits.py
+doc/ext/gen_ref.py
+doc/source/api.rst
+doc/source/conf.py
+doc/source/index.rst
+doc/source/shell.rst
+python_ceilometerclient.egg-info/PKG-INFO
+python_ceilometerclient.egg-info/SOURCES.txt
+python_ceilometerclient.egg-info/dependency_links.txt
+python_ceilometerclient.egg-info/entry_points.txt
+python_ceilometerclient.egg-info/not-zip-safe
+python_ceilometerclient.egg-info/pbr.json
+python_ceilometerclient.egg-info/requires.txt
+python_ceilometerclient.egg-info/top_level.txt
+releasenotes/notes/.placeholder
+releasenotes/notes/alarm_deprecated-74363d70d48a20e2.yaml
+releasenotes/notes/deprecation-44ae455f4ef3a81e.yaml
+releasenotes/notes/panko-redirect-9d03598dbf51f8fd.yaml
+releasenotes/source/conf.py
+releasenotes/source/index.rst
+releasenotes/source/liberty.rst
+releasenotes/source/mitaka.rst
+releasenotes/source/newton.rst
+releasenotes/source/ocata.rst
+releasenotes/source/unreleased.rst
+releasenotes/source/_static/.placeholder
+releasenotes/source/_templates/.placeholder
+tools/ceilometer.bash_completion
\ No newline at end of file
diff -pruN 2.6.2-1/python_ceilometerclient.egg-info/top_level.txt 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/top_level.txt
--- 2.6.2-1/python_ceilometerclient.egg-info/top_level.txt	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/python_ceilometerclient.egg-info/top_level.txt	2017-06-12 13:27:21.000000000 +0000
@@ -0,0 +1 @@
+ceilometerclient
diff -pruN 2.6.2-1/releasenotes/notes/alarm_deprecated-74363d70d48a20e2.yaml 2.9.0-0ubuntu4/releasenotes/notes/alarm_deprecated-74363d70d48a20e2.yaml
--- 2.6.2-1/releasenotes/notes/alarm_deprecated-74363d70d48a20e2.yaml	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/releasenotes/notes/alarm_deprecated-74363d70d48a20e2.yaml	2017-06-12 13:24:31.000000000 +0000
@@ -0,0 +1,3 @@
+---
+deprecations:
+  - Alarm commands are deprecated in favor of aodhclient.
diff -pruN 2.6.2-1/releasenotes/notes/deprecation-44ae455f4ef3a81e.yaml 2.9.0-0ubuntu4/releasenotes/notes/deprecation-44ae455f4ef3a81e.yaml
--- 2.6.2-1/releasenotes/notes/deprecation-44ae455f4ef3a81e.yaml	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/releasenotes/notes/deprecation-44ae455f4ef3a81e.yaml	2017-06-12 13:24:31.000000000 +0000
@@ -0,0 +1,6 @@
+---
+deprecations:
+  - |
+    As the Ceilometer API has been deprecated, this client is also now marked
+    as deprecated and will print a warning when used as a command-line
+    interface tool.
diff -pruN 2.6.2-1/releasenotes/notes/panko-redirect-9d03598dbf51f8fd.yaml 2.9.0-0ubuntu4/releasenotes/notes/panko-redirect-9d03598dbf51f8fd.yaml
--- 2.6.2-1/releasenotes/notes/panko-redirect-9d03598dbf51f8fd.yaml	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/releasenotes/notes/panko-redirect-9d03598dbf51f8fd.yaml	2017-06-12 13:24:31.000000000 +0000
@@ -0,0 +1,7 @@
+---
+prelude: >
+    Panko replaces the API and storage of events previously in Ceilometer
+features:
+  - |
+    Similar to aodh redirect support, specify `panko_endpoint` as a redirect
+    to Panko API.
diff -pruN 2.6.2-1/releasenotes/source/conf.py 2.9.0-0ubuntu4/releasenotes/source/conf.py
--- 2.6.2-1/releasenotes/source/conf.py	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/releasenotes/source/conf.py	2017-06-12 13:24:31.000000000 +0000
@@ -273,3 +273,6 @@ texinfo_documents = [
 
 # If true, do not generate a @detailmenu in the "Top" node's menu.
 # texinfo_no_detailmenu = False
+
+# -- Options for Internationalization output ------------------------------
+locale_dirs = ['locale/']
diff -pruN 2.6.2-1/releasenotes/source/index.rst 2.9.0-0ubuntu4/releasenotes/source/index.rst
--- 2.6.2-1/releasenotes/source/index.rst	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/releasenotes/source/index.rst	2017-06-12 13:24:31.000000000 +0000
@@ -7,10 +7,11 @@ Contents
 .. toctree::
    :maxdepth: 2
 
-   liberty
-   mitaka
    unreleased
-
+   ocata
+   newton
+   mitaka
+   liberty
 
 Indices and tables
 ==================
diff -pruN 2.6.2-1/releasenotes/source/newton.rst 2.9.0-0ubuntu4/releasenotes/source/newton.rst
--- 2.6.2-1/releasenotes/source/newton.rst	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/releasenotes/source/newton.rst	2017-06-12 13:24:31.000000000 +0000
@@ -0,0 +1,6 @@
+===================================
+ Newton Series Release Notes
+===================================
+
+.. release-notes::
+   :branch: origin/stable/newton
diff -pruN 2.6.2-1/releasenotes/source/ocata.rst 2.9.0-0ubuntu4/releasenotes/source/ocata.rst
--- 2.6.2-1/releasenotes/source/ocata.rst	1970-01-01 00:00:00.000000000 +0000
+++ 2.9.0-0ubuntu4/releasenotes/source/ocata.rst	2017-06-12 13:24:31.000000000 +0000
@@ -0,0 +1,6 @@
+===================================
+ Ocata Series Release Notes
+===================================
+
+.. release-notes::
+   :branch: origin/stable/ocata
diff -pruN 2.6.2-1/requirements.txt 2.9.0-0ubuntu4/requirements.txt
--- 2.6.2-1/requirements.txt	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/requirements.txt	2017-06-12 13:24:31.000000000 +0000
@@ -6,7 +6,7 @@ iso8601>=0.1.11 # MIT
 keystoneauth1>=2.1.0 # Apache-2.0
 oslo.i18n>=2.1.0 # Apache-2.0
 oslo.serialization>=1.10.0 # Apache-2.0
-oslo.utils>=3.5.0 # Apache-2.0
+oslo.utils>=3.17.0 # Apache-2.0
 PrettyTable<0.8,>=0.7 # BSD
 requests!=2.9.0,>=2.8.1 # Apache-2.0
 six>=1.9.0 # MIT
diff -pruN 2.6.2-1/setup.cfg 2.9.0-0ubuntu4/setup.cfg
--- 2.6.2-1/setup.cfg	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/setup.cfg	2017-06-12 13:27:22.000000000 +0000
@@ -1,35 +1,34 @@
 [metadata]
 name = python-ceilometerclient
 summary = OpenStack Telemetry API Client Library
-description-file =
-    README.rst
+description-file = 
+	README.rst
 author = OpenStack
 author-email = openstack-dev@lists.openstack.org
 home-page = http://docs.openstack.org/developer/python-ceilometerclient
-classifier =
-    Environment :: OpenStack
-    Intended Audience :: Information Technology
-    Intended Audience :: System Administrators
-    License :: OSI Approved :: Apache Software License
-    Operating System :: POSIX :: Linux
-    Programming Language :: Python
-    Programming Language :: Python :: 2
-    Programming Language :: Python :: 2.7
-    Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.4
-    Programming Language :: Python :: 3.5
+classifier = 
+	Environment :: OpenStack
+	Intended Audience :: Information Technology
+	Intended Audience :: System Administrators
+	License :: OSI Approved :: Apache Software License
+	Operating System :: POSIX :: Linux
+	Programming Language :: Python
+	Programming Language :: Python :: 2
+	Programming Language :: Python :: 2.7
+	Programming Language :: Python :: 3
+	Programming Language :: Python :: 3.5
 
 [files]
-packages =
-    ceilometerclient
+packages = 
+	ceilometerclient
 
 [global]
-setup-hooks =
-    pbr.hooks.setup_hook
+setup-hooks = 
+	pbr.hooks.setup_hook
 
 [entry_points]
-console_scripts =
-    ceilometer = ceilometerclient.shell:main
+console_scripts = 
+	ceilometer = ceilometerclient.shell:main
 
 [build_sphinx]
 source-dir = doc/source
@@ -41,3 +40,8 @@ upload-dir = doc/build/html
 
 [wheel]
 universal = 1
+
+[egg_info]
+tag_build = 
+tag_date = 0
+
diff -pruN 2.6.2-1/tox.ini 2.9.0-0ubuntu4/tox.ini
--- 2.6.2-1/tox.ini	2016-10-11 09:10:10.000000000 +0000
+++ 2.9.0-0ubuntu4/tox.ini	2017-06-12 13:24:31.000000000 +0000
@@ -1,5 +1,5 @@
 [tox]
-envlist = py34,py35,py27,pypy,pep8
+envlist = py35,py27,pypy,pep8
 minversion = 1.6
 skipsdist = True
 
@@ -9,15 +9,18 @@ install_command = pip install -U {opts}
 setenv = VIRTUAL_ENV={envdir}
 deps = -r{toxinidir}/requirements.txt
        -r{toxinidir}/test-requirements.txt
+# NOTE(tonyb): This project has chosen to *NOT* consume upper-constraints.txt
 commands =
   python setup.py testr --slowest --testr-args='{posargs}'
 
 [testenv:pep8]
-deps = hacking<0.12,>=0.11.0
+deps = hacking<0.13,>=0.12
 commands = flake8
 
 [testenv:cover]
-commands = python setup.py testr --coverage --testr-args='{posargs}'
+commands =
+  python setup.py testr --coverage --testr-args='{posargs}'
+  coverage report
 
 [testenv:venv]
 commands = {posargs}
@@ -35,4 +38,8 @@ commands = sphinx-build -a -E -W -d rele
 
 [flake8]
 show-source = True
-exclude = .venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,tools
+exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,tools
+
+[hacking]
+import_exceptions =
+  ceilometerclient.i18n
