summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulien Danjou <julien@danjou.info>2017-11-22 10:08:58 +0100
committerJulien Danjou <julien@danjou.info>2017-11-22 10:09:10 +0100
commitcc6639ad63e80f50012b24695619e5d771462031 (patch)
treea1a93f5ffce81ad930abca6e0c11e904b7b362d8
parent3ff6bac3da348bad0b220ab26eab6ad6bfbeb675 (diff)
downloadpython-ceilometerclient-cc6639ad63e80f50012b24695619e5d771462031.tar.gz
Retire ceilometerclient
Depends-On: Ic2947fd066a2df685d52539d0756cd981cc16113 Change-Id: I65738a55db82053643f7580eee20b63df52b957f
-rw-r--r--.gitignore16
-rw-r--r--.gitreview4
-rw-r--r--.testr.conf4
-rw-r--r--CONTRIBUTING.rst16
-rw-r--r--LICENSE175
-rw-r--r--README10
-rw-r--r--README.rst28
-rw-r--r--ceilometerclient/__init__.py21
-rw-r--r--ceilometerclient/apiclient/__init__.py0
-rw-r--r--ceilometerclient/apiclient/auth.py231
-rw-r--r--ceilometerclient/apiclient/base.py535
-rw-r--r--ceilometerclient/apiclient/client.py388
-rw-r--r--ceilometerclient/apiclient/exceptions.py477
-rw-r--r--ceilometerclient/apiclient/fake_client.py190
-rw-r--r--ceilometerclient/apiclient/utils.py100
-rw-r--r--ceilometerclient/client.py480
-rw-r--r--ceilometerclient/common/__init__.py0
-rw-r--r--ceilometerclient/common/base.py106
-rw-r--r--ceilometerclient/common/utils.py204
-rw-r--r--ceilometerclient/exc.py144
-rw-r--r--ceilometerclient/i18n.py27
-rw-r--r--ceilometerclient/shell.py287
-rw-r--r--ceilometerclient/tests/__init__.py0
-rw-r--r--ceilometerclient/tests/functional/__init__.py0
-rw-r--r--ceilometerclient/tests/functional/base.py38
-rwxr-xr-xceilometerclient/tests/functional/hooks/post_test_hook.sh50
-rw-r--r--ceilometerclient/tests/functional/test_readonly_ceilometer.py67
-rw-r--r--ceilometerclient/tests/unit/__init__.py0
-rw-r--r--ceilometerclient/tests/unit/test_client.py430
-rw-r--r--ceilometerclient/tests/unit/test_exc.py88
-rw-r--r--ceilometerclient/tests/unit/test_openstack_common.py45
-rw-r--r--ceilometerclient/tests/unit/test_shell.py287
-rw-r--r--ceilometerclient/tests/unit/test_utils.py298
-rw-r--r--ceilometerclient/tests/unit/utils.py24
-rw-r--r--ceilometerclient/tests/unit/v2/__init__.py0
-rw-r--r--ceilometerclient/tests/unit/v2/test_alarms.py559
-rw-r--r--ceilometerclient/tests/unit/v2/test_capabilities.py58
-rw-r--r--ceilometerclient/tests/unit/v2/test_event_types.py50
-rw-r--r--ceilometerclient/tests/unit/v2/test_events.py198
-rw-r--r--ceilometerclient/tests/unit/v2/test_options.py253
-rw-r--r--ceilometerclient/tests/unit/v2/test_query_alarm_history.py64
-rw-r--r--ceilometerclient/tests/unit/v2/test_query_alarms.py74
-rw-r--r--ceilometerclient/tests/unit/v2/test_query_samples.py67
-rw-r--r--ceilometerclient/tests/unit/v2/test_resources.py147
-rw-r--r--ceilometerclient/tests/unit/v2/test_samples.py247
-rw-r--r--ceilometerclient/tests/unit/v2/test_shell.py1977
-rw-r--r--ceilometerclient/tests/unit/v2/test_statistics.py224
-rw-r--r--ceilometerclient/tests/unit/v2/test_trait_descriptions.py56
-rw-r--r--ceilometerclient/tests/unit/v2/test_traits.py62
-rw-r--r--ceilometerclient/v2/__init__.py16
-rw-r--r--ceilometerclient/v2/alarms.py185
-rw-r--r--ceilometerclient/v2/capabilities.py29
-rw-r--r--ceilometerclient/v2/client.py132
-rw-r--r--ceilometerclient/v2/event_types.py30
-rw-r--r--ceilometerclient/v2/events.py42
-rw-r--r--ceilometerclient/v2/meters.py38
-rw-r--r--ceilometerclient/v2/options.py129
-rw-r--r--ceilometerclient/v2/query.py54
-rw-r--r--ceilometerclient/v2/resources.py45
-rw-r--r--ceilometerclient/v2/samples.py106
-rw-r--r--ceilometerclient/v2/shell.py1285
-rw-r--r--ceilometerclient/v2/statistics.py58
-rw-r--r--ceilometerclient/v2/trait_descriptions.py28
-rw-r--r--ceilometerclient/v2/traits.py28
-rw-r--r--doc/ext/gen_ref.py54
-rw-r--r--doc/source/api.rst47
-rw-r--r--doc/source/cli.rst2202
-rw-r--r--doc/source/conf.py85
-rw-r--r--doc/source/index.rst56
-rw-r--r--doc/source/shell.rst61
-rw-r--r--releasenotes/notes/.placeholder0
-rw-r--r--releasenotes/notes/alarm_deprecated-74363d70d48a20e2.yaml3
-rw-r--r--releasenotes/notes/deprecation-44ae455f4ef3a81e.yaml6
-rw-r--r--releasenotes/notes/panko-redirect-9d03598dbf51f8fd.yaml7
-rw-r--r--releasenotes/source/_static/.placeholder0
-rw-r--r--releasenotes/source/_templates/.placeholder0
-rw-r--r--releasenotes/source/conf.py284
-rw-r--r--releasenotes/source/index.rst21
-rw-r--r--releasenotes/source/liberty.rst6
-rw-r--r--releasenotes/source/mitaka.rst6
-rw-r--r--releasenotes/source/newton.rst6
-rw-r--r--releasenotes/source/ocata.rst6
-rw-r--r--releasenotes/source/pike.rst6
-rw-r--r--releasenotes/source/unreleased.rst5
-rw-r--r--requirements.txt13
-rw-r--r--setup.cfg42
-rw-r--r--setup.py29
-rw-r--r--test-requirements.txt14
-rw-r--r--tools/ceilometer.bash_completion27
-rw-r--r--tox.ini45
90 files changed, 10 insertions, 14032 deletions
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index f7e0f31..0000000
--- a/.gitignore
+++ /dev/null
@@ -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 --git a/.gitreview b/.gitreview
deleted file mode 100644
index c4b5cc4..0000000
--- a/.gitreview
+++ /dev/null
@@ -1,4 +0,0 @@
-[gerrit]
-host=review.openstack.org
-port=29418
-project=openstack/python-ceilometerclient.git
diff --git a/.testr.conf b/.testr.conf
deleted file mode 100644
index 77a2a70..0000000
--- a/.testr.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-[DEFAULT]
-test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./ceilometerclient/tests/unit} $LISTOPT $IDOPTION
-test_id_option=--load-list $IDFILE
-test_list_option=--list
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
deleted file mode 100644
index b5abcbd..0000000
--- a/CONTRIBUTING.rst
+++ /dev/null
@@ -1,16 +0,0 @@
-If you would like to contribute to the development of OpenStack,
-you must follow the steps documented at:
-
- https://docs.openstack.org/infra/manual/developers.html#development-workflow
-
-Once those steps have been completed, changes to OpenStack
-should be submitted for review via the Gerrit tool, following
-the workflow documented at:
-
- https://docs.openstack.org/infra/manual/developers.html#development-workflow
-
-Pull requests submitted through GitHub will be ignored.
-
-Bugs should be filed on Launchpad, not GitHub:
-
- https://bugs.launchpad.net/python-ceilometerclient
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 67db858..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,175 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
diff --git a/README b/README
new file mode 100644
index 0000000..d98af48
--- /dev/null
+++ b/README
@@ -0,0 +1,10 @@
+This project is no longer maintained.
+
+The contents of this repository are still available in the Git
+source code management system. To see the contents of this
+repository before it reached its end of life, please check out the
+previous commit with "git checkout HEAD^1".
+
+For any further questions, please email
+openstack-dev@lists.openstack.org or join #openstack-dev on
+Freenode.
diff --git a/README.rst b/README.rst
deleted file mode 100644
index d1dccd5..0000000
--- a/README.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-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: https://docs.openstack.org/python-ceilometerclient/latest/
-.. _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
diff --git a/ceilometerclient/__init__.py b/ceilometerclient/__init__.py
deleted file mode 100644
index d6efb69..0000000
--- a/ceilometerclient/__init__.py
+++ /dev/null
@@ -1,21 +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.
-
-__all__ = ['__version__']
-
-import pbr.version
-
-version_info = pbr.version.VersionInfo('python-ceilometerclient')
-try:
- __version__ = version_info.version_string()
-except AttributeError:
- __version__ = None
diff --git a/ceilometerclient/apiclient/__init__.py b/ceilometerclient/apiclient/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/ceilometerclient/apiclient/__init__.py
+++ /dev/null
diff --git a/ceilometerclient/apiclient/auth.py b/ceilometerclient/apiclient/auth.py
deleted file mode 100644
index 41d118f..0000000
--- a/ceilometerclient/apiclient/auth.py
+++ /dev/null
@@ -1,231 +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.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 --git a/ceilometerclient/apiclient/base.py b/ceilometerclient/apiclient/base.py
deleted file mode 100644
index 6e9990a..0000000
--- a/ceilometerclient/apiclient/base.py
+++ /dev/null
@@ -1,535 +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 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 --git a/ceilometerclient/apiclient/client.py b/ceilometerclient/apiclient/client.py
deleted file mode 100644
index df33159..0000000
--- a/ceilometerclient/apiclient/client.py
+++ /dev/null
@@ -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.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 --git a/ceilometerclient/apiclient/exceptions.py b/ceilometerclient/apiclient/exceptions.py
deleted file mode 100644
index 68b98ca..0000000
--- a/ceilometerclient/apiclient/exceptions.py
+++ /dev/null
@@ -1,477 +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.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 --git a/ceilometerclient/apiclient/fake_client.py b/ceilometerclient/apiclient/fake_client.py
deleted file mode 100644
index d897cc5..0000000
--- a/ceilometerclient/apiclient/fake_client.py
+++ /dev/null
@@ -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.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 --git a/ceilometerclient/apiclient/utils.py b/ceilometerclient/apiclient/utils.py
deleted file mode 100644
index 2f45b92..0000000
--- a/ceilometerclient/apiclient/utils.py
+++ /dev/null
@@ -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.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 --git a/ceilometerclient/client.py b/ceilometerclient/client.py
deleted file mode 100644
index 2c61f34..0000000
--- a/ceilometerclient/client.py
+++ /dev/null
@@ -1,480 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import contextlib
-import time
-
-from keystoneauth1 import adapter
-from keystoneauth1 import discover
-from keystoneauth1 import exceptions as ka_exc
-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.apiclient import auth
-from ceilometerclient.apiclient import client
-from ceilometerclient.apiclient import exceptions
-from ceilometerclient import exc
-
-
-def _discover_auth_versions(session, auth_url):
- # discover the API versions the server is supporting based on the
- # given URL
- v2_auth_url = None
- v3_auth_url = None
- try:
- ks_discover = discover.Discover(session=session, url=auth_url)
- v2_auth_url = ks_discover.url_for('2.0')
- v3_auth_url = ks_discover.url_for('3.0')
- except ka_exc.DiscoveryFailure:
- raise
- except exceptions.ClientException:
- # Identity service may not support discovery. In that case,
- # try to determine version from auth_url
- url_parts = urlparse.urlparse(auth_url)
- (scheme, netloc, path, params, query, fragment) = url_parts
- path = path.lower()
- if path.startswith('/v3'):
- v3_auth_url = auth_url
- elif path.startswith('/v2'):
- v2_auth_url = auth_url
- else:
- raise exc.CommandError('Unable to determine the Keystone '
- 'version to authenticate with '
- 'using the given auth_url.')
- return v2_auth_url, v3_auth_url
-
-
-def _get_keystone_session(**kwargs):
- # TODO(fabgia): the heavy lifting here should be really done by Keystone.
- # Unfortunately Keystone does not support a richer method to perform
- # discovery and return a single viable URL. A bug against Keystone has
- # been filed: https://bugs.launchpad.net/python-keystoneclient/+bug/1330677
-
- # first create a Keystone session
- cacert = kwargs.pop('cacert', None)
- cert = kwargs.pop('cert', None)
- key = kwargs.pop('key', None)
- insecure = kwargs.pop('insecure', False)
- auth_url = kwargs.pop('auth_url', None)
- project_id = kwargs.pop('project_id', None)
- project_name = kwargs.pop('project_name', None)
- token = kwargs['token']
- timeout = kwargs.get('timeout')
-
- if insecure:
- verify = False
- else:
- verify = cacert or True
-
- if cert and key:
- # passing cert and key together is deprecated in favour of the
- # requests lib form of having the cert and key as a tuple
- cert = (cert, key)
-
- # 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
- project_domain_id or project_domain_name)
- use_v3 = v3_auth_url and (use_domain or (not v2_auth_url))
- use_v2 = v2_auth_url and not use_domain
-
- if use_v3 and token:
- auth = v3_auth.Token(
- v3_auth_url,
- token=token,
- project_name=project_name,
- project_id=project_id,
- project_domain_name=project_domain_name,
- project_domain_id=project_domain_id)
- elif use_v2 and token:
- auth = v2_auth.Token(
- v2_auth_url,
- token=token,
- tenant_id=project_id,
- tenant_name=project_name)
- elif use_v3:
- # the auth_url as v3 specified
- # e.g. http://no.where:5000/v3
- # Keystone will return only v3 as viable option
- auth = v3_auth.Password(
- v3_auth_url,
- username=username,
- password=kwargs.pop('password', None),
- user_id=user_id,
- user_domain_name=user_domain_name,
- user_domain_id=user_domain_id,
- project_name=project_name,
- project_id=project_id,
- project_domain_name=project_domain_name,
- project_domain_id=project_domain_id)
- elif use_v2:
- # the auth_url as v2 specified
- # e.g. http://no.where:5000/v2.0
- # Keystone will return only v2 as viable option
- auth = v2_auth.Password(
- v2_auth_url,
- username,
- kwargs.pop('password', None),
- tenant_id=project_id,
- tenant_name=project_name)
-
- else:
- raise exc.CommandError('Unable to determine the Keystone version '
- 'to authenticate with using the given '
- 'auth_url.')
-
- ks_session.auth = auth
- return ks_session
-
-
-def _get_endpoint(ks_session, **kwargs):
- """Get an endpoint using the provided keystone session."""
-
- # set service specific endpoint types
- endpoint_type = kwargs.get('endpoint_type') or 'publicURL'
- service_type = kwargs.get('service_type') or 'metering'
-
- endpoint = ks_session.get_endpoint(service_type=service_type,
- interface=endpoint_type,
- region_name=kwargs.get('region_name'))
-
- return endpoint
-
-
-class AuthPlugin(auth.BaseAuthPlugin):
- opt_names = ['tenant_id', 'region_name', 'auth_token',
- 'service_type', 'endpoint_type', 'cacert',
- 'auth_url', 'insecure', 'cert_file', 'key_file',
- 'cert', 'key', 'tenant_name', 'project_name',
- 'project_id', 'project_domain_id', 'project_domain_name',
- 'user_id', 'user_domain_id', 'user_domain_name',
- 'password', 'username', 'endpoint']
-
- def __init__(self, auth_system=None, **kwargs):
- self.opt_names.extend(self.common_opt_names)
- super(AuthPlugin, self).__init__(auth_system, **kwargs)
- # NOTE(sileht): backward compat
- if self.opts.get('auth_token') and not self.opts.get('token'):
- self.opts['token'] = self.opts.get('auth_token')
-
- def _do_authenticate(self, http_client):
- token = self.opts.get('token')
- endpoint = self.opts.get('endpoint')
- if not (endpoint and token):
- ks_kwargs = self._get_ks_kwargs(http_timeout=http_client.timeout)
- ks_session = _get_keystone_session(**ks_kwargs)
- if not token:
- token = lambda: ks_session.get_token()
- if not endpoint:
- endpoint = _get_endpoint(ks_session, **ks_kwargs)
- self.opts['token'] = token
- self.opts['endpoint'] = endpoint
-
- def _get_ks_kwargs(self, http_timeout):
- project_id = (self.opts.get('project_id') or
- self.opts.get('tenant_id'))
- project_name = (self.opts.get('project_name') or
- self.opts.get('tenant_name'))
- token = self.opts.get('token')
- ks_kwargs = {
- 'username': self.opts.get('username'),
- 'password': self.opts.get('password'),
- 'user_id': self.opts.get('user_id'),
- 'user_domain_id': self.opts.get('user_domain_id'),
- 'user_domain_name': self.opts.get('user_domain_name'),
- 'project_id': project_id,
- 'project_name': project_name,
- 'project_domain_name': self.opts.get('project_domain_name'),
- 'project_domain_id': self.opts.get('project_domain_id'),
- 'auth_url': self.opts.get('auth_url'),
- 'cacert': self.opts.get('cacert'),
- 'cert': self.opts.get('cert'),
- 'key': self.opts.get('key'),
- 'insecure': strutils.bool_from_string(
- self.opts.get('insecure')),
- 'endpoint_type': self.opts.get('endpoint_type'),
- 'service_type': self.opts.get('service_type'),
- 'region_name': self.opts.get('region_name'),
- 'timeout': http_timeout,
- 'token': token() if callable(token) else token,
- }
- return ks_kwargs
-
- def token_and_endpoint(self, endpoint_type, service_type):
- token = self.opts.get('token')
- if callable(token):
- token = token()
- return token, self.opts.get('endpoint')
-
- def sufficient_options(self):
- """Check if all required options are present.
-
- :raises: AuthPluginOptionsMissing
- """
- has_token = self.opts.get('token')
- has_project_domain_or_tenant = (self.opts.get('project_id') or
- (self.opts.get('project_name') and
- (self.opts.get('user_domain_name') or
- self.opts.get('user_domain_id'))) or
- (self.opts.get('tenant_id') or
- self.opts.get('tenant_name')))
- has_credential = (self.opts.get('username')
- and has_project_domain_or_tenant
- and self.opts.get('password')
- and self.opts.get('auth_url'))
- missing = not (has_token or has_credential)
- if missing:
- missing_opts = []
- opts = ['token', 'endpoint', 'username', 'password', 'auth_url',
- 'tenant_id', 'tenant_name']
- for opt in opts:
- if not self.opts.get(opt):
- missing_opts.append(opt)
- raise exceptions.AuthPluginOptionsMissing(missing_opts)
-
-
-def _adjust_kwargs(kwargs):
- client_kwargs = {
- 'username': kwargs.get('os_username'),
- 'password': kwargs.get('os_password'),
- 'tenant_id': kwargs.get('os_tenant_id'),
- 'tenant_name': kwargs.get('os_tenant_name'),
- 'auth_url': kwargs.get('os_auth_url'),
- 'region_name': kwargs.get('os_region_name'),
- 'service_type': kwargs.get('os_service_type'),
- 'endpoint_type': kwargs.get('os_endpoint_type'),
- 'insecure': kwargs.get('os_insecure'),
- 'cacert': kwargs.get('os_cacert'),
- 'cert_file': kwargs.get('os_cert'),
- 'key_file': kwargs.get('os_key'),
- 'token': kwargs.get('os_token') or kwargs.get('os_auth_token'),
- 'user_domain_name': kwargs.get('os_user_domain_name'),
- 'user_domain_id': kwargs.get('os_user_domain_id'),
- 'project_domain_name': kwargs.get('os_project_domain_name'),
- 'project_domain_id': kwargs.get('os_project_domain_id'),
- }
-
- client_kwargs.update(kwargs)
- client_kwargs['token'] = (client_kwargs.get('token') or
- kwargs.get('token') or
- kwargs.get('auth_token'))
-
- timeout = kwargs.get('timeout')
- if timeout is not None:
- timeout = int(timeout)
- if timeout <= 0:
- timeout = None
-
- insecure = strutils.bool_from_string(client_kwargs.get('insecure'))
- verify = kwargs.get('verify')
- if verify is None:
- if insecure:
- verify = False
- else:
- verify = client_kwargs.get('cacert') or True
-
- cert = client_kwargs.get('cert_file')
- key = client_kwargs.get('key_file')
- if cert and key:
- cert = cert, key
-
- client_kwargs.update({'verify': verify, 'cert': cert, 'timeout': timeout})
- return client_kwargs
-
-
-def Client(version, *args, **kwargs):
- client_kwargs = _adjust_kwargs(kwargs)
-
- module = importutils.import_versioned_module('ceilometerclient',
- version, 'client')
- client_class = getattr(module, 'Client')
- return client_class(*args, **client_kwargs)
-
-
-def get_client(version, **kwargs):
- """Get an authenticated client, based on the credentials in the kwargs.
-
- :param version: the API version to use ('1' or '2')
- :param kwargs: keyword args containing credentials, either:
-
- * session: a keystoneauth session object
- * service_type: The default service_type for URL discovery
- * service_name: The default service_name for URL discovery
- * interface: The default interface for URL discovery
- (Default: public)
- * region_name: The default region_name for URL discovery
- * endpoint_override: Always use this endpoint URL for requests
- for this ceiloclient
- * auth: An auth plugin to use instead of the session one
- * user_agent: The User-Agent string to set
- (Default is python-ceilometer-client)
- * connect_retries: the maximum number of retries that should be
- attempted for connection errors
- * logger: A logging object
-
- or (DEPRECATED):
-
- * os_auth_token: (DEPRECATED) pre-existing token to re-use,
- use os_token instead
- * os_token: pre-existing token to re-use
- * ceilometer_url: (DEPRECATED) Ceilometer API endpoint,
- use os_endpoint instead
- * os_endpoint: Ceilometer API endpoint
-
- or (DEPRECATED):
-
- * os_username: name of user
- * os_password: user's password
- * os_user_id: user's id
- * os_user_domain_id: the domain id of the user
- * os_user_domain_name: the domain name of the user
- * os_project_id: the user project id
- * os_tenant_id: V2 alternative to os_project_id
- * os_project_name: the user project name
- * os_tenant_name: V2 alternative to os_project_name
- * os_project_domain_name: domain name for the user project
- * os_project_domain_id: domain id for the user project
- * os_auth_url: endpoint to authenticate against
- * os_cert|os_cacert: path of CA TLS certificate
- * os_key: SSL private key
- * os_insecure: allow insecure SSL (no cert verification)
- """
- endpoint = kwargs.get('os_endpoint') or kwargs.get('ceilometer_url')
-
- return Client(version, endpoint, **kwargs)
-
-
-def get_auth_plugin(endpoint, **kwargs):
- auth_plugin = AuthPlugin(
- auth_url=kwargs.get('auth_url'),
- service_type=kwargs.get('service_type'),
- token=kwargs.get('token'),
- endpoint_type=kwargs.get('endpoint_type'),
- insecure=kwargs.get('insecure'),
- region_name=kwargs.get('region_name'),
- cacert=kwargs.get('cacert'),
- tenant_id=kwargs.get('project_id') or kwargs.get('tenant_id'),
- endpoint=endpoint,
- username=kwargs.get('username'),
- password=kwargs.get('password'),
- 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'),
- project_domain_id=kwargs.get('project_domain_id')
- )
- return auth_plugin
-
-
-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',
- 'project_domain_name', 'project_domain_id',
- 'key_file', 'cert_file', 'verify', 'timeout', 'cert')
-
-
-def _construct_http_client(**kwargs):
- kwargs = kwargs.copy()
- if kwargs.get('session') is not None:
- # Drop legacy options
- for opt in LEGACY_OPTS:
- kwargs.pop(opt, None)
- # Drop redirect endpoints from kwargs
- kwargs.pop('aodh_endpoint', None)
- kwargs.pop('panko_endpoint', None)
-
- return SessionClient(
- session=kwargs.pop('session'),
- service_type=kwargs.pop('service_type', 'metering') or 'metering',
- interface=kwargs.pop('interface', kwargs.pop('endpoint_type',
- 'publicURL')),
- region_name=kwargs.pop('region_name', None),
- user_agent=kwargs.pop('user_agent', 'python-ceilometerclient'),
- auth=kwargs.get('auth'),
- timings=kwargs.pop('timings', None),
- **kwargs)
- else:
- return client.BaseClient(client.HTTPClient(
- auth_plugin=kwargs.get('auth_plugin'),
- region_name=kwargs.get('region_name'),
- endpoint_type=kwargs.get('endpoint_type'),
- original_ip=kwargs.get('original_ip'),
- verify=kwargs.get('verify'),
- cert=kwargs.get('cert'),
- timeout=kwargs.get('timeout'),
- timings=kwargs.get('timings'),
- keyring_saver=kwargs.get('keyring_saver'),
- debug=kwargs.get('debug'),
- user_agent=kwargs.get('user_agent'),
- http=kwargs.get('http')
- ))
-
-
-@contextlib.contextmanager
-def record_time(times, enabled, *args):
- """Record the time of a specific action.
-
- :param times: A list of tuples holds time data.
- :type times: list
- :param enabled: Whether timing is enabled.
- :type enabled: bool
- :param args: Other data to be stored besides time data, these args
- will be joined to a string.
- """
- if not enabled:
- yield
- else:
- start = time.time()
- yield
- end = time.time()
- times.append((' '.join(args), start, end))
-
-
-class SessionClient(adapter.LegacyJsonAdapter):
- def __init__(self, *args, **kwargs):
- self.times = []
- self.timings = kwargs.pop('timings', False)
- super(SessionClient, self).__init__(*args, **kwargs)
-
- def request(self, url, method, **kwargs):
- kwargs.setdefault('headers', kwargs.get('headers', {}))
- # NOTE(sileht): The standard call raises errors from
- # keystoneauth, where we need to raise the ceilometerclient errors.
- raise_exc = kwargs.pop('raise_exc', True)
- with record_time(self.times, self.timings, method, url):
- resp, body = super(SessionClient, self).request(url,
- method,
- raise_exc=False,
- **kwargs)
-
- if raise_exc and resp.status_code >= 400:
- raise exc.from_response(resp, body)
- return resp
diff --git a/ceilometerclient/common/__init__.py b/ceilometerclient/common/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/ceilometerclient/common/__init__.py
+++ /dev/null
diff --git a/ceilometerclient/common/base.py b/ceilometerclient/common/base.py
deleted file mode 100644
index 5df8344..0000000
--- a/ceilometerclient/common/base.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# Copyright 2012 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.
-"""
-
-import copy
-
-from ceilometerclient.apiclient import base
-from ceilometerclient.apiclient import exceptions
-from ceilometerclient import exc
-
-
-def getid(obj):
- """Extracts object ID.
-
- Abstracts the common pattern of allowing both an object or an
- object's ID (UUID) as a parameter when dealing with relationships.
- """
- try:
- return obj.id
- except AttributeError:
- return obj
-
-
-class Manager(object):
- """Managers interact with a particular type of API.
-
- It works with samples, meters, alarms, etc. and provide CRUD operations for
- them.
- """
- resource_class = None
-
- def __init__(self, api):
- self.api = api
-
- @property
- def client(self):
- """Compatible with latest oslo-incubator.apiclient code."""
- return self.api
-
- def _create(self, url, body):
- body = self.api.post(url, json=body).json()
- if body:
- return self.resource_class(self, body)
-
- def _list(self, url, response_key=None, obj_class=None, body=None,
- expect_single=False):
- try:
- resp = self.api.get(url)
- except exceptions.NotFound:
- raise exc.HTTPNotFound
- if not resp.content:
- raise exc.HTTPNotFound
- body = resp.json()
-
- if obj_class is None:
- obj_class = self.resource_class
-
- if response_key:
- try:
- data = body[response_key]
- except KeyError:
- return []
- else:
- data = body
- if expect_single:
- data = [data]
- return [obj_class(self, res, loaded=True) for res in data if res]
-
- def _update(self, url, body, response_key=None):
- body = self.api.put(url, json=body).json()
- # PUT requests may not return a body
- if body:
- return self.resource_class(self, body)
-
- def _delete(self, url):
- self.api.delete(url)
-
-
-class Resource(base.Resource):
- """A resource represents a particular instance of an object.
-
- Resource might be tenant, user, etc.
- This is pretty much just a bag for attributes.
-
- :param manager: Manager object
- :param info: dictionary representing resource attributes
- :param loaded: prevent lazy-loading if set to True
- """
-
- def to_dict(self):
- return copy.deepcopy(self._info)
diff --git a/ceilometerclient/common/utils.py b/ceilometerclient/common/utils.py
deleted file mode 100644
index 720691d..0000000
--- a/ceilometerclient/common/utils.py
+++ /dev/null
@@ -1,204 +0,0 @@
-# Copyright 2012 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.
-
-from __future__ import print_function
-
-import os
-import textwrap
-
-from oslo_serialization import jsonutils
-from oslo_utils import encodeutils
-import prettytable
-import six
-
-from ceilometerclient import exc
-
-
-# Decorator for cli-args
-def arg(*args, **kwargs):
- def _decorator(func):
- if 'help' in kwargs:
- if 'default' in kwargs:
- kwargs['help'] += " Defaults to %s." % kwargs['default']
- required = kwargs.get('required', False)
- if required:
- kwargs['help'] += " Required."
-
- # Because of the sematics of decorator composition if we just append
- # to the options list positional options will appear to be backwards.
- func.__dict__.setdefault('arguments', []).insert(0, (args, kwargs))
- return func
- return _decorator
-
-
-def print_list(objs, fields, field_labels, formatters=None, sortby=0):
- """Print a list of objects as a table, one row per object.
-
- :param objs: Iterable of :class:`Resource`
- :param fields: Attributes that correspond to columns, in order
- :param field_labels: Labels to use in the heading of the table, default to
- fields.
- :param formatters: `dict` of callables for field formatting
- :param sortby: Index of the field for sorting table rows
- """
- formatters = formatters or {}
-
- if len(field_labels) != len(fields):
- raise ValueError(("Field labels list %(labels)s has different number "
- "of elements than fields list %(fields)s"),
- {'labels': field_labels, 'fields': fields})
-
- def _make_default_formatter(field):
- return lambda o: getattr(o, field, '')
-
- new_formatters = {}
- for field, field_label in six.moves.zip(fields, field_labels):
- if field in formatters:
- new_formatters[field_label] = formatters[field]
- else:
- new_formatters[field_label] = _make_default_formatter(field)
-
- kwargs = {} if sortby is None else {'sortby': field_labels[sortby]}
- pt = prettytable.PrettyTable(field_labels)
- pt.align = 'l'
-
- for o in objs:
- row = []
- for field in field_labels:
- if field in new_formatters:
- row.append(new_formatters[field](o))
- else:
- field_name = field.lower().replace(' ', '_')
- data = getattr(o, field_name, '')
- row.append(data)
- pt.add_row(row)
-
- if six.PY3:
- print(encodeutils.safe_encode(pt.get_string(**kwargs)).decode())
- else:
- print(encodeutils.safe_encode(pt.get_string(**kwargs)))
-
-
-def nested_list_of_dict_formatter(field, column_names):
- # (TMaddox) Because the formatting scheme actually drops the whole object
- # into the formatter, rather than just the specified field, we have to
- # extract it and then pass the value.
- return lambda o: format_nested_list_of_dict(getattr(o, field),
- column_names)
-
-
-def format_nested_list_of_dict(l, column_names):
- pt = prettytable.PrettyTable(caching=False, print_empty=False,
- header=True, hrules=prettytable.FRAME,
- field_names=column_names)
- # Sort by values of first column
- if l is not None:
- l.sort(key=lambda k: k.get(column_names[0]))
- for d in l:
- pt.add_row(list(map(lambda k: d[k], column_names)))
- return pt.get_string()
-
-
-def print_dict(d, dict_property="Property", wrap=0):
- pt = prettytable.PrettyTable([dict_property, 'Value'], print_empty=False)
- pt.align = 'l'
- for k, v in sorted(six.iteritems(d)):
- # convert dict to str to check length
- if isinstance(v, (list, dict)):
- v = jsonutils.dumps(v)
- # if value has a newline, add in multiple rows
- # e.g. fault with stacktrace
- if v and isinstance(v, six.string_types) and r'\n' in v:
- lines = v.strip().split(r'\n')
- col1 = k
- for line in lines:
- if wrap > 0:
- line = textwrap.fill(six.text_type(line), wrap)
- pt.add_row([col1, line])
- col1 = ''
- else:
- if wrap > 0:
- v = textwrap.fill(six.text_type(v), wrap)
- pt.add_row([k, v])
- encoded = encodeutils.safe_encode(pt.get_string())
- # FIXME(gordc): https://bugs.launchpad.net/oslo-incubator/+bug/1370710
- if six.PY3:
- encoded = encoded.decode()
- print(encoded)
-
-
-def args_array_to_dict(kwargs, key_to_convert):
- values_to_convert = kwargs.get(key_to_convert)
- if values_to_convert:
- try:
- kwargs[key_to_convert] = dict(v.split("=", 1)
- for v in values_to_convert)
- except ValueError:
- raise exc.CommandError(
- '%s must be a list of key=value not "%s"' % (
- key_to_convert, values_to_convert))
- return kwargs
-
-
-def args_array_to_list_of_dicts(kwargs, key_to_convert):
- """Converts ['a=1;b=2','c=3;d=4'] to [{a:1,b:2},{c:3,d:4}]."""
- values_to_convert = kwargs.get(key_to_convert)
- if values_to_convert:
- try:
- kwargs[key_to_convert] = []
- for lst in values_to_convert:
- pairs = lst.split(";")
- dct = dict()
- for pair in pairs:
- kv = pair.split("=", 1)
- dct[kv[0]] = kv[1].strip(" \"'") # strip spaces and quotes
- kwargs[key_to_convert].append(dct)
- except Exception:
- raise exc.CommandError(
- '%s must be a list of key1=value1;key2=value2;... not "%s"' % (
- key_to_convert, values_to_convert))
- return kwargs
-
-
-def key_with_slash_to_nested_dict(kwargs):
- nested_kwargs = {}
- for k in list(kwargs):
- keys = k.split('/', 1)
- if len(keys) == 2:
- nested_kwargs.setdefault(keys[0], {})[keys[1]] = kwargs[k]
- del kwargs[k]
- kwargs.update(nested_kwargs)
- return kwargs
-
-
-def merge_nested_dict(dest, source, depth=0):
- for (key, value) in six.iteritems(source):
- if isinstance(value, dict) and depth:
- merge_nested_dict(dest[key], value,
- depth=(depth - 1))
- else:
- dest[key] = value
-
-
-def env(*args, **kwargs):
- """Returns the first environment variable set.
-
- If all are empty, defaults to '' or keyword arg `default`.
- """
- for arg in args:
- value = os.environ.get(arg)
- if value:
- return value
- return kwargs.get('default', '')
diff --git a/ceilometerclient/exc.py b/ceilometerclient/exc.py
deleted file mode 100644
index 8d56038..0000000
--- a/ceilometerclient/exc.py
+++ /dev/null
@@ -1,144 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import json
-import sys
-
-
-class BaseException(Exception):
- """An error occurred."""
- def __init__(self, message=None):
- self.message = message
-
- def __str__(self):
- return self.message or self.__class__.__doc__
-
-
-class CommandError(BaseException):
- """Invalid usage of CLI."""
-
-
-class InvalidEndpoint(BaseException):
- """The provided endpoint is invalid."""
-
-
-class CommunicationError(BaseException):
- """Unable to communicate with server."""
-
-
-class HTTPException(BaseException):
- """Base exception for all HTTP-derived exceptions."""
- code = 'N/A'
-
- def __init__(self, details=None):
- self.details = details
-
- def __str__(self):
- message = ""
- if self.details:
- message = self.details
- try:
- data = json.loads(self.details)
- message = data.get("error_message", "")
- if isinstance(message, dict) and "faultstring" in message:
- message = "ERROR %s" % message["faultstring"]
- except (ValueError, TypeError, AttributeError):
- pass
-
- if message:
- message = " %s" % message
- return "%s (HTTP %s)%s" % (self.__class__.__name__, self.code,
- message)
-
-
-class HTTPMultipleChoices(HTTPException):
- code = 300
-
- def __str__(self):
- self.details = ("Requested version of OpenStack Images API is not"
- "available.")
- return "%s (HTTP %s) %s" % (self.__class__.__name__, self.code,
- self.details)
-
-
-class HTTPBadRequest(HTTPException):
- code = 400
-
-
-class HTTPUnauthorized(HTTPException):
- code = 401
-
-
-class HTTPForbidden(HTTPException):
- code = 403
-
-
-class HTTPNotFound(HTTPException):
- code = 404
-
-
-class HTTPMethodNotAllowed(HTTPException):
- code = 405
-
-
-class HTTPConflict(HTTPException):
- code = 409
-
-
-class HTTPOverLimit(HTTPException):
- code = 413
-
-
-class HTTPInternalServerError(HTTPException):
- code = 500
-
-
-class HTTPNotImplemented(HTTPException):
- code = 501
-
-
-class HTTPBadGateway(HTTPException):
- code = 502
-
-
-class HTTPServiceUnavailable(HTTPException):
- code = 503
-
-
-# NOTE(bcwaldon): Build a mapping of HTTP codes to corresponding exception
-# classes
-_code_map = {}
-for obj_name in dir(sys.modules[__name__]):
- if obj_name.startswith('HTTP'):
- obj = getattr(sys.modules[__name__], obj_name)
- _code_map[obj.code] = obj
-
-
-def from_response(response, details=None):
- """Return an instance of an HTTPException based on http response."""
- if hasattr(response, "status"):
- # it is response from HTTPClient (httplib)
- code = response.status
- elif hasattr(response, "status_code"):
- # it is response from SessionClient (requests)
- code = response.status_code
- else:
- # it is something unexpected
- raise TypeError("Function 'from_response' expects only response object"
- " from httplib or requests libraries.")
- cls = _code_map.get(code)
- if cls is None:
- exc = HTTPException(details)
- exc.code = code
- return exc
- else:
- return cls(details)
diff --git a/ceilometerclient/i18n.py b/ceilometerclient/i18n.py
deleted file mode 100644
index a567932..0000000
--- a/ceilometerclient/i18n.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# 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 https://docs.openstack.org/oslo.i18n/latest/user/usage.html.
-
-"""
-
-import oslo_i18n
-
-
-_translators = oslo_i18n.TranslatorFactory(domain='ceilometerclient')
-
-# The primary translation function using the well-known name "_"
-_ = _translators.primary
diff --git a/ceilometerclient/shell.py b/ceilometerclient/shell.py
deleted file mode 100644
index d096f3b..0000000
--- a/ceilometerclient/shell.py
+++ /dev/null
@@ -1,287 +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.
-
-"""
-Command-line interface to the OpenStack Telemetry API.
-"""
-
-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
-from ceilometerclient import client as ceiloclient
-from ceilometerclient.common import utils
-from ceilometerclient import exc
-
-
-def _positive_non_zero_int(argument_value):
- if argument_value is None:
- return None
- try:
- value = int(argument_value)
- except ValueError:
- msg = "%s must be an integer" % argument_value
- raise argparse.ArgumentTypeError(msg)
- if value <= 0:
- msg = "%s must be greater than 0" % argument_value
- raise argparse.ArgumentTypeError(msg)
- return value
-
-
-class CeilometerShell(object):
-
- def __init__(self):
- self.auth_plugin = ceiloclient.AuthPlugin()
-
- def get_base_parser(self):
- parser = argparse.ArgumentParser(
- prog='ceilometer',
- description=__doc__.strip(),
- epilog='See "ceilometer help COMMAND" '
- 'for help on a specific command.',
- add_help=False,
- formatter_class=HelpFormatter,
- )
-
- # Global arguments
- parser.add_argument('-h', '--help',
- action='store_true',
- help=argparse.SUPPRESS,
- )
-
- parser.add_argument('--version',
- action='version',
- version=ceilometerclient.__version__)
-
- parser.add_argument('-d', '--debug',
- default=bool(utils.env('CEILOMETERCLIENT_DEBUG')
- ),
- action='store_true',
- help='Defaults to env[CEILOMETERCLIENT_DEBUG].')
-
- parser.add_argument('-v', '--verbose',
- default=False, action="store_true",
- help="Print more verbose output.")
-
- parser.add_argument('--timeout',
- default=600,
- type=_positive_non_zero_int,
- help='Number of seconds to wait for a response.')
-
- parser.add_argument('--ceilometer-url', metavar='<CEILOMETER_URL>',
- dest='os_endpoint',
- default=utils.env('CEILOMETER_URL'),
- help=("DEPRECATED, use --os-endpoint instead. "
- "Defaults to env[CEILOMETER_URL]."))
-
- parser.add_argument('--ceilometer_url',
- dest='os_endpoint',
- help=argparse.SUPPRESS)
-
- parser.add_argument('--ceilometer-api-version',
- default=utils.env(
- 'CEILOMETER_API_VERSION', default='2'),
- help='Defaults to env[CEILOMETER_API_VERSION] '
- 'or 2.')
-
- parser.add_argument('--ceilometer_api_version',
- help=argparse.SUPPRESS)
-
- self.auth_plugin.add_opts(parser)
- self.auth_plugin.add_common_opts(parser)
-
- return parser
-
- def get_subcommand_parser(self, version):
- parser = self.get_base_parser()
-
- self.subcommands = {}
- subparsers = parser.add_subparsers(metavar='<subcommand>')
- submodule = importutils.import_versioned_module('ceilometerclient',
- version, 'shell')
- self._find_actions(subparsers, submodule)
- self._find_actions(subparsers, self)
-
- return parser
-
- 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.
- command = attr[3:].replace('_', '-')
- callback = getattr(actions_module, attr)
- desc = callback.__doc__ or ''
- help = desc.strip().split('\n')[0]
- arguments = getattr(callback, 'arguments', [])
-
- subparser = subparsers.add_parser(command, help=help,
- description=desc,
- add_help=False,
- formatter_class=HelpFormatter)
- subparser.add_argument('-h', '--help', action='help',
- help=argparse.SUPPRESS)
- self.subcommands[command] = subparser
- for (args, kwargs) in arguments:
- subparser.add_argument(*args, **kwargs)
- subparser.set_defaults(func=callback)
-
- @staticmethod
- def _setup_logging(debug):
- format = '%(levelname)s (%(module)s) %(message)s'
- if debug:
- logging.basicConfig(format=format, level=logging.DEBUG)
- else:
- logging.basicConfig(format=format, level=logging.WARN)
- logging.getLogger('iso8601').setLevel(logging.WARNING)
- logging.getLogger('urllib3.connectionpool').setLevel(logging.WARNING)
-
- def parse_args(self, argv):
- # Parse args once to find version
- parser = self.get_base_parser()
- (options, args) = parser.parse_known_args(argv)
- self.auth_plugin.parse_opts(options)
- self._setup_logging(options.debug)
-
- # build available subcommands based on version
- api_version = options.ceilometer_api_version
- subcommand_parser = self.get_subcommand_parser(api_version)
- self.parser = subcommand_parser
-
- # Handle top-level --help/-h before attempting to parse
- # a command off the command line
- if options.help or not argv:
- self.do_help(options)
- return 0
-
- # Return parsed args
- return api_version, subcommand_parser.parse_args(argv)
-
- 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
- api_version, args = parsed
-
- # Short-circuit and deal with help command right away.
- if args.func == self.do_help:
- self.do_help(args)
- return 0
- elif args.func == self.do_bash_completion:
- self.do_bash_completion(args)
- return 0
-
- if not ((self.auth_plugin.opts.get('token')
- or self.auth_plugin.opts.get('auth_token'))
- and self.auth_plugin.opts['endpoint']):
- if not self.auth_plugin.opts['username']:
- raise exc.CommandError("You must provide a username via "
- "either --os-username or via "
- "env[OS_USERNAME]")
-
- if not self.auth_plugin.opts['password']:
- raise exc.CommandError("You must provide a password via "
- "either --os-password or via "
- "env[OS_PASSWORD]")
-
- 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 "
- "(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 "
- "either --os-auth-url or via "
- "env[OS_AUTH_URL]")
-
- client_kwargs = vars(args)
- client_kwargs.update(self.auth_plugin.opts)
- client_kwargs['auth_plugin'] = self.auth_plugin
- client = ceiloclient.get_client(api_version, **client_kwargs)
- # call whatever callback was selected
- try:
- args.func(client, args)
- except exc.HTTPUnauthorized:
- raise exc.CommandError("Invalid OpenStack Identity credentials.")
-
- def do_bash_completion(self, args):
- """Prints all of the commands and options to stdout.
-
- The ceilometer.bash_completion script doesn't have to hard code them.
- """
- commands = set()
- options = set()
- for sc_str, sc in self.subcommands.items():
- commands.add(sc_str)
- for option in list(sc._optionals._option_string_actions):
- options.add(option)
-
- commands.remove('bash-completion')
- print(' '.join(commands | options))
-
- @utils.arg('command', metavar='<subcommand>', nargs='?',
- help='Display help for <subcommand>')
- def do_help(self, args):
- """Display help about this program or one of its subcommands."""
- if getattr(args, 'command', None):
- if args.command in self.subcommands:
- self.subcommands[args.command].print_help()
- else:
- raise exc.CommandError("'%s' is not a valid subcommand" %
- args.command)
- else:
- self.parser.print_help()
-
-
-class HelpFormatter(argparse.HelpFormatter):
- def __init__(self, prog, indent_increment=2, max_help_position=32,
- width=None):
- super(HelpFormatter, self).__init__(prog, indent_increment,
- max_help_position, width)
-
- def start_section(self, heading):
- # Title-case the headings
- heading = '%s%s' % (heading[0].upper(), heading[1:])
- super(HelpFormatter, self).start_section(heading)
-
-
-def main(args=None):
- try:
- if args is None:
- args = sys.argv[1:]
-
- CeilometerShell().main(args)
-
- except Exception as e:
- if '--debug' in args or '-d' in args:
- raise
- else:
- print(encodeutils.safe_encode(six.text_type(e)), file=sys.stderr)
- sys.exit(1)
- except KeyboardInterrupt:
- print("Stopping Ceilometer Client", file=sys.stderr)
- sys.exit(130)
-
-if __name__ == "__main__":
- main()
diff --git a/ceilometerclient/tests/__init__.py b/ceilometerclient/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/ceilometerclient/tests/__init__.py
+++ /dev/null
diff --git a/ceilometerclient/tests/functional/__init__.py b/ceilometerclient/tests/functional/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/ceilometerclient/tests/functional/__init__.py
+++ /dev/null
diff --git a/ceilometerclient/tests/functional/base.py b/ceilometerclient/tests/functional/base.py
deleted file mode 100644
index 524114c..0000000
--- a/ceilometerclient/tests/functional/base.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import os
-
-from tempest.lib.cli import base
-
-
-class ClientTestBase(base.ClientTestBase):
- """Base class for ceilometerclient tests.
-
- Establishes the ceilometer client and retrieves the essential environment
- information.
- """
-
- def _get_clients(self):
- cli_dir = os.environ.get(
- 'OS_CEILOMETER_CLIENT_EXEC_DIR',
- os.path.join(os.path.abspath('.'), '.tox/functional/bin'))
-
- return base.CLIClient(
- username=os.environ.get('OS_USERNAME'),
- password=os.environ.get('OS_PASSWORD'),
- tenant_name=os.environ.get('OS_TENANT_NAME'),
- uri=os.environ.get('OS_AUTH_URL'),
- cli_dir=cli_dir)
-
- def ceilometer(self, *args, **kwargs):
- return self.clients.ceilometer(*args, **kwargs)
diff --git a/ceilometerclient/tests/functional/hooks/post_test_hook.sh b/ceilometerclient/tests/functional/hooks/post_test_hook.sh
deleted file mode 100755
index 385d314..0000000
--- a/ceilometerclient/tests/functional/hooks/post_test_hook.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/bash -xe
-
-# 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 script is executed inside post_test_hook function in devstack gate.
-
-function generate_testr_results {
- if [ -f .testrepository/0 ]; then
- sudo .tox/functional/bin/testr last --subunit > $WORKSPACE/testrepository.subunit
- sudo mv $WORKSPACE/testrepository.subunit $BASE/logs/testrepository.subunit
- sudo /usr/os-testr-env/bin/subunit2html $BASE/logs/testrepository.subunit $BASE/logs/testr_results.html
- sudo gzip -9 $BASE/logs/testrepository.subunit
- sudo gzip -9 $BASE/logs/testr_results.html
- sudo chown $USER:$USER $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz
- sudo chmod a+r $BASE/logs/testrepository.subunit.gz $BASE/logs/testr_results.html.gz
- fi
-}
-
-export CEILOMETERCLIENT_DIR="$BASE/new/python-ceilometerclient"
-
-# Get admin credentials
-cd $BASE/new/devstack
-source openrc admin admin
-
-# Go to the ceilometerclient dir
-cd $CEILOMETERCLIENT_DIR
-
-sudo chown -R $USER:stack $CEILOMETERCLIENT_DIR
-
-# Run tests
-echo "Running ceilometerclient functional test suite"
-set +e
-# Preserve env for OS_ credentials
-sudo -E -H -u $USER tox -efunctional
-EXIT_CODE=$?
-set -e
-
-# Collect and parse result
-generate_testr_results
-exit $EXIT_CODE
diff --git a/ceilometerclient/tests/functional/test_readonly_ceilometer.py b/ceilometerclient/tests/functional/test_readonly_ceilometer.py
deleted file mode 100644
index 53e2192..0000000
--- a/ceilometerclient/tests/functional/test_readonly_ceilometer.py
+++ /dev/null
@@ -1,67 +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.
-
-from ceilometerclient.tests.functional import base
-import re
-
-
-class SimpleReadOnlyCeilometerClientTest(base.ClientTestBase):
- """Basic, read-only tests for Ceilometer CLI client.
-
- Checks return values and output of read-only commands.
- These tests do not presume any content, nor do they create
- their own. They only verify the structure of output if present.
- """
-
- def test_ceilometer_meter_list(self):
- result = self.ceilometer('meter-list')
- meters = self.parser.listing(result)
- self.assertTableStruct(meters, ['Name', 'Type', 'Unit',
- 'Resource ID', 'Project ID'])
-
- def test_ceilometer_resource_list(self):
- result = self.ceilometer('resource-list')
- resources = self.parser.listing(result)
- self.assertTableStruct(resources, ['Resource ID', 'Source',
- 'User ID', 'Project ID'])
-
- def test_ceilometer_alarm_list(self):
- result = self.ceilometer('alarm-list')
- alarm = self.parser.listing(result)
- self.assertTableStruct(alarm, ['Alarm ID', 'Name', 'State',
- 'Enabled', 'Continuous'])
-
- def test_admin_help(self):
- help_text = self.ceilometer('help')
- lines = help_text.split('\n')
- self.assertFirstLineStartsWith(lines, 'usage: ceilometer')
-
- commands = []
- cmds_start = lines.index('Positional arguments:')
- cmds_end = lines.index('Optional arguments:')
- command_pattern = re.compile('^ {4}([a-z0-9\-\_]+)')
- for line in lines[cmds_start:cmds_end]:
- match = command_pattern.match(line)
- if match:
- commands.append(match.group(1))
- commands = set(commands)
- wanted_commands = set(('alarm-combination-create', 'alarm-create',
- 'help', 'alarm-delete', 'event-list'))
- self.assertFalse(wanted_commands - commands)
-
- def test_ceilometer_bash_completion(self):
- self.ceilometer('bash-completion')
-
- # Optional arguments
-
- def test_ceilometer_debug_list(self):
- self.ceilometer('meter-list', flags='--debug')
diff --git a/ceilometerclient/tests/unit/__init__.py b/ceilometerclient/tests/unit/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/ceilometerclient/tests/unit/__init__.py
+++ /dev/null
diff --git a/ceilometerclient/tests/unit/test_client.py b/ceilometerclient/tests/unit/test_client.py
deleted file mode 100644
index 400e997..0000000
--- a/ceilometerclient/tests/unit/test_client.py
+++ /dev/null
@@ -1,430 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import types
-
-from keystoneauth1 import exceptions as ks_exc
-from keystoneauth1.identity import v2 as v2_auth
-from keystoneauth1.identity import v3 as v3_auth
-from keystoneauth1 import session as ks_session
-import mock
-import requests
-
-from ceilometerclient.apiclient import exceptions
-from ceilometerclient import client
-from ceilometerclient import exc
-from ceilometerclient.tests.unit import utils
-from ceilometerclient.v2 import client as v2client
-
-FAKE_ENV = {
- 'username': 'username',
- 'password': 'password',
- 'tenant_name': 'tenant_name',
- 'auth_url': 'http://no.where',
- 'auth_plugin': mock.Mock(),
- 'ceilometer_url': 'http://no.where',
- 'token': '1234',
- 'user_domain_name': 'default',
- 'project_domain_name': 'default',
-}
-
-
-class ClientTest(utils.BaseTestCase):
- @staticmethod
- 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_redirect_client',
- return_value=None):
- return client.get_client(api_version, **env)
-
- def test_client_v2_with_session(self):
- resp = mock.Mock(status_code=200, text=b'')
- resp.json.return_value = []
- session = mock.Mock()
- session.request.return_value = resp
- c = client.get_client(2, session=session)
- c.resources.list()
- self.assertTrue(session.request.called)
- self.assertTrue(resp.json.called)
-
- def test_client_version(self):
- c2 = self.create_client(env=FAKE_ENV, api_version=2)
- self.assertIsInstance(c2, v2client.Client)
-
- def test_client_auth_lambda(self):
- env = FAKE_ENV.copy()
- env['token'] = lambda: env['token']
- self.assertIsInstance(env['token'],
- types.FunctionType)
- c2 = self.create_client(env)
- self.assertIsInstance(c2, v2client.Client)
-
- def test_client_auth_non_lambda(self):
- env = FAKE_ENV.copy()
- env['token'] = "1234"
- self.assertIsInstance(env['token'], str)
- c2 = self.create_client(env)
- self.assertIsInstance(c2, v2client.Client)
-
- def test_client_without_auth_plugin(self):
- env = FAKE_ENV.copy()
- del env['auth_plugin']
- c = self.create_client(env, api_version=2, endpoint='fake_endpoint')
- self.assertIsInstance(c.auth_plugin, client.AuthPlugin)
-
- def test_client_without_auth_plugin_keystone_v3(self):
- env = FAKE_ENV.copy()
- del env['auth_plugin']
- expected = {
- 'username': 'username',
- 'endpoint': 'http://no.where',
- 'tenant_name': 'tenant_name',
- 'service_type': None,
- 'token': '1234',
- 'endpoint_type': None,
- 'region_name': None,
- 'auth_url': 'http://no.where',
- 'tenant_id': None,
- 'insecure': None,
- 'cacert': None,
- 'password': 'password',
- 'user_domain_name': 'default',
- 'user_domain_id': None,
- 'project_domain_name': 'default',
- 'project_domain_id': None,
- }
- with mock.patch('ceilometerclient.client.AuthPlugin') as auth_plugin:
- self.create_client(env, api_version=2, endpoint='http://no.where')
- self.assertEqual(mock.call(**expected),
- auth_plugin.mock_calls[0])
-
- def test_v2_client_timeout_invalid_value(self):
- env = FAKE_ENV.copy()
- env['timeout'] = 'abc'
- self.assertRaises(ValueError, self.create_client, env)
- env['timeout'] = '1.5'
- self.assertRaises(ValueError, self.create_client, env)
-
- def _test_v2_client_timeout_integer(self, timeout, expected_value):
- env = FAKE_ENV.copy()
- env['timeout'] = timeout
- expected = {
- 'auth_plugin': mock.ANY,
- 'timeout': expected_value,
- 'original_ip': None,
- 'http': None,
- 'region_name': None,
- 'verify': True,
- 'timings': None,
- 'keyring_saver': None,
- 'cert': None,
- 'endpoint_type': None,
- 'user_agent': None,
- 'debug': None,
- }
- cls = 'ceilometerclient.apiclient.client.HTTPClient'
- with mock.patch(cls) as mocked:
- self.create_client(env)
- mocked.assert_called_with(**expected)
-
- def test_v2_client_timeout_zero(self):
- self._test_v2_client_timeout_integer(0, None)
-
- def test_v2_client_timeout_valid_value(self):
- self._test_v2_client_timeout_integer(30, 30)
-
- @mock.patch.object(ks_session, 'Session')
- def test_v2_client_timeout_keystone_session(self, mocked_session):
- mocked_session.side_effect = RuntimeError('Stop!')
- env = FAKE_ENV.copy()
- env['timeout'] = 5
- del env['auth_plugin']
- del env['token']
- client = self.create_client(env)
- self.assertRaises(RuntimeError, client.alarms.list)
- args, kwargs = mocked_session.call_args
- self.assertEqual(5, kwargs['timeout'])
-
- def test_v2_client_cacert_in_verify(self):
- env = FAKE_ENV.copy()
- env['cacert'] = '/path/to/cacert'
- client = self.create_client(env)
- self.assertEqual('/path/to/cacert',
- client.http_client.http_client.verify)
-
- def test_v2_client_certfile_and_keyfile(self):
- env = FAKE_ENV.copy()
- env['cert_file'] = '/path/to/cert'
- env['key_file'] = '/path/to/keycert'
- client = self.create_client(env)
- self.assertEqual(('/path/to/cert', '/path/to/keycert'),
- client.http_client.http_client.cert)
-
- def test_v2_client_insecure(self):
- env = FAKE_ENV.copy()
- env.pop('auth_plugin')
- env['os_insecure'] = 'True'
- client = self.create_client(env)
- self.assertIn('insecure', client.auth_plugin.opts)
- self.assertEqual('True', client.auth_plugin.opts['insecure'])
-
-
-class ClientTest2(ClientTest):
- @staticmethod
- 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_redirect_client',
- return_value=None):
- return client.Client(api_version, endpoint, **env)
-
-
-class ClientTestWithAodh(ClientTest):
- @staticmethod
- 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.apiclient.client.'
- 'HTTPClient.client_request',
- return_value=mock.MagicMock()):
- return client.get_client(api_version, **env)
-
- def test_client_without_auth_plugin(self):
- env = FAKE_ENV.copy()
- del env['auth_plugin']
- c = self.create_client(env, api_version=2, endpoint='fake_endpoint')
- self.assertIsInstance(c.alarm_client.http_client.auth_plugin,
- client.AuthPlugin)
-
- def test_v2_client_insecure(self):
- env = FAKE_ENV.copy()
- env.pop('auth_plugin')
- env['insecure'] = 'True'
- client = self.create_client(env)
- self.assertIn('insecure',
- client.alarm_client.http_client.auth_plugin.opts)
- self.assertEqual('True', (client.alarm_client.http_client.
- auth_plugin.opts['insecure']))
-
- def test_ceilometerclient_available_without_aodh_services_running(self):
- env = FAKE_ENV.copy()
- env.pop('auth_plugin', None)
- 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)
- self.assertIsInstance(ceiloclient, v2client.Client)
-
- @mock.patch('ceilometerclient.client.SessionClient')
- def test_http_client_with_session_and_aodh(self, mock_sc):
- session = mock.Mock()
- kwargs = {"session": session,
- "service_type": "metering",
- "user_agent": "python-ceilometerclient"}
- expected = {
- "auth": None,
- "interface": 'publicURL',
- "region_name": None,
- "timings": None,
- "session": session,
- "service_type": "metering",
- "user_agent": "python-ceilometerclient"}
- kwargs['aodh_endpoint'] = 'http://aodh.where'
- client._construct_http_client(**kwargs)
- mock_sc.assert_called_with(**expected)
-
-
-class ClientAuthTest(utils.BaseTestCase):
-
- @staticmethod
- 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.apiclient.client.'
- 'HTTPClient.client_request',
- return_value=mock.MagicMock()):
- return client.get_client(api_version, **env)
-
- @mock.patch('keystoneauth1.discover.Discover')
- @mock.patch('keystoneauth1.session.Session')
- def test_discover_auth_versions(self, session, discover_mock):
- env = FAKE_ENV.copy()
- env.pop('auth_plugin', None)
-
- mock_session_instance = mock.MagicMock()
- session.return_value = mock_session_instance
-
- client = self.create_client(env)
- client.auth_plugin.opts.pop('token', None)
- client.auth_plugin._do_authenticate(mock.MagicMock())
-
- self.assertEqual([mock.call(url='http://no.where',
- session=mock_session_instance)],
- discover_mock.call_args_list)
- self.assertIsInstance(mock_session_instance.auth, v3_auth.Password)
-
- @mock.patch('keystoneauth1.discover.Discover')
- @mock.patch('keystoneauth1.session.Session')
- def test_discover_auth_versions_v2_only(self, session, discover):
- env = FAKE_ENV.copy()
- env.pop('auth_plugin', None)
- env.pop('user_domain_name', None)
- env.pop('user_domain_id', None)
- env.pop('project_domain_name', None)
- env.pop('project_domain_id', None)
-
- session_instance_mock = mock.MagicMock()
- session.return_value = session_instance_mock
-
- discover_instance_mock = mock.MagicMock()
- discover_instance_mock.url_for.side_effect = (lambda v: v
- if v == '2.0' else None)
- discover.return_value = discover_instance_mock
-
- client = self.create_client(env)
- client.auth_plugin.opts.pop('token', None)
- client.auth_plugin._do_authenticate(mock.MagicMock())
- self.assertEqual([mock.call(url='http://no.where',
- session=session_instance_mock)],
- discover.call_args_list)
-
- self.assertIsInstance(session_instance_mock.auth, v2_auth.Password)
-
- @mock.patch('keystoneauth1.discover.Discover')
- @mock.patch('keystoneauth1.session.Session')
- def test_discover_auth_versions_raise_discovery_failure(self,
- session,
- discover):
- env = FAKE_ENV.copy()
- env.pop('auth_plugin', None)
- env.pop('token', None)
-
- session_instance_mock = mock.MagicMock()
- session.return_value = session_instance_mock
-
- discover_instance_mock = mock.MagicMock()
- discover_instance_mock.url_for.side_effect = (lambda v: v
- if v == '2.0' else None)
- discover.side_effect = ks_exc.DiscoveryFailure
- client = self.create_client(env)
- self.assertRaises(ks_exc.DiscoveryFailure,
- client.auth_plugin._do_authenticate,
- mock.Mock())
- discover.side_effect = mock.MagicMock()
- client = self.create_client(env)
- discover.side_effect = ks_exc.DiscoveryFailure
- client.auth_plugin.opts.pop('token', None)
-
- self.assertRaises(ks_exc.DiscoveryFailure,
- client.auth_plugin._do_authenticate,
- mock.Mock())
- self.assertEqual([mock.call(url='http://no.where',
- session=session_instance_mock),
- mock.call(url='http://no.where',
- session=session_instance_mock)],
- discover.call_args_list)
-
- @mock.patch('ceilometerclient.client._get_keystone_session')
- def test_get_endpoint(self, session):
- env = FAKE_ENV.copy()
- env.pop('auth_plugin', None)
- env.pop('endpoint', None)
-
- session_instance_mock = mock.MagicMock()
- session.return_value = session_instance_mock
-
- client = self.create_client(env)
- client.auth_plugin.opts.pop('endpoint')
- client.auth_plugin.opts.pop('token', None)
- alarm_auth_plugin = client.alarm_client.http_client.auth_plugin
- alarm_auth_plugin.opts.pop('endpoint')
- alarm_auth_plugin.opts.pop('token', None)
-
- self.assertNotEqual(client.auth_plugin, alarm_auth_plugin)
-
- client.auth_plugin._do_authenticate(mock.MagicMock())
- alarm_auth_plugin._do_authenticate(mock.MagicMock())
-
- self.assertEqual([
- mock.call(interface='publicURL', region_name=None,
- service_type='metering'),
- mock.call(interface='publicURL', region_name=None,
- service_type='alarming'),
- ], session_instance_mock.get_endpoint.mock_calls)
-
- def test_http_client_with_session(self):
- session = mock.Mock()
- session.request.return_value = mock.Mock(status_code=404,
- text=b'')
- env = {"session": session,
- "service_type": "metering",
- "user_agent": "python-ceilometerclient"}
- c = client.SessionClient(**env)
- self.assertRaises(exc.HTTPException, c.get, "/")
-
- def test_get_aodh_endpoint_without_auth_url(self):
- env = FAKE_ENV.copy()
- env.pop('auth_plugin', None)
- env.pop('endpoint', None)
- env.pop('auth_url', None)
- client = self.create_client(env, endpoint='fake_endpoint')
- self.assertEqual(client.alarm_client.http_client.auth_plugin.opts,
- client.auth_plugin.opts)
-
- @mock.patch('ceilometerclient.client._get_keystone_session')
- def test_get_different_endpoint_type(self, session):
- env = FAKE_ENV.copy()
- env.pop('auth_plugin', None)
- env.pop('endpoint', None)
- env['endpoint_type'] = 'internal'
-
- session_instance_mock = mock.MagicMock()
- session.return_value = session_instance_mock
-
- client = self.create_client(env)
- client.auth_plugin.opts.pop('endpoint')
- client.auth_plugin.opts.pop('token', None)
- alarm_auth_plugin = client.alarm_client.http_client.auth_plugin
- alarm_auth_plugin.opts.pop('endpoint')
- alarm_auth_plugin.opts.pop('token', None)
-
- self.assertNotEqual(client.auth_plugin, alarm_auth_plugin)
-
- client.auth_plugin._do_authenticate(mock.MagicMock())
- alarm_auth_plugin._do_authenticate(mock.MagicMock())
-
- self.assertEqual([
- mock.call(interface='internal', region_name=None,
- service_type='metering'),
- mock.call(interface='internal', region_name=None,
- service_type='alarming'),
- ], session_instance_mock.get_endpoint.mock_calls)
-
- @mock.patch('ceilometerclient.client._get_keystone_session')
- def test_get_sufficient_options_missing(self, session):
- env = FAKE_ENV.copy()
- env.pop('auth_plugin', None)
- env.pop('password', None)
- env.pop('endpoint', None)
- env.pop('auth_token', None)
- env.pop('tenant_name', None)
- env.pop('username', None)
-
- session_instance_mock = mock.MagicMock()
- session.return_value = session_instance_mock
- client = self.create_client(env)
- client.auth_plugin.opts.pop('token', None)
- self.assertRaises(exceptions.AuthPluginOptionsMissing,
- client.auth_plugin.sufficient_options)
diff --git a/ceilometerclient/tests/unit/test_exc.py b/ceilometerclient/tests/unit/test_exc.py
deleted file mode 100644
index e67cfc8..0000000
--- a/ceilometerclient/tests/unit/test_exc.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# Copyright 2013 eNovance
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import json
-
-from ceilometerclient import exc
-from ceilometerclient.tests.unit import utils
-
-HTTPEXCEPTIONS = {'HTTPBadRequest': exc.HTTPBadRequest,
- 'HTTPUnauthorized': exc.HTTPUnauthorized,
- 'HTTPForbidden': exc.HTTPForbidden,
- 'HTTPNotFound': exc.HTTPNotFound,
- 'HTTPMethodNotAllowed': exc.HTTPMethodNotAllowed,
- 'HTTPConflict': exc.HTTPConflict,
- 'HTTPOverLimit': exc.HTTPOverLimit,
- 'HTTPInternalServerError': exc.HTTPInternalServerError,
- 'HTTPNotImplemented': exc.HTTPNotImplemented,
- 'HTTPBadGateway': exc.HTTPBadGateway,
- 'HTTPServiceUnavailable': exc.HTTPServiceUnavailable}
-
-
-class HTTPExceptionsTest(utils.BaseTestCase):
- def test_str_no_details(self):
- for k, v in HTTPEXCEPTIONS.items():
- exception = v()
- ret_str = k + " (HTTP " + str(exception.code) + ")"
- self.assertEqual(ret_str, str(exception))
-
- def test_str_no_json(self):
- for k, v in HTTPEXCEPTIONS.items():
- exception = v(details="foo")
- ret_str = k + " (HTTP " + str(exception.code) + ") foo"
- self.assertEqual(ret_str, str(exception))
-
- def test_str_no_error_message(self):
- for k, v in HTTPEXCEPTIONS.items():
- exception = v(details=json.dumps({}))
- ret_str = k + " (HTTP " + str(exception.code) + ")"
- self.assertEqual(ret_str, str(exception))
-
- def test_str_no_faultstring(self):
- for k, v in HTTPEXCEPTIONS.items():
- exception = v(
- details=json.dumps({"error_message": {"foo": "bar"}}))
- ret_str = (k + " (HTTP " + str(exception.code) + ") " +
- str({u'foo': u'bar'}))
- self.assertEqual(ret_str, str(exception))
-
- def test_str_error_message_unknown_format(self):
- for k, v in HTTPEXCEPTIONS.items():
- exception = v(details=json.dumps({"error_message": "oops"}))
- ret_str = k + " (HTTP " + str(exception.code) + ") oops"
- self.assertEqual(ret_str, str(exception))
-
- def test_str_faultstring(self):
- for k, v in HTTPEXCEPTIONS.items():
- exception = v(details=json.dumps(
- {"error_message": {"faultstring": "oops"}}))
- ret_str = k + " (HTTP " + str(exception.code) + ") ERROR oops"
- self.assertEqual(ret_str, str(exception))
-
- def test_from_response(self):
- class HTTPLibLikeResponse(object):
- status = 400
-
- class RequestsLikeResponse(object):
- status_code = 401
-
- class UnexpectedResponse(object):
- code = 200
-
- self.assertEqual(HTTPLibLikeResponse.status,
- exc.from_response(HTTPLibLikeResponse).code)
- self.assertEqual(RequestsLikeResponse.status_code,
- exc.from_response(RequestsLikeResponse).code)
- self.assertRaises(TypeError, exc.from_response, UnexpectedResponse)
diff --git a/ceilometerclient/tests/unit/test_openstack_common.py b/ceilometerclient/tests/unit/test_openstack_common.py
deleted file mode 100644
index 04a94e2..0000000
--- a/ceilometerclient/tests/unit/test_openstack_common.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2015 Huawei.
-# 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.
-
-from ceilometerclient.common import base
-from ceilometerclient.tests.unit import utils
-from ceilometerclient.v2 import events
-
-
-class BaseTest(utils.BaseTestCase):
-
- def test_two_resources_with_same_id_are_not_equal(self):
- # Two resources with same ID: never equal if their info is not equal
- r1 = base.Resource(None, {'id': 1, 'name': 'hi'})
- r2 = base.Resource(None, {'id': 1, 'name': 'hello'})
- self.assertNotEqual(r1, r2)
-
- def test_two_resources_with_same_id_and_info_are_equal(self):
- # Two resources with same ID: equal if their info is equal
- r1 = base.Resource(None, {'id': 1, 'name': 'hello'})
- r2 = base.Resource(None, {'id': 1, 'name': 'hello'})
- self.assertEqual(r1, r2)
-
- def test_two_resources_with_diff_type_are_not_equal(self):
- # Two resources of different types: never equal
- r1 = base.Resource(None, {'id': 1})
- r2 = events.Event(None, {'id': 1})
- self.assertNotEqual(r1, r2)
-
- def test_two_resources_with_no_id_are_equal(self):
- # Two resources with no ID: equal if their info is equal
- r1 = base.Resource(None, {'name': 'joe', 'age': 12})
- r2 = base.Resource(None, {'name': 'joe', 'age': 12})
- self.assertEqual(r1, r2)
diff --git a/ceilometerclient/tests/unit/test_shell.py b/ceilometerclient/tests/unit/test_shell.py
deleted file mode 100644
index d666594..0000000
--- a/ceilometerclient/tests/unit/test_shell.py
+++ /dev/null
@@ -1,287 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import re
-import sys
-
-import fixtures
-from keystoneauth1 import session as ks_session
-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 import shell as ceilometer_shell
-from ceilometerclient.tests.unit import utils
-
-FAKE_V2_ENV = {'OS_USERNAME': 'username',
- 'OS_PASSWORD': 'password',
- 'OS_TENANT_NAME': 'tenant_name',
- 'OS_AUTH_URL': 'http://localhost:5000/v2.0'}
-
-FAKE_V3_ENV = {'OS_USERNAME': 'username',
- 'OS_PASSWORD': 'password',
- 'OS_USER_DOMAIN_NAME': 'domain_name',
- 'OS_PROJECT_ID': '1234567890',
- 'OS_AUTH_URL': 'http://localhost:5000/v3'}
-
-
-class ShellTestBase(utils.BaseTestCase):
-
- @mock.patch('sys.stdout', new=six.StringIO())
- @mock.patch.object(ks_session, 'Session', mock.MagicMock())
- @mock.patch.object(client.client.HTTPClient,
- 'client_request', mock.MagicMock())
- def shell(self, argstr):
- try:
- _shell = ceilometer_shell.CeilometerShell()
- _shell.main(argstr.split())
- except SystemExit:
- exc_type, exc_value, exc_traceback = sys.exc_info()
- self.assertEqual(0, exc_value.code)
-
- return sys.stdout.getvalue()
-
- # Patch os.environ to avoid required auth info.
- def make_env(self, env_version, exclude=None):
- env = dict((k, v) for k, v in env_version.items() if k != exclude)
- self.useFixture(fixtures.MonkeyPatch('os.environ', env))
-
-
-class ShellHelpTest(ShellTestBase):
- RE_OPTIONS = re.DOTALL | re.MULTILINE
-
- def test_help_unknown_command(self):
- self.assertRaises(exc.CommandError, self.shell, 'help foofoo')
-
- def test_help(self):
- required = [
- '.*?^usage: ceilometer',
- '.*?^See "ceilometer help COMMAND" '
- 'for help on a specific command',
- ]
- for argstr in ['--help', 'help']:
- help_text = self.shell(argstr)
- for r in required:
- self.assertThat(help_text,
- matchers.MatchesRegex(r,
- self.RE_OPTIONS))
-
- def test_help_on_subcommand(self):
- required = [
- '.*?^usage: ceilometer meter-list',
- ".*?^List the user's meter",
- ]
- argstrings = [
- 'help meter-list',
- ]
- for argstr in argstrings:
- help_text = self.shell(argstr)
- for r in required:
- self.assertThat(help_text,
- matchers.MatchesRegex(r, self.RE_OPTIONS))
-
- def test_get_base_parser(self):
- standalone_shell = ceilometer_shell.CeilometerShell()
- parser = standalone_shell.get_base_parser()
- self.assertEqual(600, parser.get_default('timeout'))
-
-
-class ShellBashCompletionTest(ShellTestBase):
-
- def test_bash_completion(self):
- completion_commands = self.shell("bash-completion")
- options = completion_commands.split(' ')
- self.assertNotIn('bash_completion', options)
- for option in options:
- self.assertThat(option,
- matchers.MatchesRegex(r'[a-z0-9-]'))
-
-
-class ShellKeystoneV2Test(ShellTestBase):
-
- @mock.patch.object(ks_session, 'Session')
- @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_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']
- self.assertRaises(exc.CommandError, ceilometer_shell.main, args)
-
- @mock.patch('sys.stderr')
- @mock.patch.object(ks_session, 'Session')
- def test_no_debug_switch_no_raises_errors(self, mock_ksclient, __):
- mock_ksclient.side_effect = exc.HTTPUnauthorized("FAIL")
- self.make_env(FAKE_V2_ENV)
- args = ['event-list']
- self.assertRaises(SystemExit, ceilometer_shell.main, args)
-
-
-class ShellKeystoneV3Test(ShellTestBase):
-
- @mock.patch.object(ks_session, 'Session')
- @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']
- self.assertRaises(exc.CommandError, ceilometer_shell.main, args)
-
- @mock.patch.object(ks_session, 'Session')
- def test_dash_d_switch_raises_error(self, mock_ksclient):
- mock_ksclient.side_effect = exc.CommandError("FAIL")
- self.make_env(FAKE_V3_ENV)
- args = ['-d', 'event-list']
- self.assertRaises(exc.CommandError, ceilometer_shell.main, args)
-
- @mock.patch('sys.stderr')
- @mock.patch.object(ks_session, 'Session')
- def test_no_debug_switch_no_raises_errors(self, mock_ksclient, __):
- mock_ksclient.side_effect = exc.HTTPUnauthorized("FAIL")
- self.make_env(FAKE_V3_ENV)
- args = ['event-list']
- self.assertRaises(SystemExit, ceilometer_shell.main, args)
-
-
-class ShellTimeoutTest(ShellTestBase):
-
- @mock.patch('sys.stderr', new=six.StringIO())
- def _test_timeout(self, timeout, expected_msg):
- args = ['--timeout', timeout, 'alarm-list']
- self.assertRaises(SystemExit, ceilometer_shell.main, args)
- self.assertEqual(expected_msg, sys.stderr.getvalue().splitlines()[-1])
-
- def test_timeout_invalid_value(self):
- expected_msg = ('ceilometer: error: argument --timeout: '
- 'abc must be an integer')
- self._test_timeout('abc', expected_msg)
-
- def test_timeout_negative_value(self):
- expected_msg = ('ceilometer: error: argument --timeout: '
- '-1 must be greater than 0')
- self._test_timeout('-1', expected_msg)
-
- def test_timeout_float_value(self):
- expected_msg = ('ceilometer: error: argument --timeout: '
- '1.5 must be an integer')
- self._test_timeout('1.5', expected_msg)
-
- def test_timeout_zero(self):
- expected_msg = ('ceilometer: error: argument --timeout: '
- '0 must be greater than 0')
- self._test_timeout('0', expected_msg)
-
- @mock.patch.object(ks_session, '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']
- self.assertRaises(exc.CommandError, ceilometer_shell.main, args)
- args, kwargs = mocked_session.call_args
- self.assertEqual(5, kwargs.get('timeout'))
-
-
-class ShellInsecureTest(ShellTestBase):
-
- @mock.patch.object(api_client, 'HTTPClient')
- @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))
- args, kwargs = mocked_client.call_args
- self.assertFalse(kwargs.get('verify'))
-
- @mock.patch.object(ks_session, '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']
- self.assertRaises(exc.CommandError, ceilometer_shell.main, args)
- args, kwargs = mocked_session.call_args
- self.assertFalse(kwargs.get('verify'))
-
- @mock.patch.object(api_client, 'HTTPClient')
- @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))
- args, kwargs = mocked_client.call_args
- self.assertTrue(kwargs.get('verify'))
-
- @mock.patch.object(ks_session, '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']
- self.assertRaises(exc.CommandError, ceilometer_shell.main, args)
- args, kwargs = mocked_session.call_args
- self.assertTrue(kwargs.get('verify'))
-
-
-class ShellEndpointTest(ShellTestBase):
-
- @mock.patch('ceilometerclient.v2.client.Client')
- def _test_endpoint_and_token(self, token_name, endpoint_name, mocked):
- args = ['--debug', token_name, 'fake-token',
- endpoint_name, 'http://fake-url', 'alarm-list']
- self.assertIsNone(ceilometer_shell.main(args))
- args, kwargs = mocked.call_args
- self.assertEqual('http://fake-url', kwargs.get('endpoint'))
- self.assertEqual('fake-token', kwargs.get('token'))
-
- def test_endpoint_and_token(self):
- self._test_endpoint_and_token('--os-auth-token', '--ceilometer-url')
- self._test_endpoint_and_token('--os-auth-token', '--os-endpoint')
- self._test_endpoint_and_token('--os-token', '--ceilometer-url')
- self._test_endpoint_and_token('--os-token', '--os-endpoint')
-
-
-class ShellAlarmUpdateRepeatAction(ShellTestBase):
- @mock.patch('ceilometerclient.v2.alarms.AlarmManager.update')
- @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)
-
- def _test(method):
- args = ['--debug', method, '--state', 'alarm', '123']
- ceilometer_shell.main(args)
- args, kwargs = mocked.call_args
- self.assertIsNone(kwargs.get('repeat_actions'))
-
- _test('alarm-update')
- _test('alarm-threshold-update')
- _test('alarm-combination-update')
- _test('alarm-event-update')
diff --git a/ceilometerclient/tests/unit/test_utils.py b/ceilometerclient/tests/unit/test_utils.py
deleted file mode 100644
index 5b20437..0000000
--- a/ceilometerclient/tests/unit/test_utils.py
+++ /dev/null
@@ -1,298 +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.
-
-import itertools
-
-import mock
-import six
-
-from ceilometerclient.common import utils
-from ceilometerclient.tests.unit import utils as test_utils
-
-
-class UtilsTest(test_utils.BaseTestCase):
-
- def test_prettytable(self):
- class Struct(object):
- def __init__(self, **entries):
- self.__dict__.update(entries)
-
- # test that the prettytable output is wellformatted (left-aligned)
- with mock.patch('sys.stdout', new=six.StringIO()) as stdout:
- utils.print_dict({'K': 'k', 'Key': 'Value'})
- self.assertEqual('''\
-+----------+-------+
-| Property | Value |
-+----------+-------+
-| K | k |
-| Key | Value |
-+----------+-------+
-''', stdout.getvalue())
-
- with mock.patch('sys.stdout', new=six.StringIO()) as stdout:
- utils.print_dict({'alarm_id': '262567fd-d79a-4bbb-a9d0-59d879b6',
- 'name': u'\u6d4b\u8bd5',
- 'description': u'\u6d4b\u8bd5',
- 'state': 'insufficient data',
- 'repeat_actions': 'False',
- 'type': 'threshold',
- 'threshold': '1.0',
- 'statistic': 'avg',
- 'alarm_actions': [u'http://something/alarm1',
- u'http://something/alarm2'],
- 'ok_actions': [{"get_attr1":
- [u"web_server_scaleup_policy1",
- u"alarm_url1"]},
- {"get_attr2":
- [u"web_server_scaleup_policy2",
- u"alarm_url2"]}],
- 'time_constraints': '[{name: c1,'
- '\\n description: test,'
- '\\n start: 0 18 * * *,'
- '\\n duration: 1,'
- '\\n timezone: US}]'},
- wrap=72)
- expected = u'''\
-+------------------+-------------------------------------------------------\
---------+
-| Property | Value \
- |
-+------------------+-------------------------------------------------------\
---------+
-| alarm_actions | ["http://something/alarm1", "http://something/alarm2"]\
- |
-| alarm_id | 262567fd-d79a-4bbb-a9d0-59d879b6 \
- |
-| description | \u6d4b\u8bd5 \
- |
-| name | \u6d4b\u8bd5 \
- |
-| ok_actions | [{"get_attr1": ["web_server_scaleup_policy1", "alarm_u\
-rl1"]}, |
-| | {"get_attr2": ["web_server_scaleup_policy2", "alarm_ur\
-l2"]}] |
-| repeat_actions | False \
- |
-| state | insufficient data \
- |
-| statistic | avg \
- |
-| threshold | 1.0 \
- |
-| time_constraints | [{name: c1, \
- |
-| | description: test, \
- |
-| | start: 0 18 * * *, \
- |
-| | duration: 1, \
- |
-| | timezone: US}] \
- |
-| type | threshold \
- |
-+------------------+-------------------------------------------------------\
---------+
-'''
- # py2 prints str type, py3 prints unicode type
- if six.PY2:
- expected = expected.encode('utf-8')
- self.assertEqual(expected, stdout.getvalue())
-
- def test_print_list(self):
- class Foo(object):
- def __init__(self, one, two, three):
- self.one = one
- self.two = two
- self.three = three
-
- foo_list = [
- Foo(10, 'a', 'B'),
- Foo(8, 'c', 'c'),
- Foo(12, '0', 'Z')]
-
- def do_print_list(sortby):
- with mock.patch('sys.stdout', new=six.StringIO()) as stdout:
- utils.print_list(foo_list,
- ['one', 'two', 'three'],
- ['1st', '2nd', '3rd'],
- {'one': lambda o: o.one * 10},
- sortby)
- return stdout.getvalue()
-
- printed = do_print_list(None)
- self.assertEqual('''\
-+-----+-----+-----+
-| 1st | 2nd | 3rd |
-+-----+-----+-----+
-| 100 | a | B |
-| 80 | c | c |
-| 120 | 0 | Z |
-+-----+-----+-----+
-''', printed)
-
- printed = do_print_list(0)
- self.assertEqual('''\
-+-----+-----+-----+
-| 1st | 2nd | 3rd |
-+-----+-----+-----+
-| 80 | c | c |
-| 100 | a | B |
-| 120 | 0 | Z |
-+-----+-----+-----+
-''', printed)
-
- printed = do_print_list(1)
- self.assertEqual('''\
-+-----+-----+-----+
-| 1st | 2nd | 3rd |
-+-----+-----+-----+
-| 120 | 0 | Z |
-| 100 | a | B |
-| 80 | c | c |
-+-----+-----+-----+
-''', printed)
-
- def test_args_array_to_dict(self):
- my_args = {
- 'matching_metadata': ['metadata.key=metadata_value'],
- 'other': 'value'
- }
- cleaned_dict = utils.args_array_to_dict(my_args,
- "matching_metadata")
- self.assertEqual({
- 'matching_metadata': {'metadata.key': 'metadata_value'},
- 'other': 'value'
- }, cleaned_dict)
-
- def test_args_array_to_list_of_dicts(self):
- starts = ['0 11 * * *', '"0 11 * * *"', '\'0 11 * * *\'']
- timezones = [None, 'US/Eastern', '"US/Eastern"', '\'US/Eastern\'']
- descs = [None, 'de sc', '"de sc"', '\'de sc\'']
- for start, tz, desc in itertools.product(starts, timezones, descs):
- my_args = {
- 'time_constraints': ['name=const1;start=%s;duration=1'
- % start],
- 'other': 'value'
- }
- expected = {
- 'time_constraints': [dict(name='const1',
- start='0 11 * * *',
- duration='1')],
- 'other': 'value'
- }
- if tz:
- my_args['time_constraints'][0] += ';timezone=%s' % tz
- expected['time_constraints'][0]['timezone'] = 'US/Eastern'
- if desc:
- my_args['time_constraints'][0] += ';description=%s' % desc
- expected['time_constraints'][0]['description'] = 'de sc'
-
- cleaned = utils.args_array_to_list_of_dicts(my_args,
- 'time_constraints')
- self.assertEqual(expected, cleaned)
-
- def test_key_with_slash_to_nested_dict(self):
- my_args = {
- 'combination_rule/alarm_ids': ['id1', 'id2'],
- 'combination_rule/operator': 'and',
- 'threshold_rule/threshold': 400,
- 'threshold_rule/statictic': 'avg',
- 'threshold_rule/comparison_operator': 'or',
- }
- nested_dict = utils.key_with_slash_to_nested_dict(my_args)
- self.assertEqual({
- 'combination_rule': {'alarm_ids': ['id1', 'id2'],
- 'operator': 'and'},
- 'threshold_rule': {'threshold': 400,
- 'statictic': 'avg',
- 'comparison_operator': 'or'},
- }, nested_dict)
-
- def test_arg(self):
- @utils.arg(help="not_required_no_default.")
- def not_required_no_default():
- pass
- _, args = not_required_no_default.__dict__['arguments'][0]
- self.assertEqual("not_required_no_default.", args['help'])
-
- @utils.arg(required=True, help="required_no_default.")
- def required_no_default():
- pass
- _, args = required_no_default.__dict__['arguments'][0]
- self.assertEqual("required_no_default. Required.", args['help'])
-
- @utils.arg(default=42, help="not_required_default.")
- def not_required_default():
- pass
- _, args = not_required_default.__dict__['arguments'][0]
- self.assertEqual("not_required_default. Defaults to 42.", args['help'])
-
- def test_merge_nested_dict(self):
- dest = {'key': 'value',
- 'nested': {'key2': 'value2',
- 'key3': 'value3',
- 'nested2': {'key': 'value',
- 'some': 'thing'}}}
- source = {'key': 'modified',
- 'nested': {'key3': 'modified3',
- 'nested2': {'key5': 'value5'}}}
- utils.merge_nested_dict(dest, source, depth=1)
-
- self.assertEqual({'key': 'modified',
- 'nested': {'key2': 'value2',
- 'key3': 'modified3',
- 'nested2': {'key5': 'value5'}}}, dest)
-
- def test_merge_nested_dict_no_depth(self):
- dest = {'key': 'value',
- 'nested': {'key2': 'value2',
- 'key3': 'value3',
- 'nested2': {'key': 'value',
- 'some': 'thing'}}}
- source = {'key': 'modified',
- 'nested': {'key3': 'modified3',
- 'nested2': {'key5': 'value5'}}}
- utils.merge_nested_dict(dest, source)
-
- self.assertEqual({'key': 'modified',
- 'nested': {'key3': 'modified3',
- 'nested2': {'key5': 'value5'}}}, dest)
-
- @mock.patch('prettytable.PrettyTable')
- def test_format_nested_list_of_dict(self, pt_mock):
- actual_rows = []
-
- def mock_add_row(row):
- actual_rows.append(row)
-
- table = mock.Mock()
- table.add_row = mock_add_row
- table.get_string.return_value = "the table"
-
- test_data = [
- {'column_1': 'value_c', 'column_2': 'value_23'},
- {'column_1': 'value_b', 'column_2': 'value_22'},
- {'column_1': 'value_a', 'column_2': 'value_21'}
- ]
- columns = ['column_1', 'column_2']
- pt_mock.return_value = table
-
- rval = utils.format_nested_list_of_dict(test_data, columns)
- self.assertEqual("the table", rval)
- self.assertEqual([['value_a', 'value_21'],
- ['value_b', 'value_22'],
- ['value_c', 'value_23']],
- actual_rows)
diff --git a/ceilometerclient/tests/unit/utils.py b/ceilometerclient/tests/unit/utils.py
deleted file mode 100644
index 57bc276..0000000
--- a/ceilometerclient/tests/unit/utils.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import fixtures
-import testtools
-
-
-class BaseTestCase(testtools.TestCase):
-
- def setUp(self):
- super(BaseTestCase, self).setUp()
- self.useFixture(fixtures.FakeLogger())
diff --git a/ceilometerclient/tests/unit/v2/__init__.py b/ceilometerclient/tests/unit/v2/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/ceilometerclient/tests/unit/v2/__init__.py
+++ /dev/null
diff --git a/ceilometerclient/tests/unit/v2/test_alarms.py b/ceilometerclient/tests/unit/v2/test_alarms.py
deleted file mode 100644
index 20fa118..0000000
--- a/ceilometerclient/tests/unit/v2/test_alarms.py
+++ /dev/null
@@ -1,559 +0,0 @@
-#
-# Copyright 2013 Red Hat, Inc
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import copy
-
-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.v2 import alarms
-
-AN_ALARM = {u'alarm_actions': [u'http://site:8000/alarm'],
- u'ok_actions': [u'http://site:8000/ok'],
- u'description': u'An alarm',
- u'type': u'threshold',
- u'severity': 'low',
- u'threshold_rule': {
- u'meter_name': u'storage.objects',
- u'query': [{u'field': u'key_name',
- u'op': u'eq',
- u'value': u'key_value'}],
- u'evaluation_periods': 2,
- u'period': 240.0,
- u'statistic': u'avg',
- u'threshold': 200.0,
- u'comparison_operator': 'gt'},
- u'time_constraints': [
- {
- u'name': u'cons1',
- u'description': u'desc1',
- u'start': u'0 11 * * *',
- u'duration': 300,
- u'timezone': u''},
- {
- u'name': u'cons2',
- u'description': u'desc2',
- u'start': u'0 23 * * *',
- u'duration': 600,
- u'timezone': ''}],
- u'timestamp': u'2013-05-09T13:41:23.085000',
- u'enabled': True,
- u'alarm_id': u'alarm-id',
- u'state': u'ok',
- u'insufficient_data_actions': [u'http://site:8000/nodata'],
- u'user_id': u'user-id',
- u'project_id': u'project-id',
- u'state_timestamp': u'2013-05-09T13:41:23.085000',
- u'repeat_actions': False,
- u'name': 'SwiftObjectAlarm'}
-CREATE_ALARM = copy.deepcopy(AN_ALARM)
-del CREATE_ALARM['timestamp']
-del CREATE_ALARM['state_timestamp']
-del CREATE_ALARM['alarm_id']
-CREATE_ALARM_WITHOUT_TC = copy.deepcopy(CREATE_ALARM)
-del CREATE_ALARM_WITHOUT_TC['time_constraints']
-DELTA_ALARM = {u'alarm_actions': ['url1', 'url2']}
-DELTA_ALARM_RULE = {u'comparison_operator': u'lt',
- u'threshold': 42.1,
- u'meter_name': u'foobar',
- u'query': [{u'field': u'key_name',
- u'op': u'eq',
- u'value': u'key_value'}]}
-DELTA_ALARM_TC = [{u'name': u'cons1',
- u'duration': 500}]
-DELTA_ALARM['time_constraints'] = DELTA_ALARM_TC
-DELTA_ALARM['user_id'] = u'new-user-id'
-UPDATED_ALARM = copy.deepcopy(AN_ALARM)
-UPDATED_ALARM.update(DELTA_ALARM)
-UPDATED_ALARM['threshold_rule'].update(DELTA_ALARM_RULE)
-DELTA_ALARM['remove_time_constraints'] = 'cons2'
-UPDATED_ALARM['time_constraints'] = [{u'name': u'cons1',
- u'description': u'desc1',
- u'start': u'0 11 * * *',
- u'duration': 500,
- u'timezone': u''}]
-DELTA_ALARM['threshold_rule'] = DELTA_ALARM_RULE
-UPDATE_ALARM = copy.deepcopy(UPDATED_ALARM)
-UPDATE_ALARM['remove_time_constraints'] = 'cons2'
-UPDATE_ALARM['user_id'] = u'new-user-id'
-del UPDATE_ALARM['project_id']
-del UPDATE_ALARM['name']
-del UPDATE_ALARM['alarm_id']
-del UPDATE_ALARM['timestamp']
-del UPDATE_ALARM['state_timestamp']
-
-AN_LEGACY_ALARM = {u'alarm_actions': [u'http://site:8000/alarm'],
- u'ok_actions': [u'http://site:8000/ok'],
- u'description': u'An alarm',
- u'matching_metadata': {u'key_name': u'key_value'},
- u'evaluation_periods': 2,
- u'timestamp': u'2013-05-09T13:41:23.085000',
- u'enabled': True,
- u'meter_name': u'storage.objects',
- u'period': 240.0,
- u'alarm_id': u'alarm-id',
- u'state': u'ok',
- u'severity': u'low',
- u'insufficient_data_actions': [u'http://site:8000/nodata'],
- u'statistic': u'avg',
- u'threshold': 200.0,
- u'user_id': u'user-id',
- u'project_id': u'project-id',
- u'state_timestamp': u'2013-05-09T13:41:23.085000',
- u'comparison_operator': 'gt',
- u'repeat_actions': False,
- u'name': 'SwiftObjectAlarm'}
-CREATE_LEGACY_ALARM = copy.deepcopy(AN_LEGACY_ALARM)
-del CREATE_LEGACY_ALARM['timestamp']
-del CREATE_LEGACY_ALARM['state_timestamp']
-del CREATE_LEGACY_ALARM['alarm_id']
-DELTA_LEGACY_ALARM = {u'alarm_actions': ['url1', 'url2'],
- u'comparison_operator': u'lt',
- u'meter_name': u'foobar',
- u'threshold': 42.1}
-DELTA_LEGACY_ALARM['time_constraints'] = [{u'name': u'cons1',
- u'duration': 500}]
-DELTA_LEGACY_ALARM['user_id'] = u'new-user-id'
-DELTA_LEGACY_ALARM['remove_time_constraints'] = 'cons2'
-UPDATED_LEGACY_ALARM = copy.deepcopy(AN_LEGACY_ALARM)
-UPDATED_LEGACY_ALARM.update(DELTA_LEGACY_ALARM)
-UPDATE_LEGACY_ALARM = copy.deepcopy(UPDATED_LEGACY_ALARM)
-UPDATE_LEGACY_ALARM['user_id'] = u'new-user-id'
-del UPDATE_LEGACY_ALARM['project_id']
-del UPDATE_LEGACY_ALARM['name']
-del UPDATE_LEGACY_ALARM['alarm_id']
-del UPDATE_LEGACY_ALARM['timestamp']
-del UPDATE_LEGACY_ALARM['state_timestamp']
-
-FULL_DETAIL = ('{"alarm_actions": [], '
- '"user_id": "8185aa72421a4fd396d4122cba50e1b5", '
- '"name": "scombo", '
- '"timestamp": "2013-10-03T08:58:33.647912", '
- '"enabled": true, '
- '"state_timestamp": "2013-10-03T08:58:33.647912", '
- '"rule": {"operator": "or", "alarm_ids": '
- '["062cc907-3a9f-4867-ab3b-fa83212b39f7"]}, '
- '"alarm_id": "alarm-id, '
- '"state": "insufficient data", '
- '"insufficient_data_actions": [], '
- '"repeat_actions": false, '
- '"ok_actions": [], '
- '"project_id": "57d04f24d0824b78b1ea9bcecedbda8f", '
- '"type": "combination", '
- '"description": "Combined state of alarms '
- '062cc907-3a9f-4867-ab3b-fa83212b39f7"}')
-ALARM_HISTORY = [{'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f',
- 'user_id': '8185aa72421a4fd396d4122cba50e1b5',
- 'event_id': 'c74a8611-6553-4764-a860-c15a6aabb5d0',
- 'timestamp': '2013-10-03T08:59:28.326000',
- 'detail': '{"state": "alarm"}',
- 'alarm_id': 'alarm-id',
- 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f',
- 'type': 'state transition'},
- {'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f',
- 'user_id': '8185aa72421a4fd396d4122cba50e1b5',
- 'event_id': 'c74a8611-6553-4764-a860-c15a6aabb5d0',
- 'timestamp': '2013-10-03T08:59:28.326000',
- 'detail': '{"description": "combination of one"}',
- 'alarm_id': 'alarm-id',
- 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f',
- 'type': 'rule change'},
- {'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f',
- 'user_id': '8185aa72421a4fd396d4122cba50e1b5',
- 'event_id': '4fd7df9e-190d-4471-8884-dc5a33d5d4bb',
- 'timestamp': '2013-10-03T08:58:33.647000',
- 'detail': FULL_DETAIL,
- 'alarm_id': 'alarm-id',
- 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f',
- 'type': 'creation'}]
-
-fixtures = {
- '/v2/alarms':
- {
- 'GET': (
- {},
- [AN_ALARM],
- ),
- 'POST': (
- {},
- CREATE_ALARM,
- ),
- },
- '/v2/alarms/alarm-id':
- {
- 'GET': (
- {},
- AN_ALARM,
- ),
- 'PUT': (
- {},
- UPDATED_ALARM,
- ),
- 'DELETE': (
- {},
- None,
- ),
- },
- '/v2/alarms/unk-alarm-id':
- {
- 'GET': (
- {},
- None,
- ),
- 'PUT': (
- {},
- None,
- ),
- },
- '/v2/alarms/alarm-id/state':
- {
- 'PUT': (
- {},
- {'alarm': 'alarm'}
- ),
- 'GET': (
- {},
- {'alarm': 'alarm'}
- ),
-
- },
- '/v2/alarms?q.field=project_id&q.field=name&q.op=&q.op='
- '&q.type=&q.type=&q.value=project-id&q.value=SwiftObjectAlarm':
- {
- 'GET': (
- {},
- [AN_ALARM],
- ),
- },
- '/v2/alarms/victim-id':
- {
- 'DELETE': (
- {},
- None,
- ),
- },
- '/v2/alarms/alarm-id/history':
- {
- 'GET': (
- {},
- ALARM_HISTORY,
- ),
- },
- '/v2/alarms/alarm-id/history?q.field=timestamp&q.op=&q.type=&q.value=NOW':
- {
- 'GET': (
- {},
- ALARM_HISTORY,
- ),
- },
-}
-
-
-class AlarmManagerTest(testtools.TestCase):
-
- def setUp(self):
- super(AlarmManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
- self.api = client.BaseClient(self.http_client)
- self.mgr = alarms.AlarmManager(self.api)
-
- def test_list_all(self):
- alarms = list(self.mgr.list())
- expect = [
- 'GET', '/v2/alarms'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(alarms))
- self.assertEqual('alarm-id', alarms[0].alarm_id)
-
- def test_list_with_query(self):
- alarms = list(self.mgr.list(q=[{"field": "project_id",
- "value": "project-id"},
- {"field": "name",
- "value": "SwiftObjectAlarm"}]))
- expect = [
- 'GET',
- '/v2/alarms?q.field=project_id&q.field=name&q.op=&q.op='
- '&q.type=&q.type=&q.value=project-id&q.value=SwiftObjectAlarm',
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(alarms))
- self.assertEqual('alarm-id', alarms[0].alarm_id)
-
- def test_get(self):
- alarm = self.mgr.get(alarm_id='alarm-id')
- expect = [
- 'GET', '/v2/alarms/alarm-id'
- ]
- self.http_client.assert_called(*expect)
- self.assertIsNotNone(alarm)
- self.assertEqual('alarm-id', alarm.alarm_id)
- self.assertEqual(alarm.rule, alarm.threshold_rule)
-
- def test_create(self):
- alarm = self.mgr.create(**CREATE_ALARM)
- expect = [
- 'POST', '/v2/alarms'
- ]
- self.http_client.assert_called(*expect, body=CREATE_ALARM)
- self.assertIsNotNone(alarm)
-
- def test_update(self):
- alarm = self.mgr.update(alarm_id='alarm-id', **UPDATE_ALARM)
- expect_get = [
- 'GET', '/v2/alarms/alarm-id'
- ]
- expect_put = [
- 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM
- ]
- self.http_client.assert_called(*expect_get, pos=0)
- self.http_client.assert_called(*expect_put, pos=1)
- self.assertIsNotNone(alarm)
- self.assertEqual('alarm-id', alarm.alarm_id)
- for (key, value) in six.iteritems(UPDATED_ALARM):
- self.assertEqual(getattr(alarm, key), value)
-
- def test_update_delta(self):
- alarm = self.mgr.update(alarm_id='alarm-id', **DELTA_ALARM)
- expect_get = [
- 'GET', '/v2/alarms/alarm-id'
- ]
- expect_put = [
- 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM
- ]
- self.http_client.assert_called(*expect_get, pos=0)
- self.http_client.assert_called(*expect_put, pos=1)
- self.assertIsNotNone(alarm)
- self.assertEqual('alarm-id', alarm.alarm_id)
- for (key, value) in six.iteritems(UPDATED_ALARM):
- self.assertEqual(getattr(alarm, key), value)
-
- def test_set_state(self):
- state = self.mgr.set_state(alarm_id='alarm-id', state='alarm')
- expect = [
- 'PUT', '/v2/alarms/alarm-id/state'
- ]
- self.http_client.assert_called(*expect, body='alarm')
- self.assertEqual({'alarm': 'alarm'}, state)
-
- def test_get_state(self):
- state = self.mgr.get_state(alarm_id='alarm-id')
- expect = [
- 'GET', '/v2/alarms/alarm-id/state'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual({'alarm': 'alarm'}, state)
-
- def test_delete(self):
- deleted = self.mgr.delete(alarm_id='victim-id')
- expect = [
- 'DELETE', '/v2/alarms/victim-id'
- ]
- self.http_client.assert_called(*expect)
- self.assertIsNone(deleted)
-
- def test_get_from_alarm_class(self):
- alarm = self.mgr.get(alarm_id='alarm-id')
- self.assertIsNotNone(alarm)
- alarm.get()
- expect = [
- 'GET', '/v2/alarms/alarm-id'
- ]
- self.http_client.assert_called(*expect, pos=0)
- self.http_client.assert_called(*expect, pos=1)
- self.assertEqual('alarm-id', alarm.alarm_id)
- self.assertEqual(alarm.threshold_rule, alarm.rule)
-
- def test_get_state_from_alarm_class(self):
- alarm = self.mgr.get(alarm_id='alarm-id')
- self.assertIsNotNone(alarm)
- state = alarm.get_state()
- expect_get_1 = [
- 'GET', '/v2/alarms/alarm-id'
- ]
- expect_get_2 = [
- 'GET', '/v2/alarms/alarm-id/state'
- ]
- self.http_client.assert_called(*expect_get_1, pos=0)
- self.http_client.assert_called(*expect_get_2, pos=1)
- self.assertEqual('alarm', state)
-
- def test_update_missing(self):
- alarm = None
- try:
- alarm = self.mgr.update(alarm_id='unk-alarm-id', **UPDATE_ALARM)
- except exc.CommandError:
- pass
- self.assertIsNone(alarm)
-
- def test_delete_from_alarm_class(self):
- alarm = self.mgr.get(alarm_id='alarm-id')
- self.assertIsNotNone(alarm)
- deleted = alarm.delete()
- expect_get = [
- 'GET', '/v2/alarms/alarm-id'
- ]
- expect_delete = [
- 'DELETE', '/v2/alarms/alarm-id'
- ]
- self.http_client.assert_called(*expect_get, pos=0)
- self.http_client.assert_called(*expect_delete, pos=1)
- self.assertIsNone(deleted)
-
- def _do_test_get_history(self, q, url):
- history = self.mgr.get_history(q=q, alarm_id='alarm-id')
- expect = ['GET', url]
- self.http_client.assert_called(*expect)
- for i in xrange(len(history)):
- change = history[i]
- self.assertIsInstance(change, alarms.AlarmChange)
- for k, v in six.iteritems(ALARM_HISTORY[i]):
- self.assertEqual(getattr(change, k), v)
-
- def test_get_all_history(self):
- url = '/v2/alarms/alarm-id/history'
- self._do_test_get_history(None, url)
-
- def test_get_constrained_history(self):
- q = [dict(field='timestamp', value='NOW')]
- url = ('/v2/alarms/alarm-id/history?q.field=timestamp'
- '&q.op=&q.type=&q.value=NOW')
- self._do_test_get_history(q, url)
-
-
-class AlarmLegacyManagerTest(testtools.TestCase):
-
- def setUp(self):
- super(AlarmLegacyManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
- self.api = client.BaseClient(self.http_client)
- self.mgr = alarms.AlarmManager(self.api)
-
- def test_create(self):
- alarm = self.mgr.create(**CREATE_LEGACY_ALARM)
- expect = [
- 'POST', '/v2/alarms', CREATE_ALARM_WITHOUT_TC,
- ]
- self.http_client.assert_called(*expect)
- self.assertIsNotNone(alarm)
-
- def test_create_counter_name(self):
- create = {}
- create.update(CREATE_LEGACY_ALARM)
- create['counter_name'] = CREATE_LEGACY_ALARM['meter_name']
- del create['meter_name']
- alarm = self.mgr.create(**create)
- expect = [
- 'POST', '/v2/alarms', CREATE_ALARM_WITHOUT_TC,
- ]
- self.http_client.assert_called(*expect)
- self.assertIsNotNone(alarm)
-
- def test_update(self):
- alarm = self.mgr.update(alarm_id='alarm-id', **DELTA_LEGACY_ALARM)
- expect_put = [
- 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM
- ]
- self.http_client.assert_called(*expect_put)
- self.assertIsNotNone(alarm)
- self.assertEqual('alarm-id', alarm.alarm_id)
- for (key, value) in six.iteritems(UPDATED_ALARM):
- self.assertEqual(getattr(alarm, key), value)
-
- def test_update_counter_name(self):
- updated = {}
- updated.update(UPDATE_LEGACY_ALARM)
- updated['counter_name'] = UPDATED_LEGACY_ALARM['meter_name']
- del updated['meter_name']
- alarm = self.mgr.update(alarm_id='alarm-id', **updated)
- expect_put = [
- 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM
- ]
- self.http_client.assert_called(*expect_put)
- self.assertIsNotNone(alarm)
- self.assertEqual('alarm-id', alarm.alarm_id)
- for (key, value) in six.iteritems(UPDATED_ALARM):
- self.assertEqual(getattr(alarm, key), value)
-
-
-class AlarmTimeConstraintTest(testtools.TestCase):
-
- def setUp(self):
- super(AlarmTimeConstraintTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
- self.api = client.BaseClient(self.http_client)
- self.mgr = alarms.AlarmManager(self.api)
-
- def test_add_new(self):
- new_constraint = dict(name='cons3',
- start='0 0 * * *',
- duration=500)
- kwargs = dict(time_constraints=[new_constraint])
- self.mgr.update(alarm_id='alarm-id', **kwargs)
- body = copy.deepcopy(AN_ALARM)
- body[u'time_constraints'] = \
- AN_ALARM[u'time_constraints'] + [new_constraint]
- expect = [
- 'PUT', '/v2/alarms/alarm-id', body
- ]
- self.http_client.assert_called(*expect)
-
- def test_update_existing(self):
- updated_constraint = dict(name='cons2',
- duration=500)
- kwargs = dict(time_constraints=[updated_constraint])
- self.mgr.update(alarm_id='alarm-id', **kwargs)
- body = copy.deepcopy(AN_ALARM)
- body[u'time_constraints'][1] = dict(name='cons2',
- description='desc2',
- start='0 23 * * *',
- duration=500,
- timezone='')
-
- expect = [
- 'PUT', '/v2/alarms/alarm-id', body
- ]
- self.http_client.assert_called(*expect)
-
- def test_update_time_constraint_no_name(self):
- updated_constraint = {
- 'start': '0 23 * * *',
- 'duration': 500
- }
- kwargs = dict(time_constraints=[updated_constraint])
- self.mgr.update(alarm_id='alarm-id', **kwargs)
- body = copy.deepcopy(AN_ALARM)
- body[u'time_constraints'].append({
- 'start': '0 23 * * *',
- 'duration': 500,
- })
- expect = [
- 'PUT', '/v2/alarms/alarm-id', body
- ]
- self.http_client.assert_called(*expect)
-
- def test_remove(self):
- kwargs = dict(remove_time_constraints=['cons2'])
- self.mgr.update(alarm_id='alarm-id', **kwargs)
- body = copy.deepcopy(AN_ALARM)
- body[u'time_constraints'] = AN_ALARM[u'time_constraints'][:1]
- expect = [
- 'PUT', '/v2/alarms/alarm-id', body
- ]
- self.http_client.assert_called(*expect)
diff --git a/ceilometerclient/tests/unit/v2/test_capabilities.py b/ceilometerclient/tests/unit/v2/test_capabilities.py
deleted file mode 100644
index 884a34f..0000000
--- a/ceilometerclient/tests/unit/v2/test_capabilities.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright 2014 Huawei Technologies Co., Ltd.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import testtools
-
-from ceilometerclient.apiclient import client
-from ceilometerclient.apiclient import fake_client
-from ceilometerclient.v2 import capabilities
-
-
-CAPABILITIES = {
- "alarm_storage": {
- "storage:production_ready": True
- },
- "api": {
- "alarms:query:complex": True,
- "alarms:query:simple": True
- },
- "event_storage": {
- "storage:production_ready": True
- },
- "storage": {
- "storage:production_ready": True
- },
-}
-
-FIXTURES = {
- '/v2/capabilities': {
- 'GET': (
- {},
- CAPABILITIES
- ),
- },
-}
-
-
-class CapabilitiesManagerTest(testtools.TestCase):
- def setUp(self):
- super(CapabilitiesManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(fixtures=FIXTURES)
- self.api = client.BaseClient(self.http_client)
- self.mgr = capabilities.CapabilitiesManager(self.api)
-
- def test_capabilities_get(self):
- capabilities = self.mgr.get()
- self.http_client.assert_called('GET', '/v2/capabilities')
- self.assertTrue(capabilities.api['alarms:query:complex'])
diff --git a/ceilometerclient/tests/unit/v2/test_event_types.py b/ceilometerclient/tests/unit/v2/test_event_types.py
deleted file mode 100644
index 3bccbae..0000000
--- a/ceilometerclient/tests/unit/v2/test_event_types.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright 2014 Hewlett-Packard Development Company, L.P.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-from ceilometerclient.apiclient import client
-from ceilometerclient.apiclient import fake_client
-from ceilometerclient.tests.unit import utils
-import ceilometerclient.v2.event_types
-
-
-fixtures = {
- '/v2/event_types': {
- 'GET': (
- {},
- ['Foo', 'Bar', 'Sna', 'Fu']
- ),
- }
-}
-
-
-class EventTypesManagerTest(utils.BaseTestCase):
-
- def setUp(self):
- super(EventTypesManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
- self.api = client.BaseClient(self.http_client)
- self.mgr = ceilometerclient.v2.event_types.EventTypeManager(self.api)
-
- def test_list(self):
- event_types = list(self.mgr.list())
- expect = [
- 'GET', '/v2/event_types'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(4, len(event_types))
- self.assertEqual("Foo", event_types[0].event_type)
- self.assertEqual("Bar", event_types[1].event_type)
- self.assertEqual("Sna", event_types[2].event_type)
- self.assertEqual("Fu", event_types[3].event_type)
diff --git a/ceilometerclient/tests/unit/v2/test_events.py b/ceilometerclient/tests/unit/v2/test_events.py
deleted file mode 100644
index 9cc94fd..0000000
--- a/ceilometerclient/tests/unit/v2/test_events.py
+++ /dev/null
@@ -1,198 +0,0 @@
-# Copyright 2014 Hewlett-Packard Development Company, L.P.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-from ceilometerclient.apiclient import client
-from ceilometerclient.apiclient import fake_client
-from ceilometerclient.tests.unit import utils
-import ceilometerclient.v2.events
-
-
-fixtures = {
- '/v2/events': {
- 'GET': (
- {},
- [
- {
- 'message_id': '1',
- 'event_type': 'Foo',
- 'generated': '1970-01-01T00:00:00',
- 'traits': {'trait_A': 'abc'},
- },
- {
- 'message_id': '2',
- 'event_type': 'Foo',
- 'generated': '1970-01-01T00:00:00',
- 'traits': {'trait_A': 'def'},
- },
- {
- 'message_id': '3',
- 'event_type': 'Bar',
- 'generated': '1970-01-01T00:00:00',
- 'traits': {'trait_B': 'bartrait'},
- },
- ]
- ),
- },
- '/v2/events?q.field=hostname&q.op=&q.type=string&q.value=localhost':
- {
- 'GET': (
- {},
- [
- {
- 'message_id': '1',
- 'event_type': 'Foo',
- 'generated': '1970-01-01T00:00:00',
- 'traits': {'trait_A': 'abc',
- 'hostname': 'localhost'},
- },
- {
- 'message_id': '2',
- 'event_type': 'Foo',
- 'generated': '1970-01-01T00:00:00',
- 'traits': {'trait_A': 'def',
- 'hostname': 'localhost'},
- }
- ]
- ),
- },
- '/v2/events?q.field=hostname&q.op=&q.type=&q.value=foreignhost':
- {
- 'GET': (
- {},
- [
- {
- 'message_id': '1',
- 'event_type': 'Foo',
- 'generated': '1970-01-01T00:00:00',
- 'traits': {'trait_A': 'abc',
- 'hostname': 'foreignhost'},
- },
- {
- 'message_id': '2',
- 'event_type': 'Foo',
- 'generated': '1970-01-01T00:00:00',
- 'traits': {'trait_A': 'def',
- 'hostname': 'foreignhost'},
- }
- ]
- ),
- },
- '/v2/events?q.field=hostname&q.field=num_cpus&q.op=&q.op='
- '&q.type=&q.type=integer&q.value=localhost&q.value=5':
- {
- 'GET': (
- {},
- [
- {
- 'message_id': '1',
- 'event_type': 'Bar',
- 'generated': '1970-01-01T00:00:00',
- 'traits': {'trait_A': 'abc',
- 'hostname': 'localhost',
- 'num_cpus': '5'},
- },
- ]
- ),
- },
-
- '/v2/events/2':
- {
- 'GET': (
- {},
- {
- 'message_id': '2',
- 'event_type': 'Foo',
- 'generated': '1970-01-01T00:00:00',
- 'traits': {'trait_A': 'def',
- 'intTrait': '42'},
- }
- ),
- },
-}
-
-
-class EventManagerTest(utils.BaseTestCase):
-
- def setUp(self):
- super(EventManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
- self.api = client.BaseClient(self.http_client)
- self.mgr = ceilometerclient.v2.events.EventManager(self.api)
-
- def test_list_all(self):
- events = list(self.mgr.list())
- expect = [
- 'GET', '/v2/events'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(3, len(events))
- self.assertEqual('Foo', events[0].event_type)
- self.assertEqual('Foo', events[1].event_type)
- self.assertEqual('Bar', events[2].event_type)
-
- def test_list_one(self):
- event = self.mgr.get(2)
- expect = [
- 'GET', '/v2/events/2'
- ]
- self.http_client.assert_called(*expect)
- self.assertIsNotNone(event)
- self.assertEqual('Foo', event.event_type)
-
- def test_list_with_query(self):
- events = list(self.mgr.list(q=[{"field": "hostname",
- "value": "localhost",
- "type": "string"}]))
- expect = [
- 'GET', '/v2/events?q.field=hostname&q.op=&q.type=string'
- '&q.value=localhost'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(2, len(events))
- self.assertEqual('Foo', events[0].event_type)
-
- def test_list_with_query_no_type(self):
- events = list(self.mgr.list(q=[{"field": "hostname",
- "value": "foreignhost"}]))
- expect = [
- 'GET', '/v2/events?q.field=hostname&q.op='
- '&q.type=&q.value=foreignhost'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(2, len(events))
- self.assertEqual('Foo', events[0].event_type)
-
- def test_list_with_multiple_filters(self):
- events = list(self.mgr.list(q=[{"field": "hostname",
- "value": "localhost"},
- {"field": "num_cpus",
- "value": "5",
- "type": "integer"}]))
-
- expect = [
- 'GET', '/v2/events?q.field=hostname&q.field=num_cpus&q.op=&q.op='
- '&q.type=&q.type=integer&q.value=localhost&q.value=5'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(events))
-
- def test_get_from_event_class(self):
- event = self.mgr.get(2)
- self.assertIsNotNone(event)
- event.get()
- expect = [
- 'GET', '/v2/events/2'
- ]
- self.http_client.assert_called(*expect, pos=0)
- self.http_client.assert_called(*expect, pos=1)
- self.assertEqual('Foo', event.event_type)
diff --git a/ceilometerclient/tests/unit/v2/test_options.py b/ceilometerclient/tests/unit/v2/test_options.py
deleted file mode 100644
index 8de17d4..0000000
--- a/ceilometerclient/tests/unit/v2/test_options.py
+++ /dev/null
@@ -1,253 +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.
-from ceilometerclient.tests.unit import utils
-from ceilometerclient.v2 import options
-
-
-class BuildUrlTest(utils.BaseTestCase):
-
- def test_one(self):
- url = options.build_url('/', [{'field': 'this',
- 'op': 'gt',
- 'value': 43}])
- self.assertEqual(url, '/?q.field=this&q.op=gt&q.type=&q.value=43')
-
- def test_two(self):
- url = options.build_url('/', [{'field': 'this',
- 'op': 'gt',
- 'value': 43},
- {'field': 'that',
- 'op': 'lt',
- 'value': 88}])
- ops = 'q.op=gt&q.op=lt'
- vals = 'q.value=43&q.value=88'
- types = 'q.type=&q.type='
- fields = 'q.field=this&q.field=that'
- self.assertEqual(url, '/?%s&%s&%s&%s' % (fields, ops, types, vals))
-
- def test_default_op(self):
- url = options.build_url('/', [{'field': 'this',
- 'value': 43}])
- self.assertEqual(url, '/?q.field=this&q.op=&q.type=&q.value=43')
-
- def test_one_param(self):
- url = options.build_url('/', None, ['period=60'])
- self.assertEqual(url, '/?period=60')
-
- def test_two_params(self):
- url = options.build_url('/', None, ['period=60',
- 'others=value'])
- self.assertEqual(url, '/?period=60&others=value')
-
- def test_with_data_type(self):
- url = options.build_url('/', [{'field': 'f1',
- 'value': '10',
- 'type': 'integer'}])
-
- self.assertEqual('/?q.field=f1&q.op=&q.type=integer&q.value=10', url)
-
-
-class CliTest(utils.BaseTestCase):
-
- def test_one(self):
- ar = options.cli_to_array('this<=34')
- self.assertEqual(ar, [{'field': 'this', 'op': 'le',
- 'value': '34', 'type': ''}])
-
- def test_two(self):
- ar = options.cli_to_array('this<=34;that!=foo')
- self.assertEqual(ar, [{'field': 'this', 'op': 'le',
- 'value': '34', 'type': ''},
- {'field': 'that', 'op': 'ne',
- 'value': 'foo', 'type': ''}])
-
- def test_negative(self):
- ar = options.cli_to_array('this>=-783')
- self.assertEqual(ar, [{'field': 'this', 'op': 'ge',
- 'value': '-783', 'type': ''}])
-
- def test_float(self):
- ar = options.cli_to_array('this<=283.347')
- self.assertEqual(ar, [{'field': 'this',
- 'op': 'le', 'value': '283.347',
- 'type': ''}])
-
- def test_comma(self):
- ar = options.cli_to_array('this=2.4,fooo=doof')
- self.assertEqual([{'field': 'this',
- 'op': 'eq',
- 'value': '2.4,fooo=doof',
- 'type': ''}],
- ar)
-
- def test_special_character(self):
- ar = options.cli_to_array('key~123=value!123')
- self.assertEqual([{'field': 'key~123',
- 'op': 'eq',
- 'value': 'value!123',
- 'type': ''}],
- ar)
-
- def _do_test_typed_float_op(self, op, op_str):
- ar = options.cli_to_array('that%sfloat::283.347' % op)
- self.assertEqual([{'field': 'that',
- 'type': 'float',
- 'value': '283.347',
- 'op': op_str}],
- ar)
-
- def test_typed_float_eq(self):
- self._do_test_typed_float_op('<', 'lt')
-
- def test_typed_float_le(self):
- self._do_test_typed_float_op('<=', 'le')
-
- def test_typed_string_whitespace(self):
- ar = options.cli_to_array('state=string::insufficient data')
- self.assertEqual([{'field': 'state',
- 'op': 'eq',
- 'type': 'string',
- 'value': 'insufficient data'}],
- ar)
-
- def test_typed_string_whitespace_complex(self):
- ar = options.cli_to_array(
- 'that>=float::99.9999;state=string::insufficient data'
- )
- self.assertEqual([{'field': 'that',
- 'op': 'ge',
- 'type': 'float',
- 'value': '99.9999'},
- {'field': 'state',
- 'op': 'eq',
- 'type': 'string',
- 'value': 'insufficient data'}],
- ar)
-
- def test_invalid_operator(self):
- self.assertRaises(ValueError, options.cli_to_array,
- 'this=2.4;fooo-doof')
-
- def test_with_dot(self):
- ar = options.cli_to_array('metadata.this<=34')
- self.assertEqual(ar, [{'field': 'metadata.this',
- 'op': 'le', 'value': '34',
- 'type': ''}])
-
- def test_single_char_field_or_value(self):
- ar = options.cli_to_array('m<=34;large.thing>s;x!=y')
- self.assertEqual([{'field': 'm',
- 'op': 'le',
- 'value': '34',
- 'type': ''},
- {'field': 'large.thing',
- 'op': 'gt',
- 'value': 's',
- 'type': ''},
- {'field': 'x',
- 'op': 'ne',
- 'value': 'y',
- 'type': ''}],
- ar)
-
- def test_without_data_type(self):
- ar = options.cli_to_array('hostname=localhost')
- self.assertEqual(ar, [{'field': 'hostname',
- 'op': 'eq',
- 'value': 'localhost',
- 'type': ''}])
-
- def test_with_string_data_type(self):
- ar = options.cli_to_array('hostname=string::localhost')
- self.assertEqual(ar, [{'field': 'hostname',
- 'op': 'eq',
- 'type': 'string',
- 'value': 'localhost'}])
-
- def test_with_int_data_type(self):
- ar = options.cli_to_array('port=integer::1234')
- self.assertEqual(ar, [{'field': 'port',
- 'op': 'eq',
- 'type': 'integer',
- 'value': '1234'}])
-
- def test_with_bool_data_type(self):
- ar = options.cli_to_array('port=boolean::true')
- self.assertEqual(ar, [{'field': 'port',
- 'op': 'eq',
- 'type': 'boolean',
- 'value': 'true'}])
-
- def test_with_float_data_type(self):
- ar = options.cli_to_array('average=float::1234.5678')
- self.assertEqual(ar, [{'field': 'average',
- 'op': 'eq',
- 'type': 'float',
- 'value': '1234.5678'}])
-
- def test_with_datetime_data_type(self):
- ar = options.cli_to_array('timestamp=datetime::sometimestamp')
- self.assertEqual(ar, [{'field': 'timestamp',
- 'op': 'eq',
- 'type': 'datetime',
- 'value': 'sometimestamp'}])
-
- def test_with_incorrect_type(self):
- ar = options.cli_to_array('timestamp=invalid::sometimestamp')
- self.assertEqual(ar, [{'field': 'timestamp',
- 'op': 'eq',
- 'type': '',
- 'value': 'invalid::sometimestamp'}])
-
- def test_with_single_colon(self):
- ar = options.cli_to_array('timestamp=datetime:sometimestamp')
- self.assertEqual(ar, [{'field': 'timestamp',
- 'op': 'eq',
- 'type': '',
- 'value': 'datetime:sometimestamp'}])
-
- def test_missing_key(self):
- self.assertRaises(ValueError, options.cli_to_array,
- 'average=float::1234.0;>=string::hello')
-
- def test_missing_value(self):
- self.assertRaises(ValueError, options.cli_to_array,
- 'average=float::1234.0;house>=')
-
- def test_timestamp_value(self):
- ar = options.cli_to_array(
- 'project=cow;timestamp>=datetime::2014-03-11T16:02:58'
- )
- self.assertEqual([{'field': 'project',
- 'op': 'eq',
- 'type': '',
- 'value': 'cow'},
- {'field': 'timestamp',
- 'op': 'ge',
- 'type': 'datetime',
- 'value': '2014-03-11T16:02:58'}],
- ar)
-
- def test_with_whitespace(self):
- ar = options.cli_to_array('start_timestamp= 2015-01-01T00:00:00;'
- ' end_timestamp =2015-06-20T14:01:59 ')
-
- self.assertEqual([{'field': 'start_timestamp',
- 'op': 'eq',
- 'type': '',
- 'value': '2015-01-01T00:00:00'},
- {'field': 'end_timestamp',
- 'op': 'eq',
- 'type': '',
- 'value': '2015-06-20T14:01:59'}],
- ar)
diff --git a/ceilometerclient/tests/unit/v2/test_query_alarm_history.py b/ceilometerclient/tests/unit/v2/test_query_alarm_history.py
deleted file mode 100644
index b37eb5d..0000000
--- a/ceilometerclient/tests/unit/v2/test_query_alarm_history.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright Ericsson AB 2014. 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.
-
-from ceilometerclient.apiclient import client
-from ceilometerclient.apiclient import fake_client
-from ceilometerclient.tests.unit import utils
-from ceilometerclient.v2 import query
-
-
-ALARMCHANGE = {"alarm_id": "e8ff32f772a44a478182c3fe1f7cad6a",
- "event_id": "c74a8611-6553-4764-a860-c15a6aabb5d0",
- "detail": "{\"threshold\": 42.0, \"evaluation_periods\": 4}",
- "on_behalf_of": "92159030020611e3b26dde429e99ee8c",
- "project_id": "b6f16144010811e387e4de429e99ee8c",
- "timestamp": "2014-03-11T16:02:58.376261",
- "type": "rule change",
- "user_id": "3e5d11fda79448ac99ccefb20be187ca"
- }
-
-QUERY = {"filter": {"and": [{">": {"timestamp": "2014-03-11T16:02:58"}},
- {"=": {"type": "rule change"}}]},
- "orderby": [{"timestamp": "desc"}],
- "limit": 10}
-
-base_url = '/v2/query/alarms/history'
-fixtures = {
- base_url:
- {
- 'POST': (
- {},
- [ALARMCHANGE],
- ),
- },
-}
-
-
-class QueryAlarmsManagerTest(utils.BaseTestCase):
-
- def setUp(self):
- super(QueryAlarmsManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
- self.api = client.BaseClient(self.http_client)
- self.mgr = query.QueryAlarmHistoryManager(self.api)
-
- def test_query(self):
- alarm_history = self.mgr.query(**QUERY)
- expect = [
-
- 'POST', '/v2/query/alarms/history', QUERY,
-
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(alarm_history))
diff --git a/ceilometerclient/tests/unit/v2/test_query_alarms.py b/ceilometerclient/tests/unit/v2/test_query_alarms.py
deleted file mode 100644
index 495bbd4..0000000
--- a/ceilometerclient/tests/unit/v2/test_query_alarms.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright Ericsson AB 2014. 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.
-
-from ceilometerclient.apiclient import client
-from ceilometerclient.apiclient import fake_client
-from ceilometerclient.tests.unit import utils
-from ceilometerclient.v2 import query
-
-
-ALARM = {"alarm_actions": ["http://site:8000/alarm"],
- "alarm_id": None,
- "combination_rule": {
- "alarm_ids": [
- "739e99cb-c2ec-4718-b900-332502355f38",
- "153462d0-a9b8-4b5b-8175-9e4b05e9b856"],
- "operator": "or"},
- "description": "An alarm",
- "enabled": True,
- "insufficient_data_actions": ["http://site:8000/nodata"],
- "name": "SwiftObjectAlarm",
- "ok_actions": ["http://site:8000/ok"],
- "project_id": "c96c887c216949acbdfbd8b494863567",
- "repeat_actions": False,
- "state": "ok",
- "state_timestamp": "2014-02-20T10:37:15.589860",
- "threshold_rule": None,
- "timestamp": "2014-02-20T10:37:15.589856",
- "type": "combination",
- "user_id": "c96c887c216949acbdfbd8b494863567"}
-
-QUERY = {"filter": {"and": [{"!=": {"state": "ok"}},
- {"=": {"type": "combination"}}]},
- "orderby": [{"state_timestamp": "desc"}],
- "limit": 10}
-
-base_url = '/v2/query/alarms'
-fixtures = {
- base_url:
- {
- 'POST': (
- {},
- [ALARM],
- ),
- },
-}
-
-
-class QueryAlarmsManagerTest(utils.BaseTestCase):
-
- def setUp(self):
- super(QueryAlarmsManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
- self.api = client.BaseClient(self.http_client)
- self.mgr = query.QueryAlarmsManager(self.api)
-
- def test_query(self):
- alarms = self.mgr.query(**QUERY)
- expect = [
- 'POST', '/v2/query/alarms', QUERY,
- ]
-
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(alarms))
diff --git a/ceilometerclient/tests/unit/v2/test_query_samples.py b/ceilometerclient/tests/unit/v2/test_query_samples.py
deleted file mode 100644
index 217c35a..0000000
--- a/ceilometerclient/tests/unit/v2/test_query_samples.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright Ericsson AB 2014. 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.
-
-from ceilometerclient.apiclient import client
-from ceilometerclient.apiclient import fake_client
-from ceilometerclient.tests.unit import utils
-from ceilometerclient.v2 import query
-
-
-SAMPLE = {u'id': u'b55d1526-9929-11e3-a3f6-02163e5df1e6',
- u'metadata': {
- u'name1': u'value1',
- u'name2': u'value2'},
- u'meter': 'instance',
- u'project_id': u'35b17138-b364-4e6a-a131-8f3099c5be68',
- u'resource_id': u'bd9431c1-8d69-4ad3-803a-8d4a6b89fd36',
- u'source': u'openstack',
- u'timestamp': u'2014-02-19T05:50:16.673604',
- u'type': u'gauge',
- u'unit': u'instance',
- u'volume': 1,
- u'user_id': 'efd87807-12d2-4b38-9c70-5f5c2ac427ff'}
-
-QUERY = {"filter": {"and": [{"=": {"source": "openstack"}},
- {">": {"timestamp": "2014-02-19T05:50:16"}}]},
- "orderby": [{"timestamp": "desc"}, {"volume": "asc"}],
- "limit": 10}
-
-base_url = '/v2/query/samples'
-fixtures = {
- base_url:
- {
- 'POST': (
- {},
- [SAMPLE],
- ),
- },
-}
-
-
-class QuerySamplesManagerTest(utils.BaseTestCase):
-
- def setUp(self):
- super(QuerySamplesManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
- self.api = client.BaseClient(self.http_client)
- self.mgr = query.QuerySamplesManager(self.api)
-
- def test_query(self):
- samples = self.mgr.query(**QUERY)
- expect = [
-
- 'POST', '/v2/query/samples', QUERY,
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(samples))
diff --git a/ceilometerclient/tests/unit/v2/test_resources.py b/ceilometerclient/tests/unit/v2/test_resources.py
deleted file mode 100644
index ca88aa5..0000000
--- a/ceilometerclient/tests/unit/v2/test_resources.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# Copyright 2012 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.
-from ceilometerclient.apiclient import client
-from ceilometerclient.apiclient import fake_client
-from ceilometerclient.tests.unit import utils
-import ceilometerclient.v2.resources
-
-
-fixtures = {
- '/v2/resources?meter_links=0': {
- 'GET': (
- {},
- [
- {
- 'resource_id': 'a',
- 'project_id': 'project_bla',
- 'user_id': 'freddy',
- 'metadata': {'zxc_id': 'bla'},
- },
- {
- 'resource_id': 'b',
- 'project_id': 'dig_the_ditch',
- 'user_id': 'joey',
- 'metadata': {'zxc_id': 'foo'},
- },
- ]
- ),
- },
- '/v2/resources?q.field=resource_id&q.op=&q.type=&q.value=a&meter_links=0':
- {
- 'GET': (
- {},
- [
- {
- 'resource_id': 'a',
- 'project_id': 'project_bla',
- 'user_id': 'freddy',
- 'metadata': {'zxc_id': 'bla'},
- },
- ]
- ),
- },
- '/v2/resources?meter_links=1': {
- 'GET': (
- {},
- [
- {
- 'resource_id': 'c',
- 'project_id': 'project_blah',
- 'user_id': 'fred',
- 'metadata': {'zxc_id': 'blah'},
- },
- {
- 'resource_id': 'd',
- 'project_id': 'bury_the_ditch',
- 'user_id': 'jack',
- 'metadata': {'zxc_id': 'foobar'},
- },
- ]
- ),
- },
- '/v2/resources/a':
- {
- 'GET': (
- {},
- {
- 'resource_id': 'a',
- 'project_id': 'project_bla',
- 'user_id': 'freddy',
- 'metadata': {'zxc_id': 'bla'},
- },
- ),
- },
-}
-
-
-class ResourceManagerTest(utils.BaseTestCase):
-
- def setUp(self):
- super(ResourceManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
- self.api = client.BaseClient(self.http_client)
- self.mgr = ceilometerclient.v2.resources.ResourceManager(self.api)
-
- def test_list_all(self):
- resources = list(self.mgr.list())
- expect = [
- 'GET', '/v2/resources?meter_links=0'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(2, len(resources))
- self.assertEqual('a', resources[0].resource_id)
- self.assertEqual('b', resources[1].resource_id)
-
- def test_list_all_with_links_enabled(self):
- resources = list(self.mgr.list(links=True))
- expect = [
- 'GET', '/v2/resources?meter_links=1'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(2, len(resources))
- self.assertEqual('c', resources[0].resource_id)
- self.assertEqual('d', resources[1].resource_id)
-
- def test_list_one(self):
- resource = self.mgr.get(resource_id='a')
- expect = [
- 'GET', '/v2/resources/a'
- ]
- self.http_client.assert_called(*expect)
- self.assertIsNotNone(resource)
- self.assertEqual('a', resource.resource_id)
-
- def test_list_by_query(self):
- resources = list(self.mgr.list(q=[{"field": "resource_id",
- "value": "a"},
- ]))
- expect = [
- 'GET', '/v2/resources?q.field=resource_id&q.op='
- '&q.type=&q.value=a&meter_links=0'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(resources))
- self.assertEqual('a', resources[0].resource_id)
-
- def test_get_from_resource_class(self):
- resource = self.mgr.get(resource_id='a')
- self.assertIsNotNone(resource)
- resource.get()
- expect = [
- 'GET', '/v2/resources/a'
- ]
- self.http_client.assert_called(*expect, pos=0)
- self.http_client.assert_called(*expect, pos=1)
- self.assertEqual('a', resource.resource_id)
diff --git a/ceilometerclient/tests/unit/v2/test_samples.py b/ceilometerclient/tests/unit/v2/test_samples.py
deleted file mode 100644
index 864ac36..0000000
--- a/ceilometerclient/tests/unit/v2/test_samples.py
+++ /dev/null
@@ -1,247 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import copy
-
-from ceilometerclient.apiclient import client
-from ceilometerclient.apiclient import fake_client
-from ceilometerclient.tests.unit import utils
-import ceilometerclient.v2.samples
-
-GET_OLD_SAMPLE = {u'counter_name': u'instance',
- u'user_id': u'user-id',
- u'resource_id': u'resource-id',
- u'timestamp': u'2012-07-02T10:40:00',
- u'source': u'test_source',
- u'message_id': u'54558a1c-6ef3-11e2-9875-5453ed1bbb5f',
- u'counter_unit': u'',
- u'counter_volume': 1.0,
- u'project_id': u'project1',
- u'resource_metadata': {u'tag': u'self.counter',
- u'display_name': u'test-server'},
- u'counter_type': u'cumulative'}
-CREATE_SAMPLE = copy.deepcopy(GET_OLD_SAMPLE)
-del CREATE_SAMPLE['message_id']
-del CREATE_SAMPLE['source']
-CREATE_LIST_SAMPLE = copy.deepcopy(CREATE_SAMPLE)
-CREATE_LIST_SAMPLE['counter_name'] = 'image'
-
-GET_SAMPLE = {
- "user_id": None,
- "resource_id": "9b651dfd-7d30-402b-972e-212b2c4bfb05",
- "timestamp": "2014-11-03T13:37:46",
- "meter": "image",
- "volume": 1.0,
- "source": "openstack",
- "recorded_at": "2014-11-03T13:37:46.994458",
- "project_id": "2cc3a7bb859b4bacbeab0aa9ca673033",
- "type": "gauge",
- "id": "98b5f258-635e-11e4-8bdd-0025647390c1",
- "unit": "image",
- "resource_metadata": {},
-}
-
-METER_URL = '/v2/meters/instance'
-METER_URL_DIRECT = '/v2/meters/instance?direct=True'
-SECOND_METER_URL = '/v2/meters/image'
-SECOND_METER_URL_DIRECT = '/v2/meters/image?direct=True'
-SAMPLE_URL = '/v2/samples'
-QUERIES = ('q.field=resource_id&q.field=source&q.op=&q.op='
- '&q.type=&q.type=&q.value=foo&q.value=bar')
-LIMIT = 'limit=1'
-
-OLD_SAMPLE_FIXTURES = {
- METER_URL: {
- 'GET': (
- {},
- [GET_OLD_SAMPLE]
- ),
- 'POST': (
- {},
- [CREATE_SAMPLE],
- ),
- },
- METER_URL_DIRECT: {
- 'POST': (
- {},
- [CREATE_SAMPLE],
- )
- },
- SECOND_METER_URL: {
- 'POST': (
- {},
- [CREATE_LIST_SAMPLE] * 10,
- ),
- },
- SECOND_METER_URL_DIRECT: {
- 'POST': (
- {},
- [CREATE_LIST_SAMPLE] * 10,
- )
- },
- '%s?%s' % (METER_URL, QUERIES): {
- 'GET': (
- {},
- [],
- ),
- },
- '%s?%s' % (METER_URL, LIMIT): {
- 'GET': (
- {},
- [GET_OLD_SAMPLE]
- ),
- }
-}
-SAMPLE_FIXTURES = {
- SAMPLE_URL: {
- 'GET': (
- (),
- [GET_SAMPLE]
- ),
- },
- '%s?%s' % (SAMPLE_URL, QUERIES): {
- 'GET': (
- {},
- [],
- ),
- },
- '%s?%s' % (SAMPLE_URL, LIMIT): {
- 'GET': (
- {},
- [GET_SAMPLE],
- ),
- },
- '%s/%s' % (SAMPLE_URL, GET_SAMPLE['id']): {
- 'GET': (
- {},
- GET_SAMPLE,
- ),
- },
-}
-
-
-class OldSampleManagerTest(utils.BaseTestCase):
-
- def setUp(self):
- super(OldSampleManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(
- fixtures=OLD_SAMPLE_FIXTURES)
- self.api = client.BaseClient(self.http_client)
- self.mgr = ceilometerclient.v2.samples.OldSampleManager(self.api)
-
- def test_list_by_meter_name(self):
- samples = list(self.mgr.list(meter_name='instance'))
- expect = [
- 'GET', '/v2/meters/instance'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(samples))
- self.assertEqual('resource-id', samples[0].resource_id)
-
- def test_list_by_meter_name_extended(self):
- samples = list(self.mgr.list(meter_name='instance',
- q=[
- {"field": "resource_id",
- "value": "foo"},
- {"field": "source",
- "value": "bar"},
- ]))
- expect = ['GET', '%s?%s' % (METER_URL, QUERIES)]
- self.http_client.assert_called(*expect)
- self.assertEqual(0, len(samples))
-
- def test_create(self):
- sample = self.mgr.create(**CREATE_SAMPLE)
- expect = [
- 'POST', '/v2/meters/instance'
- ]
- self.http_client.assert_called(*expect, body=[CREATE_SAMPLE])
- self.assertIsNotNone(sample)
-
- def test_create_directly(self):
- sample = self.mgr.create(direct=True, **CREATE_SAMPLE)
- expect = [
- 'POST', '/v2/meters/instance?direct=True'
- ]
- self.http_client.assert_called(*expect, body=[CREATE_SAMPLE])
- self.assertIsNotNone(sample)
-
- def test_create_list(self):
- test_samples = [CREATE_LIST_SAMPLE] * 10
- samples = self.mgr.create_list(test_samples)
- expect = [
- 'POST', '/v2/meters/image'
- ]
- self.http_client.assert_called(*expect, body=test_samples)
- self.assertEqual(10, len(samples))
-
- def test_create_list_directly(self):
- test_samples = [CREATE_LIST_SAMPLE] * 10
- samples = self.mgr.create_list(test_samples, direct=True)
- expect = [
- 'POST', '/v2/meters/image?direct=True'
- ]
- self.http_client.assert_called(*expect, body=test_samples)
- self.assertEqual(10, len(samples))
-
- def test_limit(self):
- samples = list(self.mgr.list(meter_name='instance', limit=1))
- expect = ['GET', '/v2/meters/instance?limit=1']
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(samples))
-
-
-class SampleManagerTest(utils.BaseTestCase):
-
- def setUp(self):
- super(SampleManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(
- fixtures=SAMPLE_FIXTURES)
- self.api = client.BaseClient(self.http_client)
- self.mgr = ceilometerclient.v2.samples.SampleManager(self.api)
-
- def test_sample_list(self):
- samples = list(self.mgr.list())
- expect = [
- 'GET', '/v2/samples'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(samples))
- self.assertEqual('9b651dfd-7d30-402b-972e-212b2c4bfb05',
- samples[0].resource_id)
-
- def test_sample_list_with_queries(self):
- queries = [
- {"field": "resource_id",
- "value": "foo"},
- {"field": "source",
- "value": "bar"},
- ]
- samples = list(self.mgr.list(q=queries))
- expect = ['GET', '%s?%s' % (SAMPLE_URL, QUERIES)]
- self.http_client.assert_called(*expect)
- self.assertEqual(0, len(samples))
-
- def test_sample_list_with_limit(self):
- samples = list(self.mgr.list(limit=1))
- expect = ['GET', '/v2/samples?limit=1']
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(samples))
-
- def test_sample_get(self):
- sample = self.mgr.get(GET_SAMPLE['id'])
- expect = ['GET', '/v2/samples/' + GET_SAMPLE['id']]
- self.http_client.assert_called(*expect)
- self.assertEqual(GET_SAMPLE, sample.to_dict())
diff --git a/ceilometerclient/tests/unit/v2/test_shell.py b/ceilometerclient/tests/unit/v2/test_shell.py
deleted file mode 100644
index eca15e3..0000000
--- a/ceilometerclient/tests/unit/v2/test_shell.py
+++ /dev/null
@@ -1,1977 +0,0 @@
-# Copyright Ericsson AB 2014. All rights reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import json
-import re
-import sys
-
-import mock
-import six
-from testtools import matchers
-
-from ceilometerclient import exc
-from ceilometerclient import shell as base_shell
-from ceilometerclient.tests.unit import test_shell
-from ceilometerclient.tests.unit import utils
-from ceilometerclient.v2 import alarms
-from ceilometerclient.v2 import capabilities
-from ceilometerclient.v2 import event_types
-from ceilometerclient.v2 import events
-from ceilometerclient.v2 import meters
-from ceilometerclient.v2 import resources
-from ceilometerclient.v2 import samples
-from ceilometerclient.v2 import shell as ceilometer_shell
-from ceilometerclient.v2 import statistics
-from ceilometerclient.v2 import trait_descriptions
-from ceilometerclient.v2 import traits
-from keystoneauth1 import exceptions
-
-
-class ShellAlarmStateCommandsTest(utils.BaseTestCase):
-
- ALARM_ID = 'foobar'
-
- def setUp(self):
- super(ShellAlarmStateCommandsTest, self).setUp()
- self.cc = mock.Mock()
- self.cc.alarms = mock.Mock()
- self.args = mock.Mock()
- self.args.alarm_id = self.ALARM_ID
-
- def test_alarm_state_get(self):
- ceilometer_shell.do_alarm_state_get(self.cc, self.args)
- self.cc.alarms.get_state.assert_called_once_with(self.ALARM_ID)
- self.assertFalse(self.cc.alarms.set_state.called)
-
- def test_alarm_state_set(self):
- self.args.state = 'ok'
- ceilometer_shell.do_alarm_state_set(self.cc, self.args)
- self.cc.alarms.set_state.assert_called_once_with(self.ALARM_ID, 'ok')
- self.assertFalse(self.cc.alarms.get_state.called)
-
-
-class ShellAlarmHistoryCommandTest(utils.BaseTestCase):
-
- ALARM_ID = '768ff714-8cfb-4db9-9753-d484cb33a1cc'
- FULL_DETAIL = ('{"alarm_actions": [], '
- '"user_id": "8185aa72421a4fd396d4122cba50e1b5", '
- '"name": "scombo", '
- '"timestamp": "2013-10-03T08:58:33.647912", '
- '"enabled": true, '
- '"state_timestamp": "2013-10-03T08:58:33.647912", '
- '"rule": {"operator": "or", "alarm_ids": '
- '["062cc907-3a9f-4867-ab3b-fa83212b39f7"]}, '
- '"alarm_id": "768ff714-8cfb-4db9-9753-d484cb33a1cc", '
- '"state": "insufficient data", '
- '"insufficient_data_actions": [], '
- '"repeat_actions": false, '
- '"ok_actions": [], '
- '"project_id": "57d04f24d0824b78b1ea9bcecedbda8f", '
- '"type": "combination", '
- '"severity": "low", '
- '"description": "Combined state of alarms '
- '062cc907-3a9f-4867-ab3b-fa83212b39f7"}')
- ALARM_HISTORY = [{'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f',
- 'user_id': '8185aa72421a4fd396d4122cba50e1b5',
- 'event_id': 'c74a8611-6553-4764-a860-c15a6aabb5d0',
- 'timestamp': '2013-10-03T08:59:28.326000',
- 'detail': '{"state": "alarm"}',
- 'alarm_id': '768ff714-8cfb-4db9-9753-d484cb33a1cc',
- 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f',
- 'type': 'state transition'},
- {'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f',
- 'user_id': '8185aa72421a4fd396d4122cba50e1b5',
- 'event_id': 'c74a8611-6553-4764-a860-c15a6aabb5d0',
- 'timestamp': '2013-10-03T08:59:28.326000',
- 'detail': '{"description": "combination of one"}',
- 'alarm_id': '768ff714-8cfb-4db9-9753-d484cb33a1cc',
- 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f',
- 'type': 'rule change'},
- {'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f',
- 'user_id': '8185aa72421a4fd396d4122cba50e1b5',
- 'event_id': '4fd7df9e-190d-4471-8884-dc5a33d5d4bb',
- 'timestamp': '2013-10-03T08:58:33.647000',
- 'detail': FULL_DETAIL,
- 'alarm_id': '768ff714-8cfb-4db9-9753-d484cb33a1cc',
- 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f',
- 'type': 'creation'}]
- TIMESTAMP_RE = (' +\| (\d{4})-(\d{2})-(\d{2})T'
- '(\d{2})\:(\d{2})\:(\d{2})\.(\d{6}) \| +')
-
- def setUp(self):
- super(ShellAlarmHistoryCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.cc.alarms = mock.Mock()
- self.args = mock.Mock()
- self.args.alarm_id = self.ALARM_ID
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def _do_test_alarm_history(self, raw_query=None, parsed_query=None):
- self.args.query = raw_query
- history = [alarms.AlarmChange(mock.Mock(), change)
- for change in self.ALARM_HISTORY]
- self.cc.alarms.get_history.return_value = history
-
- ceilometer_shell.do_alarm_history(self.cc, self.args)
- self.cc.alarms.get_history.assert_called_once_with(
- q=parsed_query,
- alarm_id=self.ALARM_ID
- )
- out = sys.stdout.getvalue()
- required = [
- '.*creation%sname: scombo.*' % self.TIMESTAMP_RE,
- '.*rule change%sdescription: combination of one.*' %
- self.TIMESTAMP_RE,
- '.*state transition%sstate: alarm.*' % self.TIMESTAMP_RE,
- ]
- for r in required:
- self.assertThat(out, matchers.MatchesRegex(r, re.DOTALL))
-
- def test_alarm_all_history(self):
- self._do_test_alarm_history()
-
- def test_alarm_constrained_history(self):
- parsed_query = [dict(field='timestamp',
- value='2013-10-03T08:59:28',
- op='gt',
- type='')]
- self._do_test_alarm_history(raw_query='timestamp>2013-10-03T08:59:28',
- parsed_query=parsed_query)
-
-
-class ShellAlarmCommandTest(utils.BaseTestCase):
-
- ALARM_ID = '768ff714-8cfb-4db9-9753-d484cb33a1cc'
- ALARM = {"alarm_actions": ["log://"],
- "ok_actions": [],
- "description": "instance running hot",
- "timestamp": "2013-11-20T10:38:42.206952",
- "enabled": True,
- "state_timestamp": "2013-11-19T17:20:44",
- "threshold_rule": {"meter_name": "cpu_util",
- "evaluation_periods": 3,
- "period": 600,
- "statistic": "avg",
- "threshold": 99.0,
- "query": [{"field": "resource_id",
- "value": "INSTANCE_ID",
- "op": "eq"}],
- "comparison_operator": "gt"},
- "time_constraints": [{"name": "cons1",
- "description": "desc1",
- "start": "0 11 * * *",
- "duration": 300,
- "timezone": ""},
- {"name": "cons2",
- "description": "desc2",
- "start": "0 23 * * *",
- "duration": 600,
- "timezone": ""}],
- "alarm_id": ALARM_ID,
- "state": "insufficient data",
- "severity": "low",
- "insufficient_data_actions": [],
- "repeat_actions": True,
- "user_id": "528d9b68fa774689834b5c04b4564f8a",
- "project_id": "ed9d4e2be2a748bc80108053cf4598f5",
- "type": "threshold",
- "name": "cpu_high"}
-
- THRESHOLD_ALARM_CLI_ARGS = [
- '--name', 'cpu_high',
- '--description', 'instance running hot',
- '--meter-name', 'cpu_util',
- '--threshold', '70.0',
- '--comparison-operator', 'gt',
- '--statistic', 'avg',
- '--period', '600',
- '--evaluation-periods', '3',
- '--alarm-action', 'log://',
- '--alarm-action', 'http://example.com/alarm/state',
- '--query', 'resource_id=INSTANCE_ID'
- ]
-
- def setUp(self):
- super(ShellAlarmCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.cc.alarms = mock.Mock()
- self.args = mock.Mock()
- self.args.alarm_id = self.ALARM_ID
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def _do_test_alarm_update_repeat_actions(self, method, repeat_actions):
- self.args.threshold = 42.0
- if repeat_actions is not None:
- self.args.repeat_actions = repeat_actions
- alarm = [alarms.Alarm(mock.Mock(), self.ALARM)]
- self.cc.alarms.get.return_value = alarm
- self.cc.alarms.update.return_value = alarm[0]
-
- method(self.cc, self.args)
- args, kwargs = self.cc.alarms.update.call_args
- self.assertEqual(self.ALARM_ID, args[0])
- self.assertEqual(42.0, kwargs.get('threshold'))
- if repeat_actions is not None:
- self.assertEqual(repeat_actions, kwargs.get('repeat_actions'))
- else:
- self.assertNotIn('repeat_actions', kwargs)
-
- def test_alarm_update_repeat_actions_untouched(self):
- method = ceilometer_shell.do_alarm_update
- self._do_test_alarm_update_repeat_actions(method, None)
-
- def test_alarm_update_repeat_actions_set(self):
- method = ceilometer_shell.do_alarm_update
- self._do_test_alarm_update_repeat_actions(method, True)
-
- def test_alarm_update_repeat_actions_clear(self):
- method = ceilometer_shell.do_alarm_update
- self._do_test_alarm_update_repeat_actions(method, False)
-
- def test_alarm_combination_update_repeat_actions_untouched(self):
- method = ceilometer_shell.do_alarm_combination_update
- self._do_test_alarm_update_repeat_actions(method, None)
-
- def test_alarm_combination_update_repeat_actions_set(self):
- method = ceilometer_shell.do_alarm_combination_update
- self._do_test_alarm_update_repeat_actions(method, True)
-
- def test_alarm_combination_update_repeat_actions_clear(self):
- method = ceilometer_shell.do_alarm_combination_update
- self._do_test_alarm_update_repeat_actions(method, False)
-
- def test_alarm_threshold_update_repeat_actions_untouched(self):
- method = ceilometer_shell.do_alarm_threshold_update
- self._do_test_alarm_update_repeat_actions(method, None)
-
- def test_alarm_threshold_update_repeat_actions_set(self):
- method = ceilometer_shell.do_alarm_threshold_update
- self._do_test_alarm_update_repeat_actions(method, True)
-
- def test_alarm_threshold_update_repeat_actions_clear(self):
- method = ceilometer_shell.do_alarm_threshold_update
- self._do_test_alarm_update_repeat_actions(method, False)
-
- def test_alarm_event_upadte_repeat_action_untouched(self):
- method = ceilometer_shell.do_alarm_event_update
- self._do_test_alarm_update_repeat_actions(method, None)
-
- def test_alarm_event_upadte_repeat_action_set(self):
- method = ceilometer_shell.do_alarm_event_update
- self._do_test_alarm_update_repeat_actions(method, True)
-
- def test_alarm_event_upadte_repeat_action_clear(self):
- method = ceilometer_shell.do_alarm_event_update
- self._do_test_alarm_update_repeat_actions(method, False)
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_alarm_threshold_create_args(self):
- argv = ['alarm-threshold-create'] + self.THRESHOLD_ALARM_CLI_ARGS
- self._test_alarm_threshold_action_args('create', argv)
-
- def test_alarm_threshold_update_args(self):
- argv = ['alarm-threshold-update', 'x'] + self.THRESHOLD_ALARM_CLI_ARGS
- self._test_alarm_threshold_action_args('update', argv)
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def _test_alarm_threshold_action_args(self, action, argv):
- shell = base_shell.CeilometerShell()
- _, args = shell.parse_args(argv)
-
- alarm = alarms.Alarm(mock.Mock(), self.ALARM)
- getattr(self.cc.alarms, action).return_value = alarm
-
- func = getattr(ceilometer_shell, 'do_alarm_threshold_' + action)
- func(self.cc, args)
- _, kwargs = getattr(self.cc.alarms, action).call_args
- self._check_alarm_threshold_args(kwargs)
-
- def _check_alarm_threshold_args(self, kwargs):
- self.assertEqual('cpu_high', kwargs.get('name'))
- self.assertEqual('instance running hot', kwargs.get('description'))
- actions = ['log://', 'http://example.com/alarm/state']
- self.assertEqual(actions, kwargs.get('alarm_actions'))
- self.assertIn('threshold_rule', kwargs)
- rule = kwargs['threshold_rule']
- self.assertEqual('cpu_util', rule.get('meter_name'))
- self.assertEqual(70.0, rule.get('threshold'))
- self.assertEqual('gt', rule.get('comparison_operator'))
- self.assertEqual('avg', rule.get('statistic'))
- self.assertEqual(600, rule.get('period'))
- self.assertEqual(3, rule.get('evaluation_periods'))
- query = dict(field='resource_id', type='',
- value='INSTANCE_ID', op='eq')
- self.assertEqual([query], rule['query'])
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_alarm_create_time_constraints(self):
- shell = base_shell.CeilometerShell()
- argv = ['alarm-threshold-create',
- '--name', 'cpu_high',
- '--meter-name', 'cpu_util',
- '--threshold', '70.0',
- '--time-constraint',
- 'name=cons1;start="0 11 * * *";duration=300',
- '--time-constraint',
- 'name=cons2;start="0 23 * * *";duration=600',
- ]
- _, args = shell.parse_args(argv)
-
- alarm = alarms.Alarm(mock.Mock(), self.ALARM)
- self.cc.alarms.create.return_value = alarm
-
- ceilometer_shell.do_alarm_threshold_create(self.cc, args)
- _, kwargs = self.cc.alarms.create.call_args
- time_constraints = [dict(name='cons1', start='0 11 * * *',
- duration='300'),
- dict(name='cons2', start='0 23 * * *',
- duration='600')]
- self.assertEqual(time_constraints, kwargs['time_constraints'])
-
-
-class ShellAlarmGnocchiCommandTest(test_shell.ShellTestBase):
-
- ALARM_ID = 'b69ecdb9-f19b-4fb5-950f-5eb53938b718'
- TIME_CONSTRAINTS = [{
- u'duration': 300,
- u'start': u'0 11 * * *',
- u'description': u'desc1',
- u'name': u'cons1',
- u'timezone': u''}, {
- u'duration': 600,
- u'start': u'0 23 * * *',
- u'name': u'cons2',
- u'description': u'desc2',
- u'timezone': u''}]
-
- ALARM1 = {
- u'name': u'name_gnocchi_alarm',
- u'description': u'description_gnocchi_alarm',
- u'enabled': True,
- u'ok_actions': [u'http://something/ok'],
- u'alarm_actions': [u'http://something/alarm'],
- u'timestamp': u'2015-12-21T03:10:32.305133',
- u'state_timestamp': u'2015-12-21T03:10:32.305133',
- u'gnocchi_resources_threshold_rule': {
- u'evaluation_periods': 3,
- u'metric': u'cpu_util',
- u'resource_id': u'768ff714-8cfb-4db9-9753-d484cb33a1cc',
- u'threshold': 70.0,
- u'granularity': 60,
- u'aggregation_method': u'count',
- u'comparison_operator': u'le',
- u'resource_type': u'instance',
- },
- u'time_constraints': TIME_CONSTRAINTS,
- u'alarm_id': ALARM_ID,
- u'state': u'ok',
- u'insufficient_data_actions': [u'http://something/insufficient'],
- u'repeat_actions': True,
- u'user_id': u'f28735621ee84f329144eb467c91fce6',
- u'project_id': u'97fcad0402ce4f65ac3bd42a0c6a7e74',
- u'type': u'gnocchi_resources_threshold',
- u'severity': u'critical',
- }
-
- ALARM2 = {
- u'name': u'name_gnocchi_alarm',
- u'description': u'description_gnocchi_alarm',
- u'enabled': True,
- u'ok_actions': [u'http://something/ok'],
- u'alarm_actions': [u'http://something/alarm'],
- u'timestamp': u'2015-12-21T03:10:32.305133',
- u'state_timestamp': u'2015-12-21T03:10:32.305133',
- u'gnocchi_aggregation_by_metrics_threshold_rule': {
- u'evaluation_periods': 3,
- u'metrics': [u'b3d9d8ab-05e8-439f-89ad-5e978dd2a5eb',
- u'009d4faf-c275-46f0-8f2d-670b15bac2b0'],
- u'threshold': 70.0,
- u'granularity': 60,
- u'aggregation_method': u'count',
- u'comparison_operator': u'le',
- },
- u'time_constraints': TIME_CONSTRAINTS,
- u'alarm_id': ALARM_ID,
- u'state': u'ok',
- u'insufficient_data_actions': [u'http://something/insufficient'],
- u'repeat_actions': True,
- u'user_id': u'f28735621ee84f329144eb467c91fce6',
- u'project_id': u'97fcad0402ce4f65ac3bd42a0c6a7e74',
- u'type': u'gnocchi_aggregation_by_metrics_threshold',
- u'severity': u'critical',
- }
-
- ALARM3 = {
- u'name': u'name_gnocchi_alarm',
- u'description': u'description_gnocchi_alarm',
- u'enabled': True,
- u'ok_actions': [u'http://something/ok'],
- u'alarm_actions': [u'http://something/alarm'],
- u'timestamp': u'2015-12-21T03:10:32.305133',
- u'state_timestamp': u'2015-12-21T03:10:32.305133',
- u'gnocchi_aggregation_by_resources_threshold_rule': {
- u'evaluation_periods': 3,
- u'metric': u'cpu_util',
- u'threshold': 70.0,
- u'granularity': 60,
- u'aggregation_method': u'count',
- u'comparison_operator': u'le',
- u'resource_type': u'instance',
- u'query': u'{"=": {"server_group":"my_autoscaling_group"}}',
- },
- u'time_constraints': TIME_CONSTRAINTS,
- u'alarm_id': ALARM_ID,
- u'state': u'ok',
- u'insufficient_data_actions': [u'http://something/insufficient'],
- u'repeat_actions': True,
- u'user_id': u'f28735621ee84f329144eb467c91fce6',
- u'project_id': u'97fcad0402ce4f65ac3bd42a0c6a7e74',
- u'type': u'gnocchi_aggregation_by_resources_threshold',
- u'severity': u'critical',
- }
-
- COMMON_CLI_ARGS = [
- '--name', 'name_gnocchi_alarm',
- '--description', 'description_gnocchi_alarm',
- '--enabled', 'True',
- '--state', 'ok',
- '--severity', 'critical',
- '--ok-action', 'http://something/ok',
- '--alarm-action', 'http://something/alarm',
- '--insufficient-data-action', 'http://something/insufficient',
- '--repeat-actions', 'True',
- '--comparison-operator', 'le',
- '--aggregation-method', 'count',
- '--threshold', '70',
- '--evaluation-periods', '3',
- '--granularity', '60',
- '--time-constraint',
- 'name=cons1;start="0 11 * * *";duration=300;description="desc1"',
- '--time-constraint',
- 'name=cons2;start="0 23 * * *";duration=600;description="desc2"',
- '--user-id', 'f28735621ee84f329144eb467c91fce6',
- '--project-id', '97fcad0402ce4f65ac3bd42a0c6a7e74',
- ]
-
- GNOCCHI_RESOURCES_CLI_ARGS = COMMON_CLI_ARGS + [
- '--metric', 'cpu_util',
- '--resource-type', 'instance',
- '--resource-id', '768ff714-8cfb-4db9-9753-d484cb33a1cc',
- ]
-
- GNOCCHI_AGGR_BY_METRICS_CLI_ARGS = COMMON_CLI_ARGS + [
- '-m', 'b3d9d8ab-05e8-439f-89ad-5e978dd2a5eb',
- '-m', '009d4faf-c275-46f0-8f2d-670b15bac2b0',
- ]
-
- GNOCCHI_AGGR_BY_RESOURCES_CLI_ARGS = COMMON_CLI_ARGS + [
- '--metric', 'cpu_util',
- '--resource-type', 'instance',
- '--query', '{"=": {"server_group":"my_autoscaling_group"}}'
- ]
-
- def setUp(self):
- super(ShellAlarmGnocchiCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.cc.alarms = mock.Mock()
- self.args = mock.Mock()
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_do_alarm_gnocchi_resources_threshold_create(self):
-
- alarm = alarms.Alarm(mock.Mock(), self.ALARM1)
- self.cc.alarms.create.return_value = alarm
- ceilometer_shell.do_alarm_gnocchi_resources_threshold_create(self.cc,
- self.args)
- self.assertEqual('''\
-+---------------------------+--------------------------------------+
-| Property | Value |
-+---------------------------+--------------------------------------+
-| aggregation_method | count |
-| alarm_actions | ["http://something/alarm"] |
-| alarm_id | b69ecdb9-f19b-4fb5-950f-5eb53938b718 |
-| comparison_operator | le |
-| description | description_gnocchi_alarm |
-| enabled | True |
-| evaluation_periods | 3 |
-| granularity | 60 |
-| insufficient_data_actions | ["http://something/insufficient"] |
-| metric | cpu_util |
-| name | name_gnocchi_alarm |
-| ok_actions | ["http://something/ok"] |
-| project_id | 97fcad0402ce4f65ac3bd42a0c6a7e74 |
-| repeat_actions | True |
-| resource_id | 768ff714-8cfb-4db9-9753-d484cb33a1cc |
-| resource_type | instance |
-| severity | critical |
-| state | ok |
-| threshold | 70.0 |
-| time_constraints | [{name: cons1, |
-| | description: desc1, |
-| | start: 0 11 * * *, |
-| | duration: 300}, |
-| | {name: cons2, |
-| | description: desc2, |
-| | start: 0 23 * * *, |
-| | duration: 600}] |
-| type | gnocchi_resources_threshold |
-| user_id | f28735621ee84f329144eb467c91fce6 |
-+---------------------------+--------------------------------------+
-''', sys.stdout.getvalue())
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_do_alarm_gnocchi_aggr_by_metrics_threshold_create(self):
-
- alarm = alarms.Alarm(mock.Mock(), self.ALARM2)
- self.cc.alarms.create.return_value = alarm
- ceilometer_shell.\
- do_alarm_gnocchi_aggregation_by_metrics_threshold_create(
- self.cc, self.args)
- stdout = sys.stdout.getvalue()
- self.assertIn("b69ecdb9-f19b-4fb5-950f-5eb53938b718", stdout)
- self.assertIn("[\"http://something/alarm\"]", stdout)
- self.assertIn("description_gnocchi_alarm", stdout)
- self.assertIn("gnocchi_aggregation_by_metrics_threshold", stdout)
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_do_alarm_gnocchi_aggr_by_resources_threshold_create(self):
-
- alarm = alarms.Alarm(mock.Mock(), self.ALARM3)
- self.cc.alarms.create.return_value = alarm
- ceilometer_shell.\
- do_alarm_gnocchi_aggregation_by_resources_threshold_create(
- self.cc, self.args)
- self.assertEqual('''\
-+---------------------------+------------------------------------------------+
-| Property | Value |
-+---------------------------+------------------------------------------------+
-| aggregation_method | count |
-| alarm_actions | ["http://something/alarm"] |
-| alarm_id | b69ecdb9-f19b-4fb5-950f-5eb53938b718 |
-| comparison_operator | le |
-| description | description_gnocchi_alarm |
-| enabled | True |
-| evaluation_periods | 3 |
-| granularity | 60 |
-| insufficient_data_actions | ["http://something/insufficient"] |
-| metric | cpu_util |
-| name | name_gnocchi_alarm |
-| ok_actions | ["http://something/ok"] |
-| project_id | 97fcad0402ce4f65ac3bd42a0c6a7e74 |
-| query | {"=": {"server_group":"my_autoscaling_group"}} |
-| repeat_actions | True |
-| resource_type | instance |
-| severity | critical |
-| state | ok |
-| threshold | 70.0 |
-| time_constraints | [{name: cons1, |
-| | description: desc1, |
-| | start: 0 11 * * *, |
-| | duration: 300}, |
-| | {name: cons2, |
-| | description: desc2, |
-| | start: 0 23 * * *, |
-| | duration: 600}] |
-| type | gnocchi_aggregation_by_resources_threshold |
-| user_id | f28735621ee84f329144eb467c91fce6 |
-+---------------------------+------------------------------------------------+
-''', sys.stdout.getvalue())
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_do_alarm_gnocchi_resources_threshold_create_args(self):
- argv = ['alarm-gnocchi-resources-threshold-create']
- argv.extend(self.GNOCCHI_RESOURCES_CLI_ARGS)
- self._test_alarm_gnocchi_resources_arguments('create', argv)
-
- def test_do_alarm_gnocchi_resources_threshold_update_args(self):
- argv = ['alarm-gnocchi-resources-threshold-update']
- argv.extend(self.GNOCCHI_RESOURCES_CLI_ARGS)
- argv.append(self.ALARM_ID)
- self._test_alarm_gnocchi_resources_arguments('update', argv)
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_do_alarm_gnocchi_aggr_by_metrics_threshold_create_args(self):
- argv = ['alarm-gnocchi-aggregation-by-metrics-threshold-create']
- argv.extend(self.GNOCCHI_AGGR_BY_METRICS_CLI_ARGS)
- self._test_alarm_gnocchi_aggr_by_metrics_arguments('create', argv)
-
- def test_do_alarm_gnocchi_aggr_by_metrics_threshold_update_args(self):
- argv = ['alarm-gnocchi-aggregation-by-metrics-threshold-update']
- argv.extend(self.GNOCCHI_AGGR_BY_METRICS_CLI_ARGS)
- argv.append(self.ALARM_ID)
- self._test_alarm_gnocchi_aggr_by_metrics_arguments('update', argv)
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_do_alarm_gnocchi_aggr_by_resources_threshold_create_args(self):
- argv = ['alarm-gnocchi-aggregation-by-resources-threshold-create']
- argv.extend(self.GNOCCHI_AGGR_BY_RESOURCES_CLI_ARGS)
- self._test_alarm_gnocchi_aggr_by_resources_arguments('create', argv)
-
- def test_do_alarm_gnocchi_aggr_by_resources_threshold_update_args(self):
- argv = ['alarm-gnocchi-aggregation-by-resources-threshold-update']
- argv.extend(self.GNOCCHI_AGGR_BY_RESOURCES_CLI_ARGS)
- argv.append(self.ALARM_ID)
- self._test_alarm_gnocchi_aggr_by_resources_arguments('update', argv)
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def _test_common_alarm_gnocchi_arguments(self, kwargs):
- self.assertEqual('97fcad0402ce4f65ac3bd42a0c6a7e74',
- kwargs.get('project_id'))
- self.assertEqual('f28735621ee84f329144eb467c91fce6',
- kwargs.get('user_id'))
- self.assertEqual('name_gnocchi_alarm', kwargs.get('name'))
- self.assertEqual('description_gnocchi_alarm',
- kwargs.get('description'))
- self.assertEqual(['http://something/alarm'],
- kwargs.get('alarm_actions'))
- self.assertEqual(['http://something/ok'], kwargs.get('ok_actions'))
- self.assertEqual(['http://something/insufficient'],
- kwargs.get('insufficient_data_actions'))
- self.assertEqual('critical', kwargs.get('severity'))
- self.assertEqual('ok', kwargs.get('state'))
- self.assertEqual(True, kwargs.get('enabled'))
- self.assertEqual(True, kwargs.get('repeat_actions'))
- time_constraints = [dict(name='cons1', start='0 11 * * *',
- duration='300', description='desc1'),
- dict(name='cons2', start='0 23 * * *',
- duration='600', description='desc2')]
- self.assertEqual(time_constraints, kwargs['time_constraints'])
-
- 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.apiclient.'
- 'client.HTTPClient.client_request') as request:
- request.site_effect = exceptions.EndpointNotFound
- base_shell.main(argv)
- args, kwargs = mocked.call_args
- self.assertEqual('gnocchi_resources_threshold', kwargs.get('type'))
- self.assertIn('gnocchi_resources_threshold_rule', kwargs)
- rule = kwargs['gnocchi_resources_threshold_rule']
- self.assertEqual('cpu_util', rule.get('metric'))
- self.assertEqual(70.0, rule.get('threshold'))
- self.assertEqual(60, rule.get('granularity'))
- self.assertEqual('count', rule.get('aggregation_method'))
- self.assertEqual('le', rule.get('comparison_operator'))
- self.assertEqual(3, rule.get('evaluation_periods'))
- self.assertEqual('768ff714-8cfb-4db9-9753-d484cb33a1cc',
- rule.get('resource_id'))
- self.assertEqual('instance', rule.get('resource_type'))
- self._test_common_alarm_gnocchi_arguments(kwargs)
-
- 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.apiclient.'
- 'client.HTTPClient.client_request') as request:
- request.site_effect = exceptions.EndpointNotFound
- base_shell.main(argv)
- args, kwargs = mocked.call_args
- self.assertEqual('gnocchi_aggregation_by_metrics_threshold',
- kwargs.get('type'))
- self.assertIn('gnocchi_aggregation_by_metrics_threshold_rule', kwargs)
- rule = kwargs['gnocchi_aggregation_by_metrics_threshold_rule']
- self.assertEqual(['b3d9d8ab-05e8-439f-89ad-5e978dd2a5eb',
- '009d4faf-c275-46f0-8f2d-670b15bac2b0'],
- rule.get('metrics'))
- self.assertEqual(70.0, rule.get('threshold'))
- self.assertEqual(60, rule.get('granularity'))
- self.assertEqual('count', rule.get('aggregation_method'))
- self.assertEqual('le', rule.get('comparison_operator'))
- self.assertEqual(3, rule.get('evaluation_periods'))
- self._test_common_alarm_gnocchi_arguments(kwargs)
-
- 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.apiclient.'
- 'client.HTTPClient.client_request') as request:
- request.site_effect = exceptions.EndpointNotFound
- base_shell.main(argv)
- args, kwargs = mocked.call_args
- self.assertEqual('gnocchi_aggregation_by_resources_threshold',
- kwargs.get('type'))
- self.assertIn('gnocchi_aggregation_by_resources_threshold_rule',
- kwargs)
- rule = kwargs['gnocchi_aggregation_by_resources_threshold_rule']
- self.assertEqual('cpu_util', rule.get('metric'))
- self.assertEqual(70.0, rule.get('threshold'))
- self.assertEqual(60, rule.get('granularity'))
- self.assertEqual('count', rule.get('aggregation_method'))
- self.assertEqual('le', rule.get('comparison_operator'))
- self.assertEqual(3, rule.get('evaluation_periods'))
- self.assertEqual('instance', rule.get('resource_type'))
- self.assertEqual('{"=": {"server_group":"my_autoscaling_group"}}',
- rule.get('query'))
- self._test_common_alarm_gnocchi_arguments(kwargs)
-
-
-class ShellSampleListCommandTest(utils.BaseTestCase):
-
- METER = 'cpu_util'
- SAMPLE_VALUES = (
- ("cpu_util",
- "5dcf5537-3161-4e25-9235-407e1385bd35",
- "2013-10-15T05:50:30",
- "%",
- 0.261666666667,
- "gauge",
- "86536501-b2c9-48f6-9c6a-7a5b14ba7482"),
- ("cpu_util",
- "87d197e9-9cf6-4c25-bc66-1b1f4cedb52f",
- "2013-10-15T05:50:29",
- "%",
- 0.261666666667,
- "gauge",
- "fe2a91ec-602b-4b55-8cba-5302ce3b916e",),
- ("cpu_util",
- "5dcf5537-3161-4e25-9235-407e1385bd35",
- "2013-10-15T05:40:30",
- "%",
- 0.251247920133,
- "gauge",
- "52768bcb-b4e9-4db9-a30c-738c758b6f43"),
- ("cpu_util",
- "87d197e9-9cf6-4c25-bc66-1b1f4cedb52f",
- "2013-10-15T05:40:29",
- "%",
- 0.26,
- "gauge",
- "31ae614a-ac6b-4fb9-b106-4667bae03308"),
- )
-
- OLD_SAMPLES = [
- dict(counter_name=s[0],
- resource_id=s[1],
- timestamp=s[2],
- counter_unit=s[3],
- counter_volume=s[4],
- counter_type=s[5])
- for s in SAMPLE_VALUES
- ]
-
- SAMPLES = [
- dict(meter=s[0],
- resource_id=s[1],
- timestamp=s[2],
- unit=s[3],
- volume=s[4],
- type=s[5],
- id=s[6])
- for s in SAMPLE_VALUES
- ]
-
- def setUp(self):
- super(ShellSampleListCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.cc.samples = mock.Mock()
- self.cc.new_samples = mock.Mock()
- self.args = mock.Mock()
- self.args.query = None
- self.args.limit = None
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_old_sample_list(self):
- self.args.meter = self.METER
- sample_list = [samples.OldSample(mock.Mock(), sample)
- for sample in self.OLD_SAMPLES]
- self.cc.samples.list.return_value = sample_list
-
- ceilometer_shell.do_sample_list(self.cc, self.args)
- self.cc.samples.list.assert_called_once_with(
- meter_name=self.METER,
- q=None,
- limit=None)
-
- self.assertEqual('''\
-+--------------------------------------+----------+-------+----------------\
-+------+---------------------+
-| Resource ID | Name | Type | Volume \
-| Unit | Timestamp |
-+--------------------------------------+----------+-------+----------------\
-+------+---------------------+
-| 5dcf5537-3161-4e25-9235-407e1385bd35 | cpu_util | gauge | 0.261666666667 \
-| % | 2013-10-15T05:50:30 |
-| 87d197e9-9cf6-4c25-bc66-1b1f4cedb52f | cpu_util | gauge | 0.261666666667 \
-| % | 2013-10-15T05:50:29 |
-| 5dcf5537-3161-4e25-9235-407e1385bd35 | cpu_util | gauge | 0.251247920133 \
-| % | 2013-10-15T05:40:30 |
-| 87d197e9-9cf6-4c25-bc66-1b1f4cedb52f | cpu_util | gauge | 0.26 \
-| % | 2013-10-15T05:40:29 |
-+--------------------------------------+----------+-------+----------------\
-+------+---------------------+
-''', sys.stdout.getvalue())
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_sample_list(self):
- self.args.meter = None
- sample_list = [samples.Sample(mock.Mock(), sample)
- for sample in self.SAMPLES]
- self.cc.new_samples.list.return_value = sample_list
-
- ceilometer_shell.do_sample_list(self.cc, self.args)
- self.cc.new_samples.list.assert_called_once_with(
- q=None,
- limit=None)
-
- self.assertEqual('''\
-+--------------------------------------+--------------------------------------\
-+----------+-------+----------------+------+---------------------+
-| ID | Resource ID \
-| Name | Type | Volume | Unit | Timestamp |
-+--------------------------------------+--------------------------------------\
-+----------+-------+----------------+------+---------------------+
-| 86536501-b2c9-48f6-9c6a-7a5b14ba7482 | 5dcf5537-3161-4e25-9235-407e1385bd35 \
-| cpu_util | gauge | 0.261666666667 | % | 2013-10-15T05:50:30 |
-| fe2a91ec-602b-4b55-8cba-5302ce3b916e | 87d197e9-9cf6-4c25-bc66-1b1f4cedb52f \
-| cpu_util | gauge | 0.261666666667 | % | 2013-10-15T05:50:29 |
-| 52768bcb-b4e9-4db9-a30c-738c758b6f43 | 5dcf5537-3161-4e25-9235-407e1385bd35 \
-| cpu_util | gauge | 0.251247920133 | % | 2013-10-15T05:40:30 |
-| 31ae614a-ac6b-4fb9-b106-4667bae03308 | 87d197e9-9cf6-4c25-bc66-1b1f4cedb52f \
-| cpu_util | gauge | 0.26 | % | 2013-10-15T05:40:29 |
-+--------------------------------------+--------------------------------------\
-+----------+-------+----------------+------+---------------------+
-''', sys.stdout.getvalue())
-
-
-class ShellSampleShowCommandTest(utils.BaseTestCase):
-
- SAMPLE = {
- "user_id": None,
- "resource_id": "9b651dfd-7d30-402b-972e-212b2c4bfb05",
- "timestamp": "2014-11-03T13:37:46",
- "meter": "image",
- "volume": 1.0,
- "source": "openstack",
- "recorded_at": "2014-11-03T13:37:46.994458",
- "project_id": "2cc3a7bb859b4bacbeab0aa9ca673033",
- "type": "gauge",
- "id": "98b5f258-635e-11e4-8bdd-0025647390c1",
- "unit": "image",
- "metadata": {
- "name": "cirros-0.3.2-x86_64-uec",
- }
- }
-
- def setUp(self):
- super(ShellSampleShowCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.cc.new_samples = mock.Mock()
- self.args = mock.Mock()
- self.args.sample_id = "98b5f258-635e-11e4-8bdd-0025647390c1"
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_sample_show(self):
- sample = samples.Sample(mock.Mock(), self.SAMPLE)
- self.cc.new_samples.get.return_value = sample
-
- ceilometer_shell.do_sample_show(self.cc, self.args)
- self.cc.new_samples.get.assert_called_once_with(
- "98b5f258-635e-11e4-8bdd-0025647390c1")
-
- self.assertEqual('''\
-+-------------+--------------------------------------+
-| Property | Value |
-+-------------+--------------------------------------+
-| id | 98b5f258-635e-11e4-8bdd-0025647390c1 |
-| metadata | {"name": "cirros-0.3.2-x86_64-uec"} |
-| meter | image |
-| project_id | 2cc3a7bb859b4bacbeab0aa9ca673033 |
-| recorded_at | 2014-11-03T13:37:46.994458 |
-| resource_id | 9b651dfd-7d30-402b-972e-212b2c4bfb05 |
-| source | openstack |
-| timestamp | 2014-11-03T13:37:46 |
-| type | gauge |
-| unit | image |
-| user_id | None |
-| volume | 1.0 |
-+-------------+--------------------------------------+
-''', sys.stdout.getvalue())
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_sample_show_raises_command_err(self):
- self.cc.new_samples.get.side_effect = exc.HTTPNotFound
-
- self.assertRaises(exc.CommandError, ceilometer_shell.do_sample_show,
- self.cc, self.args)
-
-
-class ShellSampleCreateCommandTest(utils.BaseTestCase):
-
- METER = 'instance'
- METER_TYPE = 'gauge'
- RESOURCE_ID = '0564c64c-3545-4e34-abfb-9d18e5f2f2f9'
- SAMPLE_VOLUME = '1'
- METER_UNIT = 'instance'
- SAMPLE = [{
- u'counter_name': u'instance',
- u'user_id': u'21b442b8101d407d8242b6610e0ed0eb',
- u'resource_id': u'0564c64c-3545-4e34-abfb-9d18e5f2f2f9',
- u'timestamp': u'2014-01-10T03: 05: 33.951170',
- u'message_id': u'1247cbe6-79a4-11e3-a296-000c294c58e2',
- u'source': u'384260c6987b451d8290e66e1f108082: openstack',
- u'counter_unit': u'instance',
- u'counter_volume': 1.0,
- u'project_id': u'384260c6987b451d8290e66e1f108082',
- u'counter_type': u'gauge',
- u'resource_metadata': {u'display_name': u'test_name'}
- }]
-
- def setUp(self):
- super(ShellSampleCreateCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.cc.samples = mock.Mock()
- self.args = mock.Mock()
- self.args.meter_name = self.METER
- self.args.meter_type = self.METER_TYPE
- self.args.meter_unit = self.METER_UNIT
- self.args.resource_id = self.RESOURCE_ID
- self.args.sample_volume = self.SAMPLE_VOLUME
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_sample_create(self):
- ret_sample = [samples.OldSample(mock.Mock(), sample)
- for sample in self.SAMPLE]
- self.cc.samples.create.return_value = ret_sample
-
- ceilometer_shell.do_sample_create(self.cc, self.args)
-
- self.assertEqual('''\
-+-------------------+---------------------------------------------+
-| Property | Value |
-+-------------------+---------------------------------------------+
-| message_id | 1247cbe6-79a4-11e3-a296-000c294c58e2 |
-| name | instance |
-| project_id | 384260c6987b451d8290e66e1f108082 |
-| resource_id | 0564c64c-3545-4e34-abfb-9d18e5f2f2f9 |
-| resource_metadata | {"display_name": "test_name"} |
-| source | 384260c6987b451d8290e66e1f108082: openstack |
-| timestamp | 2014-01-10T03: 05: 33.951170 |
-| type | gauge |
-| unit | instance |
-| user_id | 21b442b8101d407d8242b6610e0ed0eb |
-| volume | 1.0 |
-+-------------------+---------------------------------------------+
-''', sys.stdout.getvalue())
-
- def test_sample_create_with_invalid_resource_metadata(self):
- self.args.resource_metadata = 'foo=bar'
- with mock.patch('ceilometerclient.exc.CommandError') as e:
- e.return_value = exc.BaseException()
- self.assertRaises(exc.BaseException,
- ceilometer_shell.do_sample_create,
- self.cc, self.args)
- e.assert_called_with('Invalid resource metadata, it should be a'
- ' json string, like: \'{"foo":"bar"}\'')
-
-
-class ShellSampleCreateListCommandTest(utils.BaseTestCase):
-
- SAMPLE = {
- u'counter_name': u'image',
- u'user_id': u'21b442b8101d407d8242b6610e0ed0eb',
- u'resource_id': u'0564c64c-3545-4e34-abfb-9d18e5f2f2f9',
- u'timestamp': u'2015-05-19T12:00:08.368574',
- u'source': u'384260c6987b451d8290e66e1f108082: openstack',
- u'counter_unit': u'image',
- u'counter_volume': 1.0,
- u'project_id': u'384260c6987b451d8290e66e1f108082',
- u'resource_metadata': {},
- u'counter_type': u'cumulative'
- }
-
- def setUp(self):
- super(ShellSampleCreateListCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.cc.samples = mock.Mock()
- self.cc.samples.create_list = mock.Mock()
- self.args = mock.Mock()
- self.samples = [self.SAMPLE] * 5
- self.args.samples_list = json.dumps(self.samples)
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_sample_create_list(self):
- ret_samples = [samples.OldSample(mock.Mock(),
- sample) for sample in self.samples]
- self.cc.samples.create_list.return_value = ret_samples
- ceilometer_shell.do_sample_create_list(self.cc, self.args)
- self.cc.samples.create_list.assert_called_with(self.samples,
- direct=mock.ANY)
- self.assertEqual('''\
-+--------------------------------------+-------+------------+--------+-------\
-+----------------------------+
-| Resource ID | Name | Type | Volume | Unit \
-| Timestamp |
-+--------------------------------------+-------+------------+--------+-------\
-+----------------------------+
-| 0564c64c-3545-4e34-abfb-9d18e5f2f2f9 | image | cumulative | 1.0 | image \
-| 2015-05-19T12:00:08.368574 |
-| 0564c64c-3545-4e34-abfb-9d18e5f2f2f9 | image | cumulative | 1.0 | image \
-| 2015-05-19T12:00:08.368574 |
-| 0564c64c-3545-4e34-abfb-9d18e5f2f2f9 | image | cumulative | 1.0 | image \
-| 2015-05-19T12:00:08.368574 |
-| 0564c64c-3545-4e34-abfb-9d18e5f2f2f9 | image | cumulative | 1.0 | image \
-| 2015-05-19T12:00:08.368574 |
-| 0564c64c-3545-4e34-abfb-9d18e5f2f2f9 | image | cumulative | 1.0 | image \
-| 2015-05-19T12:00:08.368574 |
-+--------------------------------------+-------+------------+--------+-------\
-+----------------------------+
-''', sys.stdout.getvalue())
-
-
-class ShellQuerySamplesCommandTest(utils.BaseTestCase):
-
- SAMPLE = [{u'id': u'b55d1526-9929-11e3-a3f6-02163e5df1e6',
- u'metadata': {
- u'name1': u'value1',
- u'name2': u'value2'},
- u'meter': 'instance',
- u'project_id': u'35b17138-b364-4e6a-a131-8f3099c5be68',
- u'resource_id': u'bd9431c1-8d69-4ad3-803a-8d4a6b89fd36',
- u'source': u'openstack',
- u'timestamp': u'2014-02-19T05:50:16.673604',
- u'type': u'gauge',
- u'unit': u'instance',
- u'volume': 1,
- u'user_id': 'efd87807-12d2-4b38-9c70-5f5c2ac427ff'}]
-
- QUERY = {"filter": {"and": [{"=": {"source": "openstack"}},
- {">": {"timestamp": "2014-02-19T05:50:16"}}]},
- "orderby": [{"timestamp": "desc"}, {"volume": "asc"}],
- "limit": 10}
-
- def setUp(self):
- super(ShellQuerySamplesCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.args = mock.Mock()
- self.args.filter = self.QUERY["filter"]
- self.args.orderby = self.QUERY["orderby"]
- self.args.limit = self.QUERY["limit"]
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_query(self):
- ret_sample = [samples.Sample(mock.Mock(), sample)
- for sample in self.SAMPLE]
- self.cc.query_samples.query.return_value = ret_sample
-
- ceilometer_shell.do_query_samples(self.cc, self.args)
-
- self.assertEqual('''\
-+--------------------------------------+--------------------------------------\
-+----------+-------+--------+----------+----------------------------+
-| ID | Resource ID \
-| Meter | Type | Volume | Unit | Timestamp |
-+--------------------------------------+--------------------------------------\
-+----------+-------+--------+----------+----------------------------+
-| b55d1526-9929-11e3-a3f6-02163e5df1e6 | bd9431c1-8d69-4ad3-803a-8d4a6b89fd36 \
-| instance | gauge | 1 | instance | 2014-02-19T05:50:16.673604 |
-+--------------------------------------+--------------------------------------\
-+----------+-------+--------+----------+----------------------------+
-''', sys.stdout.getvalue())
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_query_raises_command_error(self):
- self.cc.query_samples.query.side_effect = exc.HTTPNotFound
-
- self.assertRaises(exc.CommandError,
- ceilometer_shell.do_query_samples,
- self.cc, self.args)
-
-
-class ShellQueryAlarmsCommandTest(utils.BaseTestCase):
-
- ALARM = [{"alarm_actions": ["http://site:8000/alarm"],
- "alarm_id": "768ff714-8cfb-4db9-9753-d484cb33a1cc",
- "combination_rule": {
- "alarm_ids": [
- "739e99cb-c2ec-4718-b900-332502355f38",
- "153462d0-a9b8-4b5b-8175-9e4b05e9b856"],
- "operator": "or"},
- "description": "An alarm",
- "enabled": True,
- "insufficient_data_actions": ["http://site:8000/nodata"],
- "name": "SwiftObjectAlarm",
- "ok_actions": ["http://site:8000/ok"],
- "project_id": "c96c887c216949acbdfbd8b494863567",
- "repeat_actions": False,
- "state": "ok",
- "severity": "critical",
- "state_timestamp": "2014-02-20T10:37:15.589860",
- "threshold_rule": None,
- "timestamp": "2014-02-20T10:37:15.589856",
- "time_constraints": [{"name": "test", "start": "0 23 * * *",
- "duration": 10800}],
- "type": "combination",
- "user_id": "c96c887c216949acbdfbd8b494863567"}]
-
- QUERY = {"filter": {"and": [{"!=": {"state": "ok"}},
- {"=": {"type": "combination"}}]},
- "orderby": [{"state_timestamp": "desc"}],
- "limit": 10}
-
- def setUp(self):
- super(ShellQueryAlarmsCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.args = mock.Mock()
- self.args.filter = self.QUERY["filter"]
- self.args.orderby = self.QUERY["orderby"]
- self.args.limit = self.QUERY["limit"]
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_query(self):
- ret_alarm = [alarms.Alarm(mock.Mock(), alarm)
- for alarm in self.ALARM]
- self.cc.query_alarms.query.return_value = ret_alarm
-
- ceilometer_shell.do_query_alarms(self.cc, self.args)
-
- self.assertEqual('''\
-+--------------------------------------+------------------+-------+----------+\
----------+------------+-------------------------------------------------------\
------------------------------------------------+-------------------------------\
--+
-| Alarm ID | Name | State | Severity \
-| Enabled | Continuous | Alarm condition \
- | Time constraints \
- |
-+--------------------------------------+------------------+-------+----------+\
----------+------------+-------------------------------------------------------\
------------------------------------------------+--------------------------------+
-| 768ff714-8cfb-4db9-9753-d484cb33a1cc | SwiftObjectAlarm | ok | critical \
-| True | False | combinated states (OR) of \
-739e99cb-c2ec-4718-b900-332502355f38, 153462d0-a9b8-4b5b-8175-9e4b05e9b856 |\
- test at 0 23 * * * for 10800s |
-+--------------------------------------+------------------+-------+----------+\
----------+------------+-------------------------------------------------------\
------------------------------------------------+------------------------------\
---+
-''', sys.stdout.getvalue())
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_time_constraints_compatibility(self):
- # client should be backwards compatible
- alarm_without_tc = dict(self.ALARM[0])
- del alarm_without_tc['time_constraints']
-
- # NOTE(nsaje): Since we're accessing a nonexisting key in the resource,
- # the resource is looking it up with the manager (which is a mock).
- manager_mock = mock.Mock()
- del manager_mock.get
- ret_alarm = [alarms.Alarm(manager_mock, alarm_without_tc)]
- self.cc.query_alarms.query.return_value = ret_alarm
-
- ceilometer_shell.do_query_alarms(self.cc, self.args)
-
- self.assertEqual('''\
-+--------------------------------------+------------------+-------+----------+\
----------+------------+-------------------------------------------------------\
------------------------------------------------+------------------+
-| Alarm ID | Name | State | Severity \
-| Enabled | Continuous | Alarm condition \
- | Time constraints |
-+--------------------------------------+------------------+-------+----------+\
----------+------------+-------------------------------------------------------\
------------------------------------------------+------------------+
-| 768ff714-8cfb-4db9-9753-d484cb33a1cc | SwiftObjectAlarm | ok | critical \
-| True | False | combinated states (OR) of \
-739e99cb-c2ec-4718-b900-332502355f38, 153462d0-a9b8-4b5b-8175-9e4b05e9b856 \
-| None |
-+--------------------------------------+------------------+-------+----------+\
----------+------------+-------------------------------------------------------\
------------------------------------------------+------------------+
-''', sys.stdout.getvalue())
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_query_raises_command_err(self):
- self.cc.query_alarms.query.side_effect = exc.HTTPNotFound
- self.assertRaises(exc.CommandError,
- ceilometer_shell.do_query_alarms,
- self.cc, self.args)
-
-
-class ShellQueryAlarmHistoryCommandTest(utils.BaseTestCase):
-
- ALARM_HISTORY = [{"alarm_id": "e8ff32f772a44a478182c3fe1f7cad6a",
- "event_id": "c74a8611-6553-4764-a860-c15a6aabb5d0",
- "detail":
- "{\"threshold\": 42.0, \"evaluation_periods\": 4}",
- "on_behalf_of": "92159030020611e3b26dde429e99ee8c",
- "project_id": "b6f16144010811e387e4de429e99ee8c",
- "timestamp": "2014-03-11T16:02:58.376261",
- "type": "rule change",
- "user_id": "3e5d11fda79448ac99ccefb20be187ca"
- }]
-
- QUERY = {"filter": {"and": [{">": {"timestamp": "2014-03-11T16:02:58"}},
- {"=": {"type": "rule change"}}]},
- "orderby": [{"timestamp": "desc"}],
- "limit": 10}
-
- def setUp(self):
- super(ShellQueryAlarmHistoryCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.args = mock.Mock()
- self.args.filter = self.QUERY["filter"]
- self.args.orderby = self.QUERY["orderby"]
- self.args.limit = self.QUERY["limit"]
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_query(self):
- ret_alarm_history = [alarms.AlarmChange(mock.Mock(), alarm_history)
- for alarm_history in self.ALARM_HISTORY]
- self.cc.query_alarm_history.query.return_value = ret_alarm_history
-
- ceilometer_shell.do_query_alarm_history(self.cc, self.args)
-
- self.assertEqual('''\
-+----------------------------------+--------------------------------------+-\
-------------+----------------------------------------------+----------------\
-------------+
-| Alarm ID | Event ID | \
-Type | Detail | Timestamp \
- |
-+----------------------------------+--------------------------------------+-\
-------------+----------------------------------------------+----------------\
-------------+
-| e8ff32f772a44a478182c3fe1f7cad6a | c74a8611-6553-4764-a860-c15a6aabb5d0 | \
-rule change | {"threshold": 42.0, "evaluation_periods": 4} | 2014-03-11T16:0\
-2:58.376261 |
-+----------------------------------+--------------------------------------+-\
-------------+----------------------------------------------+----------------\
-------------+
-''', sys.stdout.getvalue())
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_query_raises_command_err(self):
- self.cc.query_alarm_history.query.side_effect = exc.HTTPNotFound
- self.assertRaises(exc.CommandError,
- ceilometer_shell.do_query_alarm_history,
- self.cc, self.args)
-
-
-class ShellStatisticsTest(utils.BaseTestCase):
- def setUp(self):
- super(ShellStatisticsTest, self).setUp()
- self.cc = mock.Mock()
- self.displays = {
- 'duration': 'Duration',
- 'duration_end': 'Duration End',
- 'duration_start': 'Duration Start',
- 'period': 'Period',
- 'period_end': 'Period End',
- 'period_start': 'Period Start',
- 'groupby': 'Group By',
- 'avg': 'Avg',
- 'count': 'Count',
- 'max': 'Max',
- 'min': 'Min',
- 'sum': 'Sum',
- 'stddev': 'Standard deviation',
- 'cardinality': 'Cardinality'
- }
- self.args = mock.Mock()
- self.args.meter_name = 'instance'
- self.args.aggregate = []
- self.args.groupby = None
- self.args.query = None
-
- def test_statistics_list_simple(self):
- samples = [
- {u'count': 135,
- u'duration_start': u'2013-02-04T10:51:42',
- u'min': 1.0,
- u'max': 1.0,
- u'duration_end':
- u'2013-02-05T15:46:09',
- u'duration': 1734.0,
- u'avg': 1.0,
- u'sum': 135.0},
- ]
- fields = [
- 'period',
- 'period_start',
- 'period_end',
- 'max',
- 'min',
- 'avg',
- 'sum',
- 'count',
- 'duration',
- 'duration_start',
- 'duration_end',
- ]
- statistics_ret = [
- statistics.Statistics(mock.Mock(), sample) for sample in samples
- ]
- self.cc.statistics.list.return_value = statistics_ret
- with mock.patch('ceilometerclient.v2.shell.utils.print_list') as pmock:
- ceilometer_shell.do_statistics(self.cc, self.args)
- pmock.assert_called_with(
- statistics_ret,
- fields,
- [self.displays[f] for f in fields]
- )
-
- def test_statistics_list_groupby(self):
- samples = [
- {u'count': 135,
- u'duration_start': u'2013-02-04T10:51:42',
- u'min': 1.0,
- u'max': 1.0,
- u'duration_end':
- u'2013-02-05T15:46:09',
- u'duration': 1734.0,
- u'avg': 1.0,
- u'sum': 135.0,
- u'groupby': {u'resource_id': u'foo'}
- },
- {u'count': 12,
- u'duration_start': u'2013-02-04T10:51:42',
- u'min': 1.0,
- u'max': 1.0,
- u'duration_end':
- u'2013-02-05T15:46:09',
- u'duration': 1734.0,
- u'avg': 1.0,
- u'sum': 12.0,
- u'groupby': {u'resource_id': u'bar'}
- },
- ]
- fields = [
- 'period',
- 'period_start',
- 'period_end',
- 'groupby',
- 'max',
- 'min',
- 'avg',
- 'sum',
- 'count',
- 'duration',
- 'duration_start',
- 'duration_end',
- ]
- self.args.groupby = 'resource_id'
- statistics_ret = [
- statistics.Statistics(mock.Mock(), sample) for sample in samples
- ]
- self.cc.statistics.list.return_value = statistics_ret
- with mock.patch('ceilometerclient.v2.shell.utils.print_list') as pmock:
- ceilometer_shell.do_statistics(self.cc, self.args)
- pmock.assert_called_with(
- statistics_ret,
- fields,
- [self.displays[f] for f in fields],
- )
-
- def test_statistics_list_aggregates(self):
- samples = [
- {u'aggregate': {u'cardinality/resource_id': 4.0, u'count': 2.0},
- u'count': 2,
- u'duration': 0.442451,
- u'duration_end': u'2014-03-12T14:00:21.774154',
- u'duration_start': u'2014-03-12T14:00:21.331703',
- u'groupby': None,
- u'period': 0,
- u'period_end': u'2014-03-12T14:00:21.774154',
- u'period_start': u'2014-03-12T14:00:21.331703',
- u'unit': u'instance',
- },
- ]
- fields = [
- 'period',
- 'period_start',
- 'period_end',
- 'count',
- 'cardinality/resource_id',
- 'duration',
- 'duration_start',
- 'duration_end',
- ]
- self.args.aggregate = ['count', 'cardinality<-resource_id']
- statistics_ret = [
- statistics.Statistics(mock.Mock(), sample) for sample in samples
- ]
- self.cc.statistics.list.return_value = statistics_ret
- with mock.patch('ceilometerclient.v2.shell.utils.print_list') as pmock:
- ceilometer_shell.do_statistics(self.cc, self.args)
- pmock.assert_called_with(
- statistics_ret,
- fields,
- [self.displays.get(f, f) for f in fields],
- )
-
-
-class ShellEmptyIdTest(utils.BaseTestCase):
- """Test empty field which will cause calling incorrect rest uri."""
-
- def _test_entity_action_with_empty_values(self, entity,
- *args, **kwargs):
- positional = kwargs.pop('positional', False)
- for value in ('', ' ', ' ', '\t'):
- self._test_entity_action_with_empty_value(entity, value,
- positional, *args)
-
- def _test_entity_action_with_empty_value(self, entity, value,
- positional, *args):
- new_args = [value] if positional else ['--%s' % entity, value]
- argv = list(args) + new_args
- shell = base_shell.CeilometerShell()
- with mock.patch('ceilometerclient.exc.CommandError') as e:
- e.return_value = exc.BaseException()
- self.assertRaises(exc.BaseException, shell.parse_args, argv)
- entity = entity.replace('-', '_')
- e.assert_called_with('%s should not be empty' % entity)
-
- def _test_alarm_action_with_empty_ids(self, method, *args):
- args = [method] + list(args)
- self._test_entity_action_with_empty_values('alarm_id',
- positional=True, *args)
-
- def test_alarm_show_with_empty_id(self):
- self._test_alarm_action_with_empty_ids('alarm-show')
-
- def test_alarm_update_with_empty_id(self):
- self._test_alarm_action_with_empty_ids('alarm-update')
-
- def test_alarm_threshold_update_with_empty_id(self):
- self._test_alarm_action_with_empty_ids('alarm-threshold-update')
-
- def test_alarm_combination_update_with_empty_id(self):
- self._test_alarm_action_with_empty_ids('alarm-combination-update')
-
- def test_alarm_gnocchi_resources_update_with_empty_id(self):
- self._test_alarm_action_with_empty_ids(
- 'alarm-gnocchi-resources-threshold-update')
-
- def test_alarm_gnocchi_aggr_by_resources_update_with_empty_id(self):
- self._test_alarm_action_with_empty_ids(
- 'alarm-gnocchi-aggregation-by-resources-threshold-update')
-
- def test_alarm_gnocchi_aggr_by_metrics_update_with_empty_id(self):
- self._test_alarm_action_with_empty_ids(
- 'alarm-gnocchi-aggregation-by-metrics-threshold-update')
-
- def test_alarm_delete_with_empty_id(self):
- self._test_alarm_action_with_empty_ids('alarm-delete')
-
- def test_alarm_state_get_with_empty_id(self):
- self._test_alarm_action_with_empty_ids('alarm-state-get')
-
- def test_alarm_state_set_with_empty_id(self):
- args = ['alarm-state-set', '--state', 'ok']
- self._test_alarm_action_with_empty_ids(*args)
-
- def test_alarm_history_with_empty_id(self):
- self._test_alarm_action_with_empty_ids('alarm-history')
-
- def test_event_show_with_empty_message_id(self):
- args = ['event-show']
- self._test_entity_action_with_empty_values('message_id', *args)
-
- def test_resource_show_with_empty_id(self):
- args = ['resource-show']
- self._test_entity_action_with_empty_values('resource_id', *args)
-
- def test_sample_list_with_empty_meter(self):
- args = ['sample-list']
- self._test_entity_action_with_empty_values('meter', *args)
-
- def test_sample_create_with_empty_meter(self):
- args = ['sample-create', '-r', 'x', '--meter-type', 'gauge',
- '--meter-unit', 'B', '--sample-volume', '1']
- self._test_entity_action_with_empty_values('meter-name', *args)
-
- def test_statistics_with_empty_meter(self):
- args = ['statistics']
- self._test_entity_action_with_empty_values('meter', *args)
-
- def test_trait_description_list_with_empty_event_type(self):
- args = ['trait-description-list']
- self._test_entity_action_with_empty_values('event_type', *args)
-
- def test_trait_list_with_empty_event_type(self):
- args = ['trait-list', '--trait_name', 'x']
- self._test_entity_action_with_empty_values('event_type', *args)
-
- def test_trait_list_with_empty_trait_name(self):
- args = ['trait-list', '--event_type', 'x']
- self._test_entity_action_with_empty_values('trait_name', *args)
-
-
-class ShellObsoletedArgsTest(utils.BaseTestCase):
- """Test arguments that have been obsoleted."""
-
- def _test_entity_obsoleted(self, entity, value, positional, *args):
- new_args = [value] if positional else ['--%s' % entity, value]
- argv = list(args) + new_args
- shell = base_shell.CeilometerShell()
- with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout:
- shell.parse_args(argv)
- self.assertIn('obsolete', stdout.getvalue())
-
- def test_obsolete_alarm_id(self):
- for method in ['alarm-show', 'alarm-update', 'alarm-threshold-update',
- 'alarm-combination-update', 'alarm-delete',
- 'alarm-state-get', 'alarm-history']:
- self._test_entity_obsoleted('alarm_id', 'abcde', False, method)
-
-
-class ShellEventListCommandTest(utils.BaseTestCase):
-
- EVENTS = [
- {
- "generated": "2015-01-12T04:03:25.741471",
- "message_id": "fb2bef58-88af-4380-8698-e0f18fcf452d",
- "event_type": "compute.instance.create.start",
- "traits": [{
- "name": "state",
- "type": "string",
- "value": "building",
- }],
- },
- {
- "generated": "2015-01-12T04:03:28.452495",
- "message_id": "9b20509a-576b-4995-acfa-1a24ee5cf49f",
- "event_type": "compute.instance.create.end",
- "traits": [{
- "name": "state",
- "type": "string",
- "value": "active",
- }],
- },
- ]
-
- def setUp(self):
- super(ShellEventListCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.args = mock.Mock()
- self.args.query = None
- self.args.no_traits = None
- self.args.limit = None
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_event_list(self):
- ret_events = [events.Event(mock.Mock(), event)
- for event in self.EVENTS]
- self.cc.events.list.return_value = ret_events
- ceilometer_shell.do_event_list(self.cc, self.args)
- self.assertEqual('''\
-+--------------------------------------+-------------------------------+\
-----------------------------+-------------------------------+
-| Message ID | Event Type |\
- Generated | Traits |
-+--------------------------------------+-------------------------------+\
-----------------------------+-------------------------------+
-| fb2bef58-88af-4380-8698-e0f18fcf452d | compute.instance.create.start |\
- 2015-01-12T04:03:25.741471 | +-------+--------+----------+ |
-| | |\
- | | name | type | value | |
-| | |\
- | +-------+--------+----------+ |
-| | |\
- | | state | string | building | |
-| | |\
- | +-------+--------+----------+ |
-| 9b20509a-576b-4995-acfa-1a24ee5cf49f | compute.instance.create.end |\
- 2015-01-12T04:03:28.452495 | +-------+--------+--------+ |
-| | |\
- | | name | type | value | |
-| | |\
- | +-------+--------+--------+ |
-| | |\
- | | state | string | active | |
-| | |\
- | +-------+--------+--------+ |
-+--------------------------------------+-------------------------------+\
-----------------------------+-------------------------------+
-''', sys.stdout.getvalue())
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_event_list_no_traits(self):
- self.args.no_traits = True
- ret_events = [events.Event(mock.Mock(), event)
- for event in self.EVENTS]
- self.cc.events.list.return_value = ret_events
- ceilometer_shell.do_event_list(self.cc, self.args)
- self.assertEqual('''\
-+--------------------------------------+-------------------------------\
-+----------------------------+
-| Message ID | Event Type \
-| Generated |
-+--------------------------------------+-------------------------------\
-+----------------------------+
-| fb2bef58-88af-4380-8698-e0f18fcf452d | compute.instance.create.start \
-| 2015-01-12T04:03:25.741471 |
-| 9b20509a-576b-4995-acfa-1a24ee5cf49f | compute.instance.create.end \
-| 2015-01-12T04:03:28.452495 |
-+--------------------------------------+-------------------------------\
-+----------------------------+
-''', sys.stdout.getvalue())
-
-
-class ShellShadowedArgsTest(test_shell.ShellTestBase):
-
- def _test_shadowed_args_alarm(self, command, args, method):
- self.make_env(test_shell.FAKE_V2_ENV)
- cli_args = [
- '--os-project-id', '0ba30185ddf44834914a0b859d244c56',
- '--os-user-id', '85f59b3b17484ccb974c50596023bf8c',
- '--debug', command,
- '--project-id', 'the-project-id-i-want-to-set',
- '--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.apiclient.'
- 'client.HTTPClient.client_request') as request:
- request.site_effect = exceptions.EndpointNotFound
- base_shell.main(cli_args)
- args, kwargs = mocked.call_args
- self.assertEqual('the-project-id-i-want-to-set',
- kwargs.get('project_id'))
- self.assertEqual('the-user-id-i-want-to-set',
- kwargs.get('user_id'))
-
- def test_shadowed_args_threshold_alarm(self):
- cli_args = ['--meter-name', 'cpu', '--threshold', '90']
- self._test_shadowed_args_alarm('alarm-create', cli_args, 'create')
- self._test_shadowed_args_alarm('alarm-threshold-create',
- cli_args, 'create')
- cli_args += ['--alarm_id', '437b7ed0-3733-4054-a877-e9a297b8be85']
- self._test_shadowed_args_alarm('alarm-update', cli_args, 'update')
- self._test_shadowed_args_alarm('alarm-threshold-update',
- cli_args, 'update')
-
- def test_shadowed_args_combination_alarm(self):
- cli_args = ['--alarm_ids', 'fb16a05a-669d-414e-8bbe-93aa381df6a8',
- '--alarm_ids', 'b189bcca-0a7b-49a9-a244-a927ac291881']
- self._test_shadowed_args_alarm('alarm-combination-create',
- cli_args, 'create')
- cli_args += ['--alarm_id', '437b7ed0-3733-4054-a877-e9a297b8be85']
- self._test_shadowed_args_alarm('alarm-combination-update',
- cli_args, 'update')
-
- def test_shadowed_args_gnocchi_resources_threshold_alarm(self):
- cli_args = [
- '--metric', 'cpu',
- '--threshold', '80',
- '--resource-type', 'instance',
- '--resource-id', 'fb16a05a-669d-414e-8bbe-93aa381df6a8',
- '--aggregation-method', 'last',
- ]
- self._test_shadowed_args_alarm('alarm-gnocchi-resources-'
- 'threshold-create',
- cli_args, 'create')
- cli_args += ['--alarm_id', '437b7ed0-3733-4054-a877-e9a297b8be85']
- self._test_shadowed_args_alarm('alarm-gnocchi-resources-'
- 'threshold-update',
- cli_args, 'update')
-
- def test_shadowed_args_gnocchi_aggr_by_resources_threshold_alarm(self):
- cli_args = [
- '--metric', 'cpu',
- '--threshold', '80',
- '--resource-type', 'instance',
- '--aggregation-method', 'last',
- '--query', '"server_group":"my_autoscaling_group"',
- ]
- self._test_shadowed_args_alarm('alarm-gnocchi-aggregation-'
- 'by-resources-threshold-create',
- cli_args, 'create')
- cli_args += ['--alarm_id', '437b7ed0-3733-4054-a877-e9a297b8be85']
- self._test_shadowed_args_alarm('alarm-gnocchi-aggregation-'
- 'by-resources-threshold-update',
- cli_args, 'update')
-
- def test_shadowed_args_gnocchi_aggr_by_metrics_threshold_alarm(self):
- cli_args = [
- '-m', 'b3d9d8ab-05e8-439f-89ad-5e978dd2a5eb',
- '-m', '009d4faf-c275-46f0-8f2d-670b15bac2b0',
- '--threshold', '80',
- '--aggregation-method', 'last',
- ]
- self._test_shadowed_args_alarm('alarm-gnocchi-aggregation-'
- 'by-metrics-threshold-create',
- cli_args, 'create')
- cli_args += ['--alarm_id', '437b7ed0-3733-4054-a877-e9a297b8be85']
- self._test_shadowed_args_alarm('alarm-gnocchi-aggregation-'
- 'by-metrics-threshold-update',
- cli_args, 'update')
-
- @mock.patch.object(samples.OldSampleManager, 'create')
- def test_shadowed_args_sample_create(self, mocked):
- self.make_env(test_shell.FAKE_V2_ENV)
- cli_args = [
- '--os-project-id', '0ba30185ddf44834914a0b859d244c56',
- '--os-user-id', '85f59b3b17484ccb974c50596023bf8c',
- '--debug', 'sample-create',
- '--project-id', 'the-project-id-i-want-to-set',
- '--user-id', 'the-user-id-i-want-to-set',
- '--resource-id', 'b666633d-9bb6-4e05-89c0-ee5a8752fb0b',
- '--meter-name', 'cpu',
- '--meter-type', 'cumulative',
- '--meter-unit', 'ns',
- '--sample-volume', '10086',
- ]
- with mock.patch('ceilometerclient.apiclient.client.'
- 'HTTPClient.client_request') as client_request:
- client_request.site_effect = exceptions.EndpointNotFound
- base_shell.main(cli_args)
- args, kwargs = mocked.call_args
- self.assertEqual('the-project-id-i-want-to-set',
- kwargs.get('project_id'))
- self.assertEqual('the-user-id-i-want-to-set',
- kwargs.get('user_id'))
-
-
-class ShellCapabilityShowTest(utils.BaseTestCase):
-
- CAPABILITIES = {
- "alarm_storage": {
- "storage:production_ready": True
- },
- "api": {
- "alarms:query:complex": True,
- "alarms:query:simple": True
- },
- "event_storage": {
- "storage:production_ready": True
- },
- "storage": {
- "storage:production_ready": True
- },
- }
-
- def setUp(self):
- super(ShellCapabilityShowTest, self).setUp()
- self.cc = mock.Mock()
- self.args = mock.Mock()
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_capability_show(self):
- _cap = capabilities.Capabilities(mock.Mock, self.CAPABILITIES)
- self.cc.capabilities.get.return_value = _cap
-
- ceilometer_shell.do_capabilities(self.cc, self.args)
- self.assertEqual('''\
-+---------------+----------------------------------+
-| Property | Value |
-+---------------+----------------------------------+
-| alarm_storage | "storage:production_ready": true |
-| api | "alarms:query:complex": true, |
-| | "alarms:query:simple": true |
-| event_storage | "storage:production_ready": true |
-| storage | "storage:production_ready": true |
-+---------------+----------------------------------+
-''', sys.stdout.getvalue())
-
-
-class ShellMeterListCommandTest(utils.BaseTestCase):
-
- METER = {
- "name": 'image',
- "resource_id": "resource-id",
- "meter": "image",
- "project_id": "project",
- "type": "gauge",
- "unit": "image",
- }
-
- def setUp(self):
- super(ShellMeterListCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.cc.meters.list = mock.Mock()
- self.args = mock.MagicMock()
- self.args.limit = None
- self.args.unique = False
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_meter_list(self):
- meter = meters.Meter(mock.Mock(), self.METER)
- self.cc.meters.list.return_value = [meter]
-
- ceilometer_shell.do_meter_list(self.cc, self.args)
- self.cc.meters.list.assert_called_once_with(q=[], limit=None,
- unique=False)
-
- self.assertEqual('''\
-+-------+-------+-------+-------------+---------+------------+
-| Name | Type | Unit | Resource ID | User ID | Project ID |
-+-------+-------+-------+-------------+---------+------------+
-| image | gauge | image | resource-id | | project |
-+-------+-------+-------+-------------+---------+------------+
-''', sys.stdout.getvalue())
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_unique_meter_list(self):
- self.args.unique = True
- meter = meters.Meter(mock.Mock(), self.METER)
- self.cc.meters.list.return_value = [meter]
-
- ceilometer_shell.do_meter_list(self.cc, self.args)
- self.cc.meters.list.assert_called_once_with(q=[], limit=None,
- unique=True)
-
- self.assertEqual('''\
-+-------+-------+-------+-------------+---------+------------+
-| Name | Type | Unit | Resource ID | User ID | Project ID |
-+-------+-------+-------+-------------+---------+------------+
-| image | gauge | image | resource-id | | project |
-+-------+-------+-------+-------------+---------+------------+
-''', sys.stdout.getvalue())
-
-
-class ShellResourceListCommandTest(utils.BaseTestCase):
-
- RESOURCE = {
- "source": "openstack",
- "resource_id": "resource-id",
- "project_id": "project",
- "user_id": "user"
- }
-
- def setUp(self):
- super(ShellResourceListCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.cc.resources.list = mock.Mock()
- self.args = mock.MagicMock()
- self.args.limit = None
- self.args.meter_links = None
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_resource_list(self):
- resource = resources.Resource(mock.Mock(), self.RESOURCE)
- self.cc.resources.list.return_value = [resource]
- ceilometer_shell.do_resource_list(self.cc, self.args)
- self.cc.resources.list.assert_called_once_with(q=[],
- limit=None)
-
- self.assertEqual('''\
-+-------------+-----------+---------+------------+
-| Resource ID | Source | User ID | Project ID |
-+-------------+-----------+---------+------------+
-| resource-id | openstack | user | project |
-+-------------+-----------+---------+------------+
-''', sys.stdout.getvalue())
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_resource_list_with_links(self):
- resource = resources.Resource(mock.Mock(), self.RESOURCE)
- self.cc.resources.list.return_value = [resource]
- ceilometer_shell.do_resource_list(self.cc, self.args)
- self.cc.resources.list.assert_called_once_with(q=[],
- limit=None)
- self.assertEqual('''\
-+-------------+-----------+---------+------------+
-| Resource ID | Source | User ID | Project ID |
-+-------------+-----------+---------+------------+
-| resource-id | openstack | user | project |
-+-------------+-----------+---------+------------+
-''', sys.stdout.getvalue())
-
-
-class ShellEventTypeListCommandTest(utils.BaseTestCase):
-
- EVENT_TYPE = {
- "event_type": "test_event"
- }
-
- def setUp(self):
- super(ShellEventTypeListCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.cc.event_types.list = mock.Mock()
- self.args = mock.Mock()
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_sample_show(self):
- event_type = event_types.EventType(mock.Mock(), self.EVENT_TYPE)
- self.cc.event_types.list.return_value = [event_type]
-
- ceilometer_shell.do_event_type_list(self.cc, self.args)
- self.cc.event_types.list.assert_called_once_with()
-
- self.assertEqual('''\
-+------------+
-| Event Type |
-+------------+
-| test_event |
-+------------+
-''', sys.stdout.getvalue())
-
-
-class ShellTraitsListCommandTest(utils.BaseTestCase):
-
- TRAIT = {
- "name": "test",
- "value": "test",
- "type": "string",
- }
-
- def setUp(self):
- super(ShellTraitsListCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.cc.traits.list = mock.Mock()
- self.args = mock.Mock()
- self.args.event_type = "test"
- self.args.trait_name = "test"
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_trait_list(self):
- trait = traits.Trait(mock.Mock(), self.TRAIT)
- self.cc.traits.list.return_value = [trait]
-
- ceilometer_shell.do_trait_list(self.cc, self.args)
- self.cc.traits.list.assert_called_once_with(self.args.event_type,
- self.args.trait_name)
-
- self.assertEqual('''\
-+------------+-------+-----------+
-| Trait Name | Value | Data Type |
-+------------+-------+-----------+
-| test | test | string |
-+------------+-------+-----------+
-''', sys.stdout.getvalue())
-
-
-class ShellTraitsDescriptionListCommandTest(utils.BaseTestCase):
-
- TRAIT_DESCRIPTION = {
- "name": "test",
- "type": "string",
- }
-
- def setUp(self):
- super(ShellTraitsDescriptionListCommandTest, self).setUp()
- self.cc = mock.Mock()
- self.cc.trait_descriptions.list = mock.Mock()
- self.args = mock.Mock()
- self.args.event_type = "test"
-
- @mock.patch('sys.stdout', new=six.StringIO())
- def test_traits_description_list(self):
- trait_desc = trait_descriptions.TraitDescription(
- mock.Mock(), self.TRAIT_DESCRIPTION)
- self.cc.trait_descriptions.list.return_value = [trait_desc]
-
- ceilometer_shell.do_trait_description_list(self.cc, self.args)
- self.cc.trait_descriptions.list.assert_called_once_with(
- self.args.event_type)
-
- self.assertEqual('''\
-+------------+-----------+
-| Trait Name | Data Type |
-+------------+-----------+
-| test | string |
-+------------+-----------+
-''', sys.stdout.getvalue())
diff --git a/ceilometerclient/tests/unit/v2/test_statistics.py b/ceilometerclient/tests/unit/v2/test_statistics.py
deleted file mode 100644
index b7924cc..0000000
--- a/ceilometerclient/tests/unit/v2/test_statistics.py
+++ /dev/null
@@ -1,224 +0,0 @@
-# Copyright 2012 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.
-from ceilometerclient.apiclient import client
-from ceilometerclient.apiclient import fake_client
-from ceilometerclient.tests.unit import utils
-import ceilometerclient.v2.statistics
-
-base_url = '/v2/meters/instance/statistics'
-qry = ('q.field=resource_id&q.field=source&q.op=&q.op='
- '&q.type=&q.type=&q.value=foo&q.value=bar')
-period = '&period=60'
-groupby = '&groupby=resource_id'
-aggregate_query = ("aggregate.func=cardinality&aggregate.param=resource_id"
- "&aggregate.func=count")
-samples = [
- {u'count': 135,
- u'duration_start': u'2013-02-04T10:51:42',
- u'min': 1.0,
- u'max': 1.0,
- u'duration_end':
- u'2013-02-05T15:46:09',
- u'duration': 1734.0,
- u'avg': 1.0,
- u'sum': 135.0},
-]
-groupby_samples = [
- {u'count': 135,
- u'duration_start': u'2013-02-04T10:51:42',
- u'min': 1.0,
- u'max': 1.0,
- u'duration_end':
- u'2013-02-05T15:46:09',
- u'duration': 1734.0,
- u'avg': 1.0,
- u'sum': 135.0,
- u'groupby': {u'resource_id': u'foo'}
- },
- {u'count': 12,
- u'duration_start': u'2013-02-04T10:51:42',
- u'min': 1.0,
- u'max': 1.0,
- u'duration_end':
- u'2013-02-05T15:46:09',
- u'duration': 1734.0,
- u'avg': 1.0,
- u'sum': 12.0,
- u'groupby': {u'resource_id': u'bar'}
- },
-]
-aggregate_samples = [
- {u'aggregate': {u'cardinality/resource_id': 4.0, u'count': 2.0},
- u'count': 2,
- u'duration': 0.442451,
- u'duration_end': u'2014-03-12T14:00:21.774154',
- u'duration_start': u'2014-03-12T14:00:21.331703',
- u'groupby': None,
- u'period': 0,
- u'period_end': u'2014-03-12T14:00:21.774154',
- u'period_start': u'2014-03-12T14:00:21.331703',
- u'unit': u'instance',
- },
-]
-fixtures = {
- base_url:
- {
- 'GET': (
- {},
- samples
- ),
- },
- '%s?%s' % (base_url, qry):
- {
- 'GET': (
- {},
- samples
- ),
- },
- '%s?%s%s' % (base_url, qry, period):
- {
- 'GET': (
- {},
- samples
- ),
- },
- '%s?%s%s' % (base_url, qry, groupby):
- {
- 'GET': (
- {},
- groupby_samples
- ),
- },
- '%s?%s' % (base_url, aggregate_query):
- {
- 'GET': (
- {},
- aggregate_samples
- ),
- }
-}
-
-
-class StatisticsManagerTest(utils.BaseTestCase):
-
- def setUp(self):
- super(StatisticsManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
- self.api = client.BaseClient(self.http_client)
- self.mgr = ceilometerclient.v2.statistics.StatisticsManager(self.api)
-
- def test_list_by_meter_name(self):
- stats = list(self.mgr.list(meter_name='instance'))
- expect = [
- 'GET', '/v2/meters/instance/statistics'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(stats))
- self.assertEqual(135, stats[0].count)
-
- def test_list_by_meter_name_extended(self):
- stats = list(self.mgr.list(meter_name='instance',
- q=[
- {"field": "resource_id",
- "value": "foo"},
- {"field": "source",
- "value": "bar"},
- ]))
- expect = [
- 'GET', '%s?%s' % (base_url, qry)
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(stats))
- self.assertEqual(135, stats[0].count)
-
- def test_list_by_meter_name_with_period(self):
- stats = list(self.mgr.list(meter_name='instance',
- q=[
- {"field": "resource_id",
- "value": "foo"},
- {"field": "source",
- "value": "bar"},
- ],
- period=60))
- expect = [
- 'GET', '%s?%s%s' % (base_url, qry, period)
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(stats))
- self.assertEqual(135, stats[0].count)
-
- def test_list_by_meter_name_with_groupby(self):
- stats = list(self.mgr.list(meter_name='instance',
- q=[
- {"field": "resource_id",
- "value": "foo"},
- {"field": "source",
- "value": "bar"},
- ],
- groupby=['resource_id']))
- expect = [
- 'GET',
- '%s?%s%s' % (base_url, qry, groupby)
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(2, len(stats))
- self.assertEqual(135, stats[0].count)
- self.assertEqual(12, stats[1].count)
- self.assertEqual('foo', stats[0].groupby.get('resource_id'))
- self.assertEqual('bar', stats[1].groupby.get('resource_id'))
-
- def test_list_by_meter_name_with_groupby_as_str(self):
- stats = list(self.mgr.list(meter_name='instance',
- q=[
- {"field": "resource_id",
- "value": "foo"},
- {"field": "source",
- "value": "bar"},
- ],
- groupby='resource_id'))
- expect = [
- 'GET',
- '%s?%s%s' % (base_url, qry, groupby)
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(2, len(stats))
- self.assertEqual(135, stats[0].count)
- self.assertEqual(12, stats[1].count)
- self.assertEqual('foo', stats[0].groupby.get('resource_id'))
- self.assertEqual('bar', stats[1].groupby.get('resource_id'))
-
- def test_list_by_meter_name_with_aggregates(self):
- aggregates = [
- {
- 'func': 'count',
- },
- {
- 'func': 'cardinality',
- 'param': 'resource_id',
- },
- ]
- stats = list(self.mgr.list(meter_name='instance',
- aggregates=aggregates))
- expect = [
- 'GET',
- '%s?%s' % (base_url, aggregate_query)
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(1, len(stats))
- self.assertEqual(2, stats[0].count)
- self.assertEqual(2.0, stats[0].aggregate.get('count'))
- self.assertEqual(4.0, stats[0].aggregate.get(
- 'cardinality/resource_id',
- ))
diff --git a/ceilometerclient/tests/unit/v2/test_trait_descriptions.py b/ceilometerclient/tests/unit/v2/test_trait_descriptions.py
deleted file mode 100644
index cd3e4fe..0000000
--- a/ceilometerclient/tests/unit/v2/test_trait_descriptions.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright 2014 Hewlett-Packard Development Company, L.P.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-from ceilometerclient.apiclient import client
-from ceilometerclient.apiclient import fake_client
-from ceilometerclient.tests.unit import utils
-import ceilometerclient.v2.trait_descriptions
-
-
-fixtures = {
- '/v2/event_types/Foo/traits': {
- 'GET': (
- {},
- [
- {'name': 'trait_1', 'type': 'string'},
- {'name': 'trait_2', 'type': 'integer'},
- {'name': 'trait_3', 'type': 'datetime'}
- ]
- ),
- }
-}
-
-
-class TraitDescriptionManagerTest(utils.BaseTestCase):
-
- def setUp(self):
- super(TraitDescriptionManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
- self.api = client.BaseClient(self.http_client)
- self.mgr = (ceilometerclient.v2.trait_descriptions.
- TraitDescriptionManager(self.api))
-
- def test_list(self):
- trait_descriptions = list(self.mgr.list('Foo'))
- expect = [
- 'GET', '/v2/event_types/Foo/traits'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(3, len(trait_descriptions))
- for i, vals in enumerate([('trait_1', 'string'),
- ('trait_2', 'integer'),
- ('trait_3', 'datetime')]):
-
- name, type = vals
- self.assertEqual(trait_descriptions[i].name, name)
- self.assertEqual(trait_descriptions[i].type, type)
diff --git a/ceilometerclient/tests/unit/v2/test_traits.py b/ceilometerclient/tests/unit/v2/test_traits.py
deleted file mode 100644
index 351760b..0000000
--- a/ceilometerclient/tests/unit/v2/test_traits.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright 2014 Hewlett-Packard Development Company, L.P.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-from ceilometerclient.apiclient import client
-from ceilometerclient.apiclient import fake_client
-from ceilometerclient.tests.unit import utils
-import ceilometerclient.v2.traits
-
-
-fixtures = {
- '/v2/event_types/Foo/traits/trait_1': {
- 'GET': (
- {},
- [
- {'name': 'trait_1',
- 'type': 'datetime',
- 'value': '2014-01-07T17:22:10.925553'},
- {'name': 'trait_1',
- 'type': 'datetime',
- 'value': '2014-01-07T17:23:10.925553'}
- ]
- ),
- }
-}
-
-
-class TraitManagerTest(utils.BaseTestCase):
-
- def setUp(self):
- super(TraitManagerTest, self).setUp()
- self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures)
- self.api = client.BaseClient(self.http_client)
- self.mgr = ceilometerclient.v2.traits.TraitManager(self.api)
-
- def test_list(self):
- traits = list(self.mgr.list('Foo', 'trait_1'))
- expect = [
- 'GET', '/v2/event_types/Foo/traits/trait_1'
- ]
- self.http_client.assert_called(*expect)
- self.assertEqual(2, len(traits))
- for i, vals in enumerate([('trait_1',
- 'datetime',
- '2014-01-07T17:22:10.925553'),
- ('trait_1',
- 'datetime',
- '2014-01-07T17:23:10.925553')]):
-
- name, type, value = vals
- self.assertEqual(traits[i].name, name)
- self.assertEqual(traits[i].type, type)
- self.assertEqual(traits[i].value, value)
diff --git a/ceilometerclient/v2/__init__.py b/ceilometerclient/v2/__init__.py
deleted file mode 100644
index e8f350d..0000000
--- a/ceilometerclient/v2/__init__.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2012 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.
-
-from ceilometerclient.v2.client import Client # noqa
diff --git a/ceilometerclient/v2/alarms.py b/ceilometerclient/v2/alarms.py
deleted file mode 100644
index f669624..0000000
--- a/ceilometerclient/v2/alarms.py
+++ /dev/null
@@ -1,185 +0,0 @@
-#
-# Copyright 2013 Red Hat, Inc
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import warnings
-
-from ceilometerclient.common import base
-from ceilometerclient.common import utils
-from ceilometerclient import exc
-from ceilometerclient.v2 import options
-
-
-UPDATABLE_ATTRIBUTES = [
- 'name',
- 'description',
- 'type',
- 'state',
- 'severity',
- 'enabled',
- 'alarm_actions',
- 'ok_actions',
- 'insufficient_data_actions',
- 'repeat_actions',
- 'project_id',
- 'user_id'
-]
-CREATION_ATTRIBUTES = UPDATABLE_ATTRIBUTES + ['time_constraints']
-
-
-class Alarm(base.Resource):
- def __repr__(self):
- return "<Alarm %s>" % self._info
-
- def __getattr__(self, k):
- # Alias to have the Alarm client object
- # that look like the Alarm storage object
- if k == 'rule':
- k = '%s_rule' % self.type
- if k == 'id':
- return self.alarm_id
- return super(Alarm, self).__getattr__(k)
-
- def delete(self):
- return self.manager.delete(self.alarm_id)
-
- def get_state(self):
- state = self.manager.get_state(self.alarm_id)
- return state.get('alarm')
-
-
-class AlarmChange(base.Resource):
- def __repr__(self):
- return "<AlarmChange %s>" % self._info
-
- def __getattr__(self, k):
- return super(AlarmChange, self).__getattr__(k)
-
-
-class AlarmManager(base.Manager):
- resource_class = Alarm
-
- def _path(self, id=None):
- return '/v2/alarms/%s' % id if id else '/v2/alarms'
-
- def list(self, q=None):
- return self._list(options.build_url(self._path(), q))
-
- def get(self, alarm_id):
- try:
- return self._list(self._path(alarm_id), expect_single=True)[0]
- except IndexError:
- return None
-
- except exc.HTTPNotFound:
- # When we try to get a deleted alarm, or
- # when an alarm doesn't exist, HTTPNotFound exception occurs.
- # Since scenario tests at the time of cleanUp() will not know
- # how to handle it, we only return None.
- return None
-
- @classmethod
- def _compat_legacy_alarm_kwargs(cls, kwargs, create=False):
- cls._compat_counter_rename_kwargs(kwargs, create)
- cls._compat_alarm_before_rule_type_kwargs(kwargs, create)
-
- @staticmethod
- def _compat_counter_rename_kwargs(kwargs, create=False):
- # NOTE(jd) Compatibility with Havana-2 API
- if 'counter_name' in kwargs:
- warnings.warn("counter_name has been renamed to meter_name",
- DeprecationWarning)
- kwargs['meter_name'] = kwargs['counter_name']
-
- @staticmethod
- def _compat_alarm_before_rule_type_kwargs(kwargs, create=False):
- # NOTE(sileht) Compatibility with Havana-3 API
- if create and 'type' not in kwargs:
- warnings.warn("alarm without type set is deprecated",
- DeprecationWarning)
- kwargs['type'] = 'threshold'
-
- for field in ['period', 'evaluation_periods', 'threshold',
- 'statistic', 'comparison_operator', 'meter_name']:
- if field in kwargs:
- kwargs.setdefault('threshold_rule', {})[field] = kwargs[field]
- del kwargs[field]
-
- if 'matching_metadata' in kwargs:
- query = []
- for key in kwargs['matching_metadata']:
- query.append({'field': key,
- 'op': 'eq',
- 'value': kwargs['matching_metadata'][key]})
- del kwargs['matching_metadata']
- kwargs['threshold_rule']['query'] = query
-
- @staticmethod
- def _merge_time_constraints(existing_tcs, kwargs):
- new_tcs = kwargs.get('time_constraints', [])
- if not existing_tcs:
- updated_tcs = new_tcs
- else:
- updated_tcs = [dict(tc) for tc in existing_tcs]
- for tc in new_tcs:
- for i, old_tc in enumerate(updated_tcs):
- # if names match, merge
- if old_tc['name'] == tc.get('name'):
- utils.merge_nested_dict(updated_tcs[i], tc)
- break
- else:
- updated_tcs.append(tc)
- tcs_to_remove = kwargs.get('remove_time_constraints', [])
- for tc in updated_tcs:
- if tc.get('name') in tcs_to_remove:
- updated_tcs.remove(tc)
- return updated_tcs
-
- def create(self, **kwargs):
- self._compat_legacy_alarm_kwargs(kwargs, create=True)
- new = dict((key, value) for (key, value) in kwargs.items()
- if (key in CREATION_ATTRIBUTES
- or key.endswith('_rule')))
- return self._create(self._path(), new)
-
- def update(self, alarm_id, **kwargs):
- self._compat_legacy_alarm_kwargs(kwargs)
- alarm = self.get(alarm_id)
- if alarm is None:
- raise exc.CommandError('Alarm not found: %s' % alarm_id)
- updated = alarm.to_dict()
- updated['time_constraints'] = self._merge_time_constraints(
- updated.get('time_constraints', []), kwargs)
- kwargs = dict((k, v) for k, v in kwargs.items()
- if k in updated and (k in UPDATABLE_ATTRIBUTES
- or k.endswith('_rule')))
- utils.merge_nested_dict(updated, kwargs, depth=1)
- return self._update(self._path(alarm_id), updated)
-
- def delete(self, alarm_id):
- return self._delete(self._path(alarm_id))
-
- def set_state(self, alarm_id, state):
- body = self.api.put("%s/state" % self._path(alarm_id),
- json=state).json()
- return body
-
- def get_state(self, alarm_id):
- body = self.api.get("%s/state" % self._path(alarm_id)).json()
- return body
-
- def get_history(self, alarm_id, q=None):
- path = '%s/history' % self._path(alarm_id)
- url = options.build_url(path, q)
- return self._list(url, obj_class=AlarmChange)
diff --git a/ceilometerclient/v2/capabilities.py b/ceilometerclient/v2/capabilities.py
deleted file mode 100644
index 9a0f528..0000000
--- a/ceilometerclient/v2/capabilities.py
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Copyright 2014 Huawei, Inc
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from ceilometerclient.common import base
-
-
-class Capabilities(base.Resource):
- def __repr__(self):
- return "<Capabilities %s>" % self._info
-
-
-class CapabilitiesManager(base.Manager):
- resource_class = Capabilities
-
- def get(self):
- path = "/v2/capabilities"
- return Capabilities(self, self.api.get(path).json())
diff --git a/ceilometerclient/v2/client.py b/ceilometerclient/v2/client.py
deleted file mode 100644
index e61e43f..0000000
--- a/ceilometerclient/v2/client.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# Copyright Ericsson AB 2014. All rights reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-import copy
-
-import requests
-
-from ceilometerclient import client as ceiloclient
-from ceilometerclient.v2 import alarms
-from ceilometerclient.v2 import capabilities
-from ceilometerclient.v2 import event_types
-from ceilometerclient.v2 import events
-from ceilometerclient.v2 import meters
-from ceilometerclient.v2 import query
-from ceilometerclient.v2 import resources
-from ceilometerclient.v2 import samples
-from ceilometerclient.v2 import statistics
-from ceilometerclient.v2 import trait_descriptions
-from ceilometerclient.v2 import traits
-from keystoneauth1 import exceptions as ka_exc
-
-
-class Client(object):
- """Client for the Ceilometer v2 API.
-
- :param session: a keystoneauth session object
- :type session: keystoneauth1.session.Session
- :param str service_type: The default service_type for URL discovery
- :param str service_name: The default service_name for URL discovery
- :param str interface: The default interface for URL discovery
- (Default: public)
- :param str region_name: The default region_name for URL discovery
- :param str endpoint_override: Always use this endpoint URL for requests
- for this ceiloclient
- :param auth: An auth plugin to use instead of the session one
- :type auth: keystoneauth1.plugin.BaseAuthPlugin
- :param str user_agent: The User-Agent string to set
- (Default is python-ceilometer-client)
- :param int connect_retries: the maximum number of retries that should be
- attempted for connection errors
- :param logger: A logging object
- :type logger: logging.Logger
- """
-
- def __init__(self, *args, **kwargs):
- """Initialize a new client for the Ceilometer v2 API."""
-
- if not kwargs.get('auth_plugin') and not kwargs.get('session'):
- kwargs['auth_plugin'] = ceiloclient.get_auth_plugin(*args,
- **kwargs)
-
- self.auth_plugin = kwargs.get('auth_plugin')
-
- self.http_client = ceiloclient._construct_http_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)
- 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.event_client)
-
- self.query_samples = query.QuerySamplesManager(
- self.http_client)
- self.query_alarms = query.QueryAlarmsManager(self.alarm_client)
- self.query_alarm_history = query.QueryAlarmHistoryManager(
- self.alarm_client)
- self.capabilities = capabilities.CapabilitiesManager(self.http_client)
-
- @staticmethod
- 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"] = 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 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(
- 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. Same applies to panko.
- return None
-
- try:
- # NOTE(sileht): try to use redirect
- c = ceiloclient._construct_http_client(**kwargs)
- c.get("/")
- return c
- except ka_exc.EndpointNotFound:
- return None
- except requests.exceptions.ConnectionError:
- return None
diff --git a/ceilometerclient/v2/event_types.py b/ceilometerclient/v2/event_types.py
deleted file mode 100644
index 0f44931..0000000
--- a/ceilometerclient/v2/event_types.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2014 Hewlett-Packard Development Company, L.P.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from ceilometerclient.common import base
-
-
-class EventType(base.Resource):
- def __repr__(self):
- return "<EventType %s>" % self._info
-
-
-def object_class_str(mgr, value, loaded):
- return EventType(mgr, {"event_type": value}, loaded)
-
-
-class EventTypeManager(base.Manager):
-
- def list(self):
- return self._list('/v2/event_types', obj_class=object_class_str)
diff --git a/ceilometerclient/v2/events.py b/ceilometerclient/v2/events.py
deleted file mode 100644
index 6cd46d2..0000000
--- a/ceilometerclient/v2/events.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2014 Hewlett-Packard Development Company, L.P.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from ceilometerclient.common import base
-from ceilometerclient.v2 import options
-
-
-class Event(base.Resource):
- def __repr__(self):
- return "<Event %s>" % self._info
-
- def __getattr__(self, k):
- if k == 'id':
- return self.message_id
- return super(Event, self).__getattr__(k)
-
-
-class EventManager(base.Manager):
- resource_class = Event
-
- def list(self, q=None, limit=None):
- path = '/v2/events'
- params = ['limit=%s' % limit] if limit else None
- return self._list(options.build_url(path, q, params))
-
- def get(self, message_id):
- path = '/v2/events/%s'
- try:
- return self._list(path % message_id, expect_single=True)[0]
- except IndexError:
- return None
diff --git a/ceilometerclient/v2/meters.py b/ceilometerclient/v2/meters.py
deleted file mode 100644
index 015c04c..0000000
--- a/ceilometerclient/v2/meters.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Copyright 2013 Red Hat, Inc
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from ceilometerclient.common import base
-from ceilometerclient.v2 import options
-
-
-class Meter(base.Resource):
- def __repr__(self):
- return "<Meter %s>" % self._info
-
-
-class MeterManager(base.Manager):
- resource_class = Meter
-
- def list(self, q=None, limit=None, unique=False):
- path = '/v2/meters'
- params = []
-
- if limit:
- params.append('limit=%s' % limit)
-
- if unique:
- params.append('unique=%s' % str(unique))
-
- return self._list(options.build_url(path, q, params))
diff --git a/ceilometerclient/v2/options.py b/ceilometerclient/v2/options.py
deleted file mode 100644
index b586542..0000000
--- a/ceilometerclient/v2/options.py
+++ /dev/null
@@ -1,129 +0,0 @@
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import re
-
-from six.moves import urllib
-
-OP_LOOKUP = {'!=': 'ne',
- '>=': 'ge',
- '<=': 'le',
- '>': 'gt',
- '<': 'lt',
- '=': 'eq'}
-
-OP_LOOKUP_KEYS = '|'.join(sorted(OP_LOOKUP.keys(), key=len, reverse=True))
-OP_SPLIT_RE = re.compile(r'(%s)' % OP_LOOKUP_KEYS)
-
-DATA_TYPE_RE = re.compile(r'^(string|integer|float|datetime|boolean)(::)(.+)$')
-
-
-def build_url(path, q, params=None):
- """Convert list of dicts and a list of params to query url format.
-
- This will convert the following:
- "[{field=this,op=le,value=34},
- {field=that,op=eq,value=foo,type=string}],
- ['foo=bar','sna=fu']"
- to:
- "?q.field=this&q.field=that&
- q.op=le&q.op=eq&
- q.type=&q.type=string&
- q.value=34&q.value=foo&
- foo=bar&sna=fu"
- """
- if q:
- query_params = {'q.field': [],
- 'q.value': [],
- 'q.op': [],
- 'q.type': []}
-
- for query in q:
- for name in ['field', 'op', 'value', 'type']:
- query_params['q.%s' % name].append(query.get(name, ''))
-
- # Transform the dict to a sequence of two-element tuples in fixed
- # order, then the encoded string will be consistent in Python 2&3.
- new_qparams = sorted(query_params.items(), key=lambda x: x[0])
- path += "?" + urllib.parse.urlencode(new_qparams, doseq=True)
-
- if params:
- for p in params:
- path += '&%s' % p
- elif params:
- path += '?%s' % params[0]
- for p in params[1:]:
- path += '&%s' % p
- return path
-
-
-def cli_to_array(cli_query):
- """Convert CLI list of queries to the Python API format.
-
- This will convert the following:
- "this<=34;that=string::foo"
- to
- "[{field=this,op=le,value=34,type=''},
- {field=that,op=eq,value=foo,type=string}]"
-
- """
-
- if cli_query is None:
- return None
-
- def split_by_op(query):
- """Split a single query string to field, operator, value."""
-
- def _value_error(message):
- raise ValueError('invalid query %(query)s: missing %(message)s' %
- {'query': query, 'message': message})
-
- try:
- field, operator, value = OP_SPLIT_RE.split(query, maxsplit=1)
- except ValueError:
- _value_error('operator')
-
- if not len(field):
- _value_error('field')
-
- if not len(value):
- _value_error('value')
-
- return field.strip(), operator, value.strip()
-
- def split_by_data_type(query_value):
- frags = DATA_TYPE_RE.match(query_value)
-
- # The second match is the separator. Return a list without it if
- # a type identifier was found.
- return frags.group(1, 3) if frags else None
-
- opts = []
- queries = cli_query.split(';')
- for q in queries:
- query = split_by_op(q)
- opt = {}
- opt['field'] = query[0]
- opt['op'] = OP_LOOKUP[query[1]]
-
- # Allow the data type of the value to be specified via <type>::<value>,
- # where type can be one of integer, string, float, datetime, boolean
- value_frags = split_by_data_type(query[2])
- if not value_frags:
- opt['value'] = query[2]
- opt['type'] = ''
- else:
- opt['type'] = value_frags[0]
- opt['value'] = value_frags[1]
- opts.append(opt)
- return opts
diff --git a/ceilometerclient/v2/query.py b/ceilometerclient/v2/query.py
deleted file mode 100644
index 9d540b2..0000000
--- a/ceilometerclient/v2/query.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright Ericsson AB 2014. 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.
-
-from ceilometerclient.common import base
-from ceilometerclient.v2 import alarms
-from ceilometerclient.v2 import samples
-
-
-class QueryManager(base.Manager):
- path_suffix = None
-
- def query(self, filter=None, orderby=None, limit=None):
- query = {}
- if filter:
- query["filter"] = filter
- if orderby:
- query["orderby"] = orderby
- if limit:
- query["limit"] = limit
-
- url = '/v2/query%s' % self.path_suffix
-
- body = self.api.post(url, json=query).json()
-
- if body:
- return [self.resource_class(self, b) for b in body]
- else:
- return []
-
-
-class QuerySamplesManager(QueryManager):
- resource_class = samples.Sample
- path_suffix = '/samples'
-
-
-class QueryAlarmsManager(QueryManager):
- resource_class = alarms.Alarm
- path_suffix = '/alarms'
-
-
-class QueryAlarmHistoryManager(QueryManager):
- resource_class = alarms.AlarmChange
- path_suffix = '/alarms/history'
diff --git a/ceilometerclient/v2/resources.py b/ceilometerclient/v2/resources.py
deleted file mode 100644
index d516ee1..0000000
--- a/ceilometerclient/v2/resources.py
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# Copyright 2013 Red Hat, Inc
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from ceilometerclient.common import base
-from ceilometerclient.v2 import options
-
-
-class Resource(base.Resource):
- def __repr__(self):
- return "<Resource %s>" % self._info
-
- def __getattr__(self, k):
- if k == 'id':
- return self.resource_id
- return super(Resource, self).__getattr__(k)
-
-
-class ResourceManager(base.Manager):
- resource_class = Resource
-
- def list(self, q=None, links=None, limit=None):
- path = '/v2/resources'
- params = ['meter_links=%d' % (1 if links else 0)]
- if limit:
- params.append('limit=%s' % limit)
- return self._list(options.build_url(path, q, params))
-
- def get(self, resource_id):
- path = '/v2/resources/%s' % resource_id
- try:
- return self._list(path, expect_single=True)[0]
- except IndexError:
- return None
diff --git a/ceilometerclient/v2/samples.py b/ceilometerclient/v2/samples.py
deleted file mode 100644
index 8752a0d..0000000
--- a/ceilometerclient/v2/samples.py
+++ /dev/null
@@ -1,106 +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.
-
-from ceilometerclient.common import base
-from ceilometerclient.v2 import options
-
-CREATION_ATTRIBUTES = ('source',
- 'counter_name',
- 'counter_type',
- 'counter_unit',
- 'counter_volume',
- 'user_id',
- 'project_id',
- 'resource_id',
- 'timestamp',
- 'resource_metadata')
-
-
-class OldSample(base.Resource):
- """Represents API v2 OldSample object.
-
- Model definition:
- https://docs.openstack.org/ceilometer/latest/webapi/v2.html#OldSample
- """
- def __repr__(self):
- return "<OldSample %s>" % self._info
-
-
-class OldSampleManager(base.Manager):
- resource_class = OldSample
-
- @staticmethod
- def _path(counter_name=None):
- return '/v2/meters/%s' % counter_name if counter_name else '/v2/meters'
-
- def list(self, meter_name=None, q=None, limit=None):
- path = self._path(counter_name=meter_name)
- params = ['limit=%s' % str(limit)] if limit else None
- return self._list(options.build_url(path, q, params))
-
- def create(self, **kwargs):
- direct = kwargs.pop('direct', False)
- new = dict((key, value) for (key, value) in kwargs.items()
- if key in CREATION_ATTRIBUTES)
- url = self._path(counter_name=kwargs['counter_name'])+(
- '?direct=%s' % (str(direct)) if direct else '')
- body = self.api.post(url, json=[new]).json()
- if body:
- return [OldSample(self, b) for b in body]
-
- def create_list(self, sample_list=None, **kwargs):
- sample_dict = {}
- direct = kwargs.pop('direct', False)
-
- for sample_body in sample_list:
- sample = dict((key, value) for (key, value) in sample_body.items()
- if key in CREATION_ATTRIBUTES)
- sample_dict.setdefault(
- sample_body["counter_name"], []
- ).append(sample)
-
- sample_return_list = []
-
- for (counter_name, sample_body) in sample_dict.items():
- url = self._path(counter_name=counter_name)+(
- '?direct=%s' % (str(direct)) if direct else '')
- body = self.api.post(url, json=sample_body).json()
-
- if body:
- sample_return_list.extend([OldSample(self, b) for b in body])
- return sample_return_list
-
-
-class Sample(base.Resource):
- """Represents API v2 Sample object.
-
- Model definition:
- https://docs.openstack.org/ceilometer/latest/webapi/v2.html#Sample
- """
- def __repr__(self):
- return "<Sample %s>" % self._info
-
-
-class SampleManager(base.Manager):
- resource_class = Sample
-
- def list(self, q=None, limit=None):
- params = ['limit=%s' % str(limit)] if limit else None
- return self._list(options.build_url("/v2/samples", q, params))
-
- def get(self, sample_id):
- path = "/v2/samples/" + sample_id
- try:
- return self._list(path, expect_single=True)[0]
- except IndexError:
- return None
diff --git a/ceilometerclient/v2/shell.py b/ceilometerclient/v2/shell.py
deleted file mode 100644
index ca9e264..0000000
--- a/ceilometerclient/v2/shell.py
+++ /dev/null
@@ -1,1285 +0,0 @@
-#
-# 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
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import argparse
-import functools
-import json
-import warnings
-
-from oslo_serialization import jsonutils
-from oslo_utils import strutils
-import six
-from six import moves
-
-from ceilometerclient.common import utils
-from ceilometerclient import exc
-from ceilometerclient.v2 import options
-
-
-ALARM_STATES = ['ok', 'alarm', 'insufficient data']
-ALARM_SEVERITY = ['low', 'moderate', 'critical']
-ALARM_OPERATORS = ['lt', 'le', 'eq', 'ne', 'ge', 'gt']
-ALARM_COMBINATION_OPERATORS = ['and', 'or']
-STATISTICS = ['max', 'min', 'avg', 'sum', 'count']
-GNOCCHI_AGGREGATION = ['last', 'min', 'median', 'sum',
- 'std', 'first', 'mean', 'count',
- 'moving-average', 'max']
-GNOCCHI_AGGREGATION.extend(['%spct' % num for num in moves.xrange(1, 100)])
-
-AGGREGATES = {'avg': 'Avg',
- 'count': 'Count',
- 'max': 'Max',
- 'min': 'Min',
- 'sum': 'Sum',
- 'stddev': 'Standard deviation',
- 'cardinality': 'Cardinality'}
-OPERATORS_STRING = dict(gt='>', ge='>=',
- lt='<', le="<=",
- eq='==', ne='!=')
-ORDER_DIRECTIONS = ['asc', 'desc']
-COMPLEX_OPERATORS = ['and', 'or']
-SIMPLE_OPERATORS = ["=", "!=", "<", "<=", '>', '>=']
-
-DEFAULT_API_LIMIT = ('API server limits result to <default_api_return_limit> '
- 'rows if no limit provided. Option is configured in '
- 'ceilometer.conf [api] group')
-
-
-class NotEmptyAction(argparse.Action):
- def __call__(self, parser, namespace, values, option_string=None):
- values = values or getattr(namespace, self.dest)
- if not values or values.isspace():
- raise exc.CommandError('%s should not be empty' % self.dest)
- setattr(namespace, self.dest, values)
-
-
-def obsoleted_by(new_dest):
- class ObsoletedByAction(argparse.Action):
- def __call__(self, parser, namespace, values, option_string=None):
- old_dest = option_string or self.dest
- print('%s is obsolete! See help for more details.' % old_dest)
- setattr(namespace, new_dest, values)
- return ObsoletedByAction
-
-
-@utils.arg('-q', '--query', metavar='<QUERY>',
- help='key[op]data_type::value; list. data_type is optional, '
- 'but if supplied must be string, integer, float, or boolean.')
-@utils.arg('-m', '--meter', metavar='<NAME>', required=True,
- action=NotEmptyAction, help='Name of meter to list statistics for.')
-@utils.arg('-p', '--period', metavar='<PERIOD>',
- help='Period in seconds over which to group samples.')
-@utils.arg('-g', '--groupby', metavar='<FIELD>', action='append',
- help='Field for group by.')
-@utils.arg('-a', '--aggregate', metavar='<FUNC>[<-<PARAM>]', action='append',
- default=[], help=('Function for data aggregation. '
- 'Available aggregates are: '
- '%s.' % ", ".join(AGGREGATES.keys())))
-def do_statistics(cc, args):
- """List the statistics for a meter."""
- aggregates = []
- for a in args.aggregate:
- aggregates.append(dict(zip(('func', 'param'), a.split("<-"))))
- api_args = {'meter_name': args.meter,
- 'q': options.cli_to_array(args.query),
- 'period': args.period,
- 'groupby': args.groupby,
- 'aggregates': aggregates}
- try:
- statistics = cc.statistics.list(**api_args)
- except exc.HTTPNotFound:
- raise exc.CommandError('Samples not found: %s' % args.meter)
- else:
- fields_display = {'duration': 'Duration',
- 'duration_end': 'Duration End',
- 'duration_start': 'Duration Start',
- 'period': 'Period',
- 'period_end': 'Period End',
- 'period_start': 'Period Start',
- 'groupby': 'Group By'}
- fields_display.update(AGGREGATES)
- fields = ['period', 'period_start', 'period_end']
- if args.groupby:
- fields.append('groupby')
- if args.aggregate:
- for a in aggregates:
- if 'param' in a:
- fields.append("%(func)s/%(param)s" % a)
- else:
- fields.append(a['func'])
- for stat in statistics:
- stat.__dict__.update(stat.aggregate)
- else:
- fields.extend(['max', 'min', 'avg', 'sum', 'count'])
- fields.extend(['duration', 'duration_start', 'duration_end'])
- cols = [fields_display.get(f, f) for f in fields]
- utils.print_list(statistics, fields, cols)
-
-
-@utils.arg('-q', '--query', metavar='<QUERY>',
- help='key[op]data_type::value; list. data_type is optional, '
- 'but if supplied must be string, integer, float, or boolean.')
-@utils.arg('-m', '--meter', metavar='<NAME>',
- action=NotEmptyAction, help='Name of meter to show samples for.')
-@utils.arg('-l', '--limit', metavar='<NUMBER>',
- help='Maximum number of samples to return. %s' % DEFAULT_API_LIMIT)
-def do_sample_list(cc, args):
- """List the samples (return OldSample objects if -m/--meter is set)."""
- if not args.meter:
- return _do_sample_list(cc, args)
- else:
- return _do_old_sample_list(cc, args)
-
-
-def _do_old_sample_list(cc, args):
- fields = {'meter_name': args.meter,
- 'q': options.cli_to_array(args.query),
- 'limit': args.limit}
- try:
- samples = cc.samples.list(**fields)
- except exc.HTTPNotFound:
- raise exc.CommandError('Samples not found: %s' % args.meter)
- else:
- field_labels = ['Resource ID', 'Name', 'Type', 'Volume', 'Unit',
- 'Timestamp']
- fields = ['resource_id', 'counter_name', 'counter_type',
- 'counter_volume', 'counter_unit', 'timestamp']
- utils.print_list(samples, fields, field_labels, sortby=None)
-
-
-def _do_sample_list(cc, args):
- fields = {
- 'q': options.cli_to_array(args.query),
- 'limit': args.limit
- }
- samples = cc.new_samples.list(**fields)
- field_labels = ['ID', 'Resource ID', 'Name', 'Type', 'Volume', 'Unit',
- 'Timestamp']
- fields = ['id', 'resource_id', 'meter', 'type', 'volume', 'unit',
- 'timestamp']
- utils.print_list(samples, fields, field_labels, sortby=None)
-
-
-@utils.arg('sample_id', metavar='<SAMPLE_ID>', action=NotEmptyAction,
- help='ID (aka message ID) of the sample to show.')
-def do_sample_show(cc, args):
- '''Show a sample.'''
- try:
- sample = cc.new_samples.get(args.sample_id)
- except exc.HTTPNotFound:
- raise exc.CommandError('Sample not found: %s' % args.sample_id)
-
- fields = ['id', 'meter', 'volume', 'type', 'unit', 'source',
- 'resource_id', 'user_id', 'project_id',
- 'timestamp', 'recorded_at', 'metadata']
- data = dict((f, getattr(sample, f, '')) for f in fields)
- utils.print_dict(data, wrap=72)
-
-
-def _restore_shadowed_arg(shadowed, observed):
- def wrapper(func):
- @functools.wraps(func)
- def wrapped(cc, args):
- v = getattr(args, observed, None)
- setattr(args, shadowed, v)
- return func(cc, args)
- return wrapped
- return wrapper
-
-
-@utils.arg('--project-id', metavar='<SAMPLE_PROJECT_ID>',
- dest='sample_project_id',
- help='Tenant to associate with sample '
- '(configurable by admin users only).')
-@utils.arg('--user-id', metavar='<SAMPLE_USER_ID>',
- dest='sample_user_id',
- help='User to associate with sample '
- '(configurable by admin users only).')
-@utils.arg('-r', '--resource-id', metavar='<RESOURCE_ID>', required=True,
- help='ID of the resource.')
-@utils.arg('-m', '--meter-name', metavar='<METER_NAME>', required=True,
- action=NotEmptyAction, help='The meter name.')
-@utils.arg('--meter-type', metavar='<METER_TYPE>', required=True,
- help='The meter type.')
-@utils.arg('--meter-unit', metavar='<METER_UNIT>', required=True,
- help='The meter unit.')
-@utils.arg('--sample-volume', metavar='<SAMPLE_VOLUME>', required=True,
- help='The sample volume.')
-@utils.arg('--resource-metadata', metavar='<RESOURCE_METADATA>',
- help='Resource metadata. Provided value should be a set of '
- 'key-value pairs e.g. {"key":"value"}.')
-@utils.arg('--timestamp', metavar='<TIMESTAMP>',
- help='The sample timestamp.')
-@utils.arg('--direct', metavar='<DIRECT>', default=False,
- help='Post sample to storage directly.')
-@_restore_shadowed_arg('project_id', 'sample_project_id')
-@_restore_shadowed_arg('user_id', 'sample_user_id')
-def do_sample_create(cc, args={}):
- """Create a sample."""
- arg_to_field_mapping = {
- 'meter_name': 'counter_name',
- 'meter_unit': 'counter_unit',
- 'meter_type': 'counter_type',
- 'sample_volume': 'counter_volume',
- }
- fields = {}
- for var in vars(args).items():
- k, v = var[0], var[1]
- if v is not None:
- if k == 'resource_metadata':
- try:
- fields[k] = json.loads(v)
- except ValueError:
- msg = ('Invalid resource metadata, it should be a json'
- ' string, like: \'{"foo":"bar"}\'')
- raise exc.CommandError(msg)
- else:
- fields[arg_to_field_mapping.get(k, k)] = v
- sample = cc.samples.create(**fields)
- fields = ['counter_name', 'user_id', 'resource_id',
- 'timestamp', 'message_id', 'source', 'counter_unit',
- 'counter_volume', 'project_id', 'resource_metadata',
- 'counter_type']
- data = dict([(f.replace('counter_', ''), getattr(sample[0], f, ''))
- for f in fields])
- utils.print_dict(data, wrap=72)
-
-
-@utils.arg('-q', '--query', metavar='<QUERY>',
- help='key[op]data_type::value; list. data_type is optional, '
- 'but if supplied must be string, integer, float, or boolean.')
-@utils.arg('-l', '--limit', metavar='<NUMBER>',
- help='Maximum number of meters to return. %s' % DEFAULT_API_LIMIT)
-@utils.arg('--unique', dest='unique',
- metavar='{True|False}',
- type=lambda v: strutils.bool_from_string(v, True),
- help='Retrieves unique list of meters.')
-def do_meter_list(cc, args={}):
- """List the user's meters."""
- meters = cc.meters.list(q=options.cli_to_array(args.query),
- limit=args.limit, unique=args.unique)
- field_labels = ['Name', 'Type', 'Unit', 'Resource ID', 'User ID',
- 'Project ID']
- fields = ['name', 'type', 'unit', 'resource_id', 'user_id',
- 'project_id']
- utils.print_list(meters, fields, field_labels,
- sortby=0)
-
-
-@utils.arg('samples_list', metavar='<SAMPLES_LIST>', action=NotEmptyAction,
- help='Json array with samples to create.')
-@utils.arg('--direct', metavar='<DIRECT>', default=False,
- help='Post samples to storage directly.')
-def do_sample_create_list(cc, args={}):
- """Create a sample list."""
- sample_list_array = json.loads(args.samples_list)
- samples = cc.samples.create_list(sample_list_array, direct=args.direct)
- field_labels = ['Resource ID', 'Name', 'Type', 'Volume', 'Unit',
- 'Timestamp']
- fields = ['resource_id', 'counter_name', 'counter_type',
- 'counter_volume', 'counter_unit', 'timestamp']
- utils.print_list(samples, fields, field_labels, sortby=None)
-
-
-def _display_alarm_list(alarms, sortby=None):
- # omit action initially to keep output width sane
- # (can switch over to vertical formatting when available from CLIFF)
- field_labels = ['Alarm ID', 'Name', 'State', 'Severity', 'Enabled',
- 'Continuous', 'Alarm condition', 'Time constraints']
- fields = ['alarm_id', 'name', 'state', 'severity', 'enabled',
- 'repeat_actions', 'rule', 'time_constraints']
- utils.print_list(
- alarms, fields, field_labels,
- formatters={'rule': alarm_rule_formatter,
- 'time_constraints': time_constraints_formatter_brief},
- sortby=sortby)
-
-
-def _display_rule(type, rule):
- if type == 'threshold':
- return ('%(statistic)s(%(meter_name)s) %(comparison_operator)s '
- '%(threshold)s during %(evaluation_periods)s x %(period)ss' %
- {
- 'meter_name': rule['meter_name'],
- 'threshold': rule['threshold'],
- 'statistic': rule['statistic'],
- 'evaluation_periods': rule['evaluation_periods'],
- 'period': rule['period'],
- 'comparison_operator': OPERATORS_STRING.get(
- rule['comparison_operator'])
- })
- elif type == 'combination':
- return ('combinated states (%(operator)s) of %(alarms)s' % {
- 'operator': rule['operator'].upper(),
- 'alarms': ", ".join(rule['alarm_ids'])})
- else:
- # just dump all
- return "\n".join(["%s: %s" % (f, v)
- for f, v in six.iteritems(rule)])
-
-
-def alarm_rule_formatter(alarm):
- return _display_rule(alarm.type, alarm.rule)
-
-
-def _display_time_constraints_brief(time_constraints):
- if time_constraints:
- return ', '.join('%(name)s at %(start)s %(timezone)s for %(duration)ss'
- % {
- 'name': tc['name'],
- 'start': tc['start'],
- 'duration': tc['duration'],
- 'timezone': tc.get('timezone', '')
- }
- for tc in time_constraints)
- else:
- return 'None'
-
-
-def time_constraints_formatter_brief(alarm):
- return _display_time_constraints_brief(getattr(alarm,
- 'time_constraints',
- None))
-
-
-def _infer_type(detail):
- if 'type' in detail:
- return detail['type']
- elif 'meter_name' in detail['rule']:
- return 'threshold'
- elif 'alarms' in detail['rule']:
- return 'combination'
- else:
- return 'unknown'
-
-
-def alarm_change_detail_formatter(change):
- detail = json.loads(change.detail)
- fields = []
- if change.type == 'state transition':
- fields.append('state: %s' % detail['state'])
- elif change.type == 'creation' or change.type == 'deletion':
- for k in ['name', 'description', 'type', 'rule', 'severity']:
- if k == 'rule':
- fields.append('rule: %s' % _display_rule(detail['type'],
- detail[k]))
- else:
- fields.append('%s: %s' % (k, detail[k]))
- if 'time_constraints' in detail:
- fields.append('time_constraints: %s' %
- _display_time_constraints_brief(
- detail['time_constraints']))
- elif change.type == 'rule change':
- for k, v in six.iteritems(detail):
- if k == 'rule':
- fields.append('rule: %s' % _display_rule(_infer_type(detail),
- v))
- else:
- fields.append('%s: %s' % (k, v))
- return '\n'.join(fields)
-
-
-@utils.arg('-q', '--query', metavar='<QUERY>',
- help='key[op]data_type::value; list. data_type is optional, '
- '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)
-
-
-def alarm_query_formater(alarm):
- qs = []
- for q in alarm.rule['query']:
- qs.append('%s %s %s' % (
- q['field'], OPERATORS_STRING.get(q['op']), q['value']))
- return r' AND\n'.join(qs)
-
-
-def time_constraints_formatter_full(alarm):
- time_constraints = []
- for tc in alarm.time_constraints:
- lines = []
- for k in ['name', 'description', 'start', 'duration', 'timezone']:
- if k in tc and tc[k]:
- lines.append(r'%s: %s' % (k, tc[k]))
- time_constraints.append('{' + r',\n '.join(lines) + '}')
- return '[' + r',\n '.join(time_constraints) + ']'
-
-
-def _display_alarm(alarm):
- fields = ['name', 'description', 'type',
- 'state', 'severity', 'enabled', 'alarm_id', 'user_id',
- 'project_id', 'alarm_actions', 'ok_actions',
- 'insufficient_data_actions', 'repeat_actions']
- data = dict([(f, getattr(alarm, f, '')) for f in fields])
- data.update(alarm.rule)
- if alarm.type == 'threshold':
- data['query'] = alarm_query_formater(alarm)
- if alarm.time_constraints:
- data['time_constraints'] = time_constraints_formatter_full(alarm)
- utils.print_dict(data, wrap=72)
-
-
-@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
- action=obsoleted_by('alarm_id'), help=argparse.SUPPRESS,
- dest='alarm_id_deprecated')
-@utils.arg('alarm_id', metavar='<ALARM_ID>', nargs='?',
- 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.
- if alarm is None:
- raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
- else:
- _display_alarm(alarm)
-
-
-def common_alarm_arguments(create=False):
- def _wrapper(func):
- @utils.arg('--name', metavar='<NAME>', required=create,
- help='Name of the alarm (must be unique per tenant).')
- @utils.arg('--project-id', metavar='<ALARM_PROJECT_ID>',
- dest='alarm_project_id',
- help='Tenant to associate with alarm '
- '(configurable by admin users only).')
- @utils.arg('--user-id', metavar='<ALARM_USER_ID>',
- dest='alarm_user_id',
- help='User to associate with alarm '
- '(configurable by admin users only).')
- @utils.arg('--description', metavar='<DESCRIPTION>',
- help='Free text description of the alarm.')
- @utils.arg('--state', metavar='<STATE>',
- help='State of the alarm, one of: ' + str(ALARM_STATES))
- @utils.arg('--severity', metavar='<SEVERITY>',
- help='Severity of the alarm, one of: '
- + str(ALARM_SEVERITY))
- @utils.arg('--enabled',
- type=lambda v: strutils.bool_from_string(v, True),
- metavar='{True|False}',
- help='True if alarm evaluation/actioning is enabled.')
- @utils.arg('--alarm-action', dest='alarm_actions',
- metavar='<Webhook URL>', action='append', default=None,
- help=('URL to invoke when state transitions to alarm. '
- 'May be used multiple times.'))
- @utils.arg('--ok-action', dest='ok_actions',
- metavar='<Webhook URL>', action='append', default=None,
- help=('URL to invoke when state transitions to OK. '
- 'May be used multiple times.'))
- @utils.arg('--insufficient-data-action',
- dest='insufficient_data_actions',
- metavar='<Webhook URL>', action='append', default=None,
- help=('URL to invoke when state transitions to '
- 'insufficient data. May be used multiple times.'))
- @utils.arg('--time-constraint', dest='time_constraints',
- metavar='<Time Constraint>', action='append',
- default=None,
- help=('Only evaluate the alarm if the time at evaluation '
- 'is within this time constraint. Start point(s) of '
- 'the constraint are specified with a cron expression'
- ', whereas its duration is given in seconds. '
- 'Can be specified multiple times for multiple '
- 'time constraints, format is: '
- 'name=<CONSTRAINT_NAME>;start=<CRON>;'
- 'duration=<SECONDS>;[description=<DESCRIPTION>;'
- '[timezone=<IANA Timezone>]]'))
- @utils.arg('--repeat-actions', dest='repeat_actions',
- metavar='{True|False}', type=strutils.bool_from_string,
- help=('True if actions should be repeatedly notified '
- 'while alarm remains in target state.'))
- @functools.wraps(func)
- def _wrapped(*args, **kwargs):
- return func(*args, **kwargs)
- return _wrapped
- return _wrapper
-
-
-def common_alarm_gnocchi_arguments(rule_namespace, create=False):
- def _wrapper(func):
- @utils.arg('--granularity', type=int, metavar='<GRANULARITY>',
- dest=rule_namespace + '/granularity',
- help='Length of each period (seconds) to evaluate over.')
- @utils.arg('--evaluation-periods', type=int, metavar='<COUNT>',
- dest=rule_namespace + '/evaluation_periods',
- help='Number of periods to evaluate over.')
- @utils.arg('--aggregation-method', metavar='<AGGREATION>',
- dest=rule_namespace + '/aggregation_method',
- required=create,
- help=('Aggregation method to use, one of: ' +
- str(GNOCCHI_AGGREGATION) + '.'))
- @utils.arg('--comparison-operator', metavar='<OPERATOR>',
- dest=rule_namespace + '/comparison_operator',
- help=('Operator to compare with, one of: ' +
- str(ALARM_OPERATORS) + '.'))
- @utils.arg('--threshold', type=float, metavar='<THRESHOLD>',
- dest=rule_namespace + '/threshold',
- required=create,
- help='Threshold to evaluate against.')
- @functools.wraps(func)
- def _wrapped(*args, **kwargs):
- return func(*args, **kwargs)
- return _wrapped
- return _wrapper
-
-
-def common_alarm_gnocchi_aggregation_by_metrics_arguments(create=False):
- def _wrapper(func):
- @utils.arg('-m', '--metrics', metavar='<METRICS>',
- dest=('gnocchi_aggregation_by_metrics_threshold_rule/'
- 'metrics'),
- action='append', required=create,
- help='Metric to evaluate against.')
- @functools.wraps(func)
- def _wrapped(*args, **kwargs):
- return func(*args, **kwargs)
- return _wrapped
- return _wrapper
-
-
-def common_alarm_gnocchi_aggregation_by_resources_arguments(create=False):
- def _wrapper(func):
- @utils.arg('-m', '--metric', metavar='<METRIC>',
- dest=('gnocchi_aggregation_by_resources_threshold_rule/'
- 'metric'),
- required=create,
- help='Metric to evaluate against.')
- @utils.arg('--resource-type', metavar='<RESOURCE_TYPE>',
- dest=('gnocchi_aggregation_by_resources_threshold_rule/'
- 'resource_type'),
- required=create,
- help='Resource_type to evaluate against.')
- @utils.arg('--query', metavar='<QUERY>',
- dest=('gnocchi_aggregation_by_resources_threshold_rule/'
- 'query'),
- required=create,
- help=('Gnocchi resources search query filter'))
- @functools.wraps(func)
- def _wrapped(*args, **kwargs):
- return func(*args, **kwargs)
- return _wrapped
- return _wrapper
-
-
-def common_alarm_gnocchi_resources_arguments(create=False):
- def _wrapper(func):
- @utils.arg('-m', '--metric', metavar='<METRIC>',
- dest='gnocchi_resources_threshold_rule/metric',
- required=create,
- help='Metric to evaluate against.')
- @utils.arg('--resource-type', metavar='<RESOURCE_TYPE>',
- dest='gnocchi_resources_threshold_rule/resource_type',
- required=create,
- help='Resource_type to evaluate against.')
- @utils.arg('--resource-id', metavar='<RESOURCE_ID>',
- dest='gnocchi_resources_threshold_rule/resource_id',
- required=create,
- help=('Resource id to evaluate against'))
- @functools.wraps(func)
- def _wrapped(*args, **kwargs):
- return func(*args, **kwargs)
- return _wrapped
- return _wrapper
-
-
-def common_alarm_event_arguments():
- def _wrapper(func):
- @utils.arg('--event-type', dest='event_rule/event_type',
- metavar='<EVENT_TYPE>',
- help='Event type for event alarm.')
- @utils.arg('-q', '--query', dest='event_rule/query', metavar='<QUERY>',
- help=('key[op]data_type::value; list for filtering events. '
- 'data_type is optional, but if supplied must be '
- 'string, integer, float or datetime.'))
- @functools.wraps(func)
- def _wrapped(*args, **kwargs):
- return func(*args, **kwargs)
- return _wrapped
- return _wrapper
-
-
-@common_alarm_arguments(create=True)
-@utils.arg('--period', type=int, metavar='<PERIOD>',
- help='Length of each period (seconds) to evaluate over.')
-@utils.arg('--evaluation-periods', type=int, metavar='<COUNT>',
- help='Number of periods to evaluate over.')
-@utils.arg('-m', '--meter-name', metavar='<METRIC>', required=True,
- help='Metric to evaluate against.')
-@utils.arg('--statistic', metavar='<STATISTIC>',
- help='Statistic to evaluate, one of: ' + str(STATISTICS) + '.')
-@utils.arg('--comparison-operator', metavar='<OPERATOR>',
- help='Operator to compare with, one of: ' + str(ALARM_OPERATORS) +
- '.')
-@utils.arg('--threshold', type=float, metavar='<THRESHOLD>', required=True,
- help='Threshold to evaluate against.')
-@utils.arg('--matching-metadata', dest='matching_metadata',
- metavar='<Matching Metadata>', action='append', default=None,
- help=('A meter should match this resource metadata (key=value) '
- 'additionally to the meter_name.'))
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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")
- alarm = cc.alarms.create(**fields)
- _display_alarm(alarm)
-
-
-@common_alarm_arguments(create=True)
-@common_alarm_gnocchi_arguments('gnocchi_resources_threshold_rule',
- create=True)
-@common_alarm_gnocchi_resources_arguments(create=True)
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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)
- fields['type'] = 'gnocchi_resources_threshold'
- alarm = cc.alarms.create(**fields)
- _display_alarm(alarm)
-
-
-@common_alarm_arguments(create=True)
-@common_alarm_gnocchi_arguments(
- 'gnocchi_aggregation_by_metrics_threshold_rule', create=True)
-@common_alarm_gnocchi_aggregation_by_metrics_arguments(create=True)
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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)
- fields['type'] = 'gnocchi_aggregation_by_metrics_threshold'
- alarm = cc.alarms.create(**fields)
- _display_alarm(alarm)
-
-
-@common_alarm_arguments(create=True)
-@common_alarm_gnocchi_arguments(
- 'gnocchi_aggregation_by_resources_threshold_rule', create=True)
-@common_alarm_gnocchi_aggregation_by_resources_arguments(create=True)
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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)
- fields['type'] = 'gnocchi_aggregation_by_resources_threshold'
- alarm = cc.alarms.create(**fields)
- _display_alarm(alarm)
-
-
-@common_alarm_arguments(create=True)
-@utils.arg('-m', '--meter-name', metavar='<METRIC>', required=True,
- dest='threshold_rule/meter_name',
- help='Metric to evaluate against.')
-@utils.arg('--period', type=int, metavar='<PERIOD>',
- dest='threshold_rule/period',
- help='Length of each period (seconds) to evaluate over.')
-@utils.arg('--evaluation-periods', type=int, metavar='<COUNT>',
- dest='threshold_rule/evaluation_periods',
- help='Number of periods to evaluate over.')
-@utils.arg('--statistic', metavar='<STATISTIC>',
- dest='threshold_rule/statistic',
- help='Statistic to evaluate, one of: ' + str(STATISTICS) + '.')
-@utils.arg('--comparison-operator', metavar='<OPERATOR>',
- dest='threshold_rule/comparison_operator',
- help='Operator to compare with, one of: ' + str(ALARM_OPERATORS) +
- '.')
-@utils.arg('--threshold', type=float, metavar='<THRESHOLD>', required=True,
- dest='threshold_rule/threshold',
- help='Threshold to evaluate against.')
-@utils.arg('-q', '--query', metavar='<QUERY>',
- dest='threshold_rule/query',
- help='key[op]data_type::value; list. data_type is optional, '
- 'but if supplied must be string, integer, float, or boolean.')
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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)
- fields['type'] = 'threshold'
- if 'query' in fields['threshold_rule']:
- fields['threshold_rule']['query'] = options.cli_to_array(
- fields['threshold_rule']['query'])
- alarm = cc.alarms.create(**fields)
- _display_alarm(alarm)
-
-
-@common_alarm_arguments(create=True)
-@utils.arg('--alarm_ids', action='append', metavar='<ALARM IDS>',
- required=True, dest='combination_rule/alarm_ids',
- help='List of alarm IDs.')
-@utils.arg('--operator', metavar='<OPERATOR>',
- dest='combination_rule/operator',
- help='Operator to compare with, one of: ' + str(
- ALARM_COMBINATION_OPERATORS) + '.')
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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)
- fields['type'] = 'combination'
- alarm = cc.alarms.create(**fields)
- _display_alarm(alarm)
-
-
-@common_alarm_arguments(create=True)
-@common_alarm_event_arguments()
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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'
- fields['event_rule'] = fields.get('event_rule', {})
- if 'query' in fields['event_rule']:
- fields['event_rule']['query'] = options.cli_to_array(
- fields['event_rule']['query'])
- alarm = cc.alarms.create(**fields)
- _display_alarm(alarm)
-
-
-@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
- action=obsoleted_by('alarm_id'), help=argparse.SUPPRESS,
- dest='alarm_id_deprecated')
-@utils.arg('alarm_id', metavar='<ALARM_ID>', nargs='?',
- action=NotEmptyAction, help='ID of the alarm to update.')
-@common_alarm_arguments()
-@utils.arg('--remove-time-constraint', action='append',
- metavar='<Constraint names>',
- dest='remove_time_constraints',
- help='Name or list of names of the time constraints to remove.')
-@utils.arg('--period', type=int, metavar='<PERIOD>',
- help='Length of each period (seconds) to evaluate over.')
-@utils.arg('--evaluation-periods', type=int, metavar='<COUNT>',
- help='Number of periods to evaluate over.')
-@utils.arg('-m', '--meter-name', metavar='<METRIC>',
- help='Metric to evaluate against.')
-@utils.arg('--statistic', metavar='<STATISTIC>',
- help='Statistic to evaluate, one of: ' + str(STATISTICS))
-@utils.arg('--comparison-operator', metavar='<OPERATOR>',
- help='Operator to compare with, one of: ' + str(ALARM_OPERATORS) +
- '.')
-@utils.arg('--threshold', type=float, metavar='<THRESHOLD>',
- help='Threshold to evaluate against.')
-@utils.arg('--matching-metadata', dest='matching_metadata',
- metavar='<Matching Metadata>', action='append', default=None,
- help=('A meter should match this resource metadata (key=value) '
- 'additionally to the meter_name.'))
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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")
- fields.pop('alarm_id')
- try:
- alarm = cc.alarms.update(args.alarm_id, **fields)
- except exc.HTTPNotFound:
- raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
- _display_alarm(alarm)
-
-
-@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
- action=obsoleted_by('alarm_id'), help=argparse.SUPPRESS,
- dest='alarm_id_deprecated')
-@utils.arg('alarm_id', metavar='<ALARM_ID>', nargs='?',
- action=NotEmptyAction, help='ID of the alarm to update.')
-@common_alarm_arguments()
-@utils.arg('--remove-time-constraint', action='append',
- metavar='<Constraint names>',
- dest='remove_time_constraints',
- help='Name or list of names of the time constraints to remove.')
-@utils.arg('-m', '--meter-name', metavar='<METRIC>',
- dest='threshold_rule/meter_name',
- help='Metric to evaluate against.')
-@utils.arg('--period', type=int, metavar='<PERIOD>',
- dest='threshold_rule/period',
- help='Length of each period (seconds) to evaluate over.')
-@utils.arg('--evaluation-periods', type=int, metavar='<COUNT>',
- dest='threshold_rule/evaluation_periods',
- help='Number of periods to evaluate over.')
-@utils.arg('--statistic', metavar='<STATISTIC>',
- dest='threshold_rule/statistic',
- help='Statistic to evaluate, one of: ' + str(STATISTICS) +
- '.')
-@utils.arg('--comparison-operator', metavar='<OPERATOR>',
- dest='threshold_rule/comparison_operator',
- help='Operator to compare with, one of: ' + str(ALARM_OPERATORS) +
- '.')
-@utils.arg('--threshold', type=float, metavar='<THRESHOLD>',
- dest='threshold_rule/threshold',
- help='Threshold to evaluate against.')
-@utils.arg('-q', '--query', metavar='<QUERY>',
- dest='threshold_rule/query',
- help='key[op]data_type::value; list. data_type is optional, '
- 'but if supplied must be string, integer, float, or boolean.')
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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)
- fields.pop('alarm_id')
- fields['type'] = 'threshold'
- if 'threshold_rule' in fields and 'query' in fields['threshold_rule']:
- fields['threshold_rule']['query'] = options.cli_to_array(
- fields['threshold_rule']['query'])
- try:
- alarm = cc.alarms.update(args.alarm_id, **fields)
- except exc.HTTPNotFound:
- raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
- _display_alarm(alarm)
-
-
-@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
- action=obsoleted_by('alarm_id'), help=argparse.SUPPRESS,
- dest='alarm_id_deprecated')
-@utils.arg('alarm_id', metavar='<ALARM_ID>', nargs='?',
- action=NotEmptyAction, help='ID of the alarm to update.')
-@common_alarm_arguments()
-@common_alarm_gnocchi_arguments('gnocchi_resources_threshold_rule')
-@common_alarm_gnocchi_resources_arguments()
-@utils.arg('--remove-time-constraint', action='append',
- metavar='<Constraint names>',
- dest='remove_time_constraints',
- help='Name or list of names of the time constraints to remove.')
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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)
- fields.pop('alarm_id')
- fields['type'] = 'gnocchi_resources_threshold'
- try:
- alarm = cc.alarms.update(args.alarm_id, **fields)
- except exc.HTTPNotFound:
- raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
- _display_alarm(alarm)
-
-
-@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
- action=obsoleted_by('alarm_id'), help=argparse.SUPPRESS,
- dest='alarm_id_deprecated')
-@utils.arg('alarm_id', metavar='<ALARM_ID>', nargs='?',
- action=NotEmptyAction, help='ID of the alarm to update.')
-@common_alarm_arguments()
-@common_alarm_gnocchi_arguments(
- 'gnocchi_aggregation_by_metrics_threshold_rule')
-@common_alarm_gnocchi_aggregation_by_metrics_arguments()
-@utils.arg('--remove-time-constraint', action='append',
- metavar='<Constraint names>',
- dest='remove_time_constraints',
- help='Name or list of names of the time constraints to remove.')
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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)
- fields.pop('alarm_id')
- fields['type'] = 'gnocchi_aggregation_by_metrics_threshold'
- try:
- alarm = cc.alarms.update(args.alarm_id, **fields)
- except exc.HTTPNotFound:
- raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
- _display_alarm(alarm)
-
-
-@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
- action=obsoleted_by('alarm_id'), help=argparse.SUPPRESS,
- dest='alarm_id_deprecated')
-@utils.arg('alarm_id', metavar='<ALARM_ID>', nargs='?',
- action=NotEmptyAction, help='ID of the alarm to update.')
-@common_alarm_arguments()
-@common_alarm_gnocchi_arguments(
- 'gnocchi_aggregation_by_resources_threshold_rule')
-@common_alarm_gnocchi_aggregation_by_resources_arguments()
-@utils.arg('--remove-time-constraint', action='append',
- metavar='<Constraint names>',
- dest='remove_time_constraints',
- help='Name or list of names of the time constraints to remove.')
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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)
- fields.pop('alarm_id')
- fields['type'] = 'gnocchi_aggregation_by_resources_threshold'
- try:
- alarm = cc.alarms.update(args.alarm_id, **fields)
- except exc.HTTPNotFound:
- raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
- _display_alarm(alarm)
-
-
-@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
- action=obsoleted_by('alarm_id'), help=argparse.SUPPRESS,
- dest='alarm_id_deprecated')
-@utils.arg('alarm_id', metavar='<ALARM_ID>', nargs='?',
- action=NotEmptyAction, help='ID of the alarm to update.')
-@common_alarm_arguments()
-@utils.arg('--remove-time-constraint', action='append',
- metavar='<Constraint names>',
- dest='remove_time_constraints',
- help='Name or list of names of the time constraints to remove.')
-@utils.arg('--alarm_ids', action='append', metavar='<ALARM IDS>',
- dest='combination_rule/alarm_ids',
- help='List of alarm IDs.')
-@utils.arg('--operator', metavar='<OPERATOR>',
- dest='combination_rule/operator',
- help='Operator to compare with, one of: ' + str(
- ALARM_COMBINATION_OPERATORS) + '.')
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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)
- fields.pop('alarm_id')
- fields['type'] = 'combination'
- try:
- alarm = cc.alarms.update(args.alarm_id, **fields)
- except exc.HTTPNotFound:
- raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
- _display_alarm(alarm)
-
-
-@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
- action=obsoleted_by('alarm_id'), help=argparse.SUPPRESS,
- dest='alarm_id_deprecated')
-@utils.arg('alarm_id', metavar='<ALARM_ID>', nargs='?',
- action=NotEmptyAction, help='ID of the alarm to update.')
-@common_alarm_arguments()
-@common_alarm_event_arguments()
-@_restore_shadowed_arg('project_id', 'alarm_project_id')
-@_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')
- fields['type'] = 'event'
- if fields.get('event_rule') and 'query' in fields['event_rule']:
- fields['event_rule']['query'] = options.cli_to_array(
- fields['event_rule']['query'])
- try:
- alarm = cc.alarms.update(args.alarm_id, **fields)
- except exc.HTTPNotFound:
- raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
- _display_alarm(alarm)
-
-
-@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
- action=obsoleted_by('alarm_id'), help=argparse.SUPPRESS,
- dest='alarm_id_deprecated')
-@utils.arg('alarm_id', metavar='<ALARM_ID>', nargs='?',
- 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:
- raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
-
-
-@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
- action=obsoleted_by('alarm_id'), help=argparse.SUPPRESS,
- dest='alarm_id_deprecated')
-@utils.arg('alarm_id', metavar='<ALARM_ID>', nargs='?',
- action=NotEmptyAction, help='ID of the alarm state to set.')
-@utils.arg('--state', metavar='<STATE>', required=True,
- help='State of the alarm, one of: ' + str(ALARM_STATES) +
- '.')
-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:
- raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
- utils.print_dict({'state': state}, wrap=72)
-
-
-@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
- action=obsoleted_by('alarm_id'), help=argparse.SUPPRESS,
- dest='alarm_id_deprecated')
-@utils.arg('alarm_id', metavar='<ALARM_ID>', nargs='?',
- 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:
- raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
- utils.print_dict({'state': state}, wrap=72)
-
-
-@utils.arg('-a', '--alarm_id', metavar='<ALARM_ID>',
- action=obsoleted_by('alarm_id'), help=argparse.SUPPRESS,
- dest='alarm_id_deprecated')
-@utils.arg('alarm_id', metavar='<ALARM_ID>', nargs='?', action=NotEmptyAction,
- help='ID of the alarm for which history is shown.')
-@utils.arg('-q', '--query', metavar='<QUERY>',
- help='key[op]data_type::value; list. data_type is optional, '
- '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:
- history = cc.alarms.get_history(**kwargs)
- except exc.HTTPNotFound:
- raise exc.CommandError('Alarm not found: %s' % args.alarm_id)
- field_labels = ['Type', 'Timestamp', 'Detail']
- fields = ['type', 'timestamp', 'detail']
- # We're using sortby=None as the alarm history returned from the Ceilometer
- # is already sorted in the "the newer state is the earlier one in the
- # list". If we'll pass any field as a sortby param, it'll be sorted in the
- # ASC way by the PrettyTable
- utils.print_list(history, fields, field_labels,
- formatters={'detail': alarm_change_detail_formatter},
- sortby=None)
-
-
-@utils.arg('-q', '--query', metavar='<QUERY>',
- help='key[op]data_type::value; list. data_type is optional, '
- 'but if supplied must be string, integer, float, or boolean.')
-@utils.arg('-l', '--limit', metavar='<NUMBER>',
- help='Maximum number of resources to return. %s' %
- DEFAULT_API_LIMIT)
-def do_resource_list(cc, args={}):
- """List the resources."""
- resources = cc.resources.list(q=options.cli_to_array(args.query),
- limit=args.limit)
-
- field_labels = ['Resource ID', 'Source', 'User ID', 'Project ID']
- fields = ['resource_id', 'source', 'user_id', 'project_id']
- utils.print_list(resources, fields, field_labels,
- sortby=1)
-
-
-@utils.arg('resource_id', metavar='<RESOURCE_ID>',
- action=NotEmptyAction, help='ID of the resource to show.')
-def do_resource_show(cc, args={}):
- """Show the resource."""
- try:
- resource = cc.resources.get(args.resource_id)
- except exc.HTTPNotFound:
- raise exc.CommandError('Resource not found: %s' % args.resource_id)
- else:
- fields = ['resource_id', 'source', 'user_id',
- 'project_id', 'metadata']
- data = dict([(f, getattr(resource, f, '')) for f in fields])
- utils.print_dict(data, wrap=72)
-
-
-@utils.arg('-q', '--query', metavar='<QUERY>',
- help='key[op]data_type::value; list. data_type is optional, '
- 'but if supplied must be string, integer, float '
- 'or datetime.')
-@utils.arg('--no-traits', dest='no_traits', action='store_true',
- help='If specified, traits will not be printed.')
-@utils.arg('-l', '--limit', metavar='<NUMBER>',
- help='Maximum number of events to return. %s' % DEFAULT_API_LIMIT)
-def do_event_list(cc, args={}):
- """List events."""
- events = cc.events.list(q=options.cli_to_array(args.query),
- limit=args.limit)
- field_labels = ['Message ID', 'Event Type', 'Generated', 'Traits']
- fields = ['message_id', 'event_type', 'generated', 'traits']
- if args.no_traits:
- field_labels.pop()
- fields.pop()
- utils.print_list(events, fields, field_labels,
- formatters={
- 'traits': utils.nested_list_of_dict_formatter(
- 'traits', ['name', 'type', 'value']
- )},
- sortby=None)
-
-
-@utils.arg('message_id', metavar='<message_id>', action=NotEmptyAction,
- help='The ID of the event. Should be a UUID.')
-def do_event_show(cc, args={}):
- """Show a particular event."""
- try:
- event = cc.events.get(args.message_id)
- except exc.HTTPNotFound:
- raise exc.CommandError('Event not found: %s' % args.message_id)
-
- fields = ['event_type', 'generated', 'traits', 'raw']
- data = dict([(f, getattr(event, f, '')) for f in fields])
- utils.print_dict(data, wrap=72)
-
-
-def do_event_type_list(cc, args={}):
- """List event types."""
- event_types = cc.event_types.list()
- utils.print_list(event_types, ['event_type'], ['Event Type'])
-
-
-@utils.arg('-e', '--event_type', metavar='<EVENT_TYPE>',
- help='Type of the event for which traits will be shown.',
- required=True, action=NotEmptyAction)
-def do_trait_description_list(cc, args={}):
- """List trait info for an event type."""
- trait_descriptions = cc.trait_descriptions.list(args.event_type)
- field_labels = ['Trait Name', 'Data Type']
- fields = ['name', 'type']
- utils.print_list(trait_descriptions, fields, field_labels)
-
-
-@utils.arg('-e', '--event_type', metavar='<EVENT_TYPE>',
- help='Type of the event for which traits will listed.',
- required=True, action=NotEmptyAction)
-@utils.arg('-t', '--trait_name', metavar='<TRAIT_NAME>',
- help='The name of the trait to list.',
- required=True, action=NotEmptyAction)
-def do_trait_list(cc, args={}):
- """List all traits with name <trait_name> for Event Type <event_type>."""
- traits = cc.traits.list(args.event_type, args.trait_name)
- field_labels = ['Trait Name', 'Value', 'Data Type']
- fields = ['name', 'value', 'type']
- utils.print_list(traits, fields, field_labels)
-
-
-@utils.arg('-f', '--filter', metavar='<FILTER>',
- help=('{complex_op: [{simple_op: {field_name: value}}]} '
- 'The complex_op is one of: ' + str(COMPLEX_OPERATORS) + ', '
- 'simple_op is one of: ' + str(SIMPLE_OPERATORS) + '.'))
-@utils.arg('-o', '--orderby', metavar='<ORDERBY>',
- help=('[{field_name: direction}, {field_name: direction}] '
- 'The direction is one of: ' + str(ORDER_DIRECTIONS) + '.'))
-@utils.arg('-l', '--limit', metavar='<LIMIT>',
- help='Maximum number of samples to return. %s' % DEFAULT_API_LIMIT)
-def do_query_samples(cc, args):
- """Query samples."""
- fields = {'filter': args.filter,
- 'orderby': args.orderby,
- 'limit': args.limit}
- try:
- samples = cc.query_samples.query(**fields)
- except exc.HTTPNotFound:
- raise exc.CommandError('Samples not found')
- else:
- field_labels = ['ID', 'Resource ID', 'Meter', 'Type', 'Volume',
- 'Unit', 'Timestamp']
- fields = ['id', 'resource_id', 'meter', 'type',
- 'volume', 'unit', 'timestamp']
- utils.print_list(samples, fields, field_labels,
- sortby=None)
-
-
-@utils.arg('-f', '--filter', metavar='<FILTER>',
- help=('{complex_op: [{simple_op: {field_name: value}}]} '
- 'The complex_op is one of: ' + str(COMPLEX_OPERATORS) + ', '
- 'simple_op is one of: ' + str(SIMPLE_OPERATORS) + '.'))
-@utils.arg('-o', '--orderby', metavar='<ORDERBY>',
- help=('[{field_name: direction}, {field_name: direction}] '
- 'The direction is one of: ' + str(ORDER_DIRECTIONS) + '.'))
-@utils.arg('-l', '--limit', metavar='<LIMIT>',
- help='Maximum number of alarms to return. %s' % DEFAULT_API_LIMIT)
-def do_query_alarms(cc, args):
- """Query Alarms."""
- fields = {'filter': args.filter,
- 'orderby': args.orderby,
- 'limit': args.limit}
- try:
- alarms = cc.query_alarms.query(**fields)
- except exc.HTTPNotFound:
- raise exc.CommandError('Alarms not found')
- else:
- _display_alarm_list(alarms, sortby=None)
-
-
-@utils.arg('-f', '--filter', metavar='<FILTER>',
- help=('{complex_op: [{simple_op: {field_name: value}}]} '
- 'The complex_op is one of: ' + str(COMPLEX_OPERATORS) + ', '
- 'simple_op is one of: ' + str(SIMPLE_OPERATORS) + '.'))
-@utils.arg('-o', '--orderby', metavar='<ORDERBY>',
- help=('[{field_name: direction}, {field_name: direction}] '
- 'The direction is one of: ' + str(ORDER_DIRECTIONS) + '.'))
-@utils.arg('-l', '--limit', metavar='<LIMIT>',
- help='Maximum number of alarm history items to return. %s' %
- DEFAULT_API_LIMIT)
-def do_query_alarm_history(cc, args):
- """Query Alarm History."""
- fields = {'filter': args.filter,
- 'orderby': args.orderby,
- 'limit': args.limit}
- try:
- alarm_history = cc.query_alarm_history.query(**fields)
- except exc.HTTPNotFound:
- raise exc.CommandError('Alarm history not found')
- else:
- field_labels = ['Alarm ID', 'Event ID', 'Type', 'Detail', 'Timestamp']
- fields = ['alarm_id', 'event_id', 'type', 'detail', 'timestamp']
- utils.print_list(alarm_history, fields, field_labels,
- formatters={'rule': alarm_change_detail_formatter},
- sortby=None)
-
-
-def do_capabilities(cc, args):
- """Print Ceilometer capabilities."""
- capabilities = cc.capabilities.get().to_dict()
- # Capability is a nested dict, and has no user defined data,
- # so it is safe to format here with json tools.
- for key in capabilities:
- # remove the leading and trailing pair of {}
- capabilities[key] = jsonutils.dumps(capabilities[key],
- sort_keys=True, indent=0)[2:-2]
- utils.print_dict(capabilities)
diff --git a/ceilometerclient/v2/statistics.py b/ceilometerclient/v2/statistics.py
deleted file mode 100644
index 4775238..0000000
--- a/ceilometerclient/v2/statistics.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import six
-
-from ceilometerclient.common import base
-from ceilometerclient.v2 import options
-
-
-class Statistics(base.Resource):
- def __repr__(self):
- return "<Statistics %s>" % self._info
-
-
-class StatisticsManager(base.Manager):
- resource_class = Statistics
-
- @staticmethod
- def _build_aggregates(aggregates):
- url_aggregates = []
- for aggregate in aggregates:
- if 'param' in aggregate:
- url_aggregates.insert(
- 0,
- "aggregate.param=%(param)s" % aggregate
- )
- url_aggregates.insert(
- 0,
- "aggregate.func=%(func)s" % aggregate
- )
- else:
- url_aggregates.append(
- "aggregate.func=%(func)s" % aggregate
- )
- return url_aggregates
-
- def list(self, meter_name, q=None, period=None, groupby=None,
- aggregates=None):
- groupby = groupby or []
- aggregates = aggregates or []
- p = ['period=%s' % period] if period else []
- if isinstance(groupby, six.string_types):
- groupby = [groupby]
- p.extend(['groupby=%s' % g for g in groupby] if groupby else [])
- p.extend(self._build_aggregates(aggregates))
- return self._list(options.build_url(
- '/v2/meters/' + meter_name + '/statistics',
- q, p))
diff --git a/ceilometerclient/v2/trait_descriptions.py b/ceilometerclient/v2/trait_descriptions.py
deleted file mode 100644
index 418647a..0000000
--- a/ceilometerclient/v2/trait_descriptions.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2013 Hewlett-Packard Development Company, L.P.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from ceilometerclient.common import base
-
-
-class TraitDescription(base.Resource):
- def __repr__(self):
- return "<Trait %s>" % self._info
-
-
-class TraitDescriptionManager(base.Manager):
- resource_class = TraitDescription
-
- def list(self, event_type):
- path = '/v2/event_types/%s/traits' % event_type
- return self._list(path)
diff --git a/ceilometerclient/v2/traits.py b/ceilometerclient/v2/traits.py
deleted file mode 100644
index 55f8960..0000000
--- a/ceilometerclient/v2/traits.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2013 Hewlett-Packard Development Company, L.P.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from ceilometerclient.common import base
-
-
-class Trait(base.Resource):
- def __repr__(self):
- return "<Trait %s>" % self._info
-
-
-class TraitManager(base.Manager):
- resource_class = Trait
-
- def list(self, event_type, trait_name):
- path = '/v2/event_types/%s/traits/%s' % (event_type, trait_name)
- return self._list(path)
diff --git a/doc/ext/gen_ref.py b/doc/ext/gen_ref.py
deleted file mode 100644
index f8560b3..0000000
--- a/doc/ext/gen_ref.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# -*- coding: utf-8 -*-
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import os
-import sys
-
-BASE_DIR = os.path.dirname(os.path.abspath(__file__))
-ROOT = os.path.abspath(os.path.join(BASE_DIR, "..", "..", ".."))
-
-sys.path.insert(0, ROOT)
-sys.path.insert(0, BASE_DIR)
-
-
-def gen_ref(ver, title, names):
- refdir = os.path.join(BASE_DIR, "ref")
- pkg = "ceilometerclient"
- if ver:
- pkg = "%s.%s" % (pkg, ver)
- refdir = os.path.join(refdir, ver)
- if not os.path.exists(refdir):
- os.makedirs(refdir)
- idxpath = os.path.join(refdir, "index.rst")
- with open(idxpath, "w") as idx:
- idx.write(("%(title)s\n"
- "%(signs)s\n"
- "\n"
- ".. toctree::\n"
- " :maxdepth: 1\n"
- "\n") % {"title": title, "signs": "=" * len(title)})
- for name in names:
- idx.write(" %s\n" % name)
- rstpath = os.path.join(refdir, "%s.rst" % name)
- with open(rstpath, "w") as rst:
- rst.write(("%(title)s\n"
- "%(signs)s\n"
- "\n"
- ".. automodule:: %(pkg)s.%(name)s\n"
- " :members:\n"
- " :undoc-members:\n"
- " :show-inheritance:\n"
- " :noindex:\n")
- % {"title": name.capitalize(),
- "signs": "=" * len(name),
- "pkg": pkg, "name": name})
diff --git a/doc/source/api.rst b/doc/source/api.rst
deleted file mode 100644
index df6eaf5..0000000
--- a/doc/source/api.rst
+++ /dev/null
@@ -1,47 +0,0 @@
-The :mod:`ceilometerclient` Python API
-======================================
-
-.. module:: ceilometerclient
- :synopsis: A client for the OpenStack Ceilometer API.
-
-.. currentmodule:: ceilometerclient
-
-Usage
------
-
-First create a client instance with your credentials::
-
- >>> import ceilometerclient.client
- >>> cclient = ceilometerclient.client.get_client(VERSION, os_username=USERNAME, os_password=PASSWORD, os_tenant_name=PROJECT_NAME, os_auth_url=AUTH_URL)
-
-Here ``VERSION`` should be: ``2``.
-
-Then call methods on its managers::
-
- >>> cclient.meters.list()
- [<Meter ...>, ...]
-
- >>> cclient.new_samples.list()
- [<Sample ...>, ...]
-
-V2 client tips
-++++++++++++++
-
-Use queries to narrow your search (more info at `Ceilometer V2 API reference`__)::
-
- >>> query = [dict(field='resource_id', op='eq', value='5a301761-f78b-46e2-8900-8b4f6fe6675a'), dict(field='meter',op='eq',value='cpu_util')]
- >>> cclient.new_samples.list(q=query, limit=10)
- [<Sample ...>, ...]
-
-__ https://docs.openstack.org/ceilometer/latest/webapi/v2.html#Query
-
-Reference
----------
-
-For more information, see the reference:
-
-.. toctree::
- :maxdepth: 2
-
- ref/index
- ref/v2/index
diff --git a/doc/source/cli.rst b/doc/source/cli.rst
deleted file mode 100644
index aa0c8c2..0000000
--- a/doc/source/cli.rst
+++ /dev/null
@@ -1,2202 +0,0 @@
-.. ###################################################
-.. ## WARNING ######################################
-.. ############## WARNING ##########################
-.. ########################## WARNING ##############
-.. ###################################### WARNING ##
-.. ###################################################
-.. ###################################################
-.. ##
-.. This file is tool-generated. Do not edit manually.
-.. http://docs.openstack.org/contributor-guide/
-.. doc-tools/cli-reference.html
-.. ##
-.. ## WARNING ######################################
-.. ############## WARNING ##########################
-.. ########################## WARNING ##############
-.. ###################################### WARNING ##
-.. ###################################################
-
-==================================================================
-Telemetry Data Collection service (ceilometer) command-line client
-==================================================================
-
-The ceilometer client is the command-line interface (CLI) for
-the Telemetry Data Collection service (ceilometer) API
-and its extensions.
-
-This chapter documents :command:`ceilometer` version ``2.9.0``.
-
-For help on a specific :command:`ceilometer` command, enter:
-
-.. code-block:: console
-
- $ ceilometer help COMMAND
-
-.. _ceilometer_command_usage:
-
-ceilometer usage
-~~~~~~~~~~~~~~~~
-
-.. code-block:: console
-
- usage: ceilometer [--version] [-d] [-v] [--timeout TIMEOUT]
- [--ceilometer-url <CEILOMETER_URL>]
- [--ceilometer-api-version CEILOMETER_API_VERSION]
- [--os-tenant-id <tenant-id>]
- [--os-region-name <region-name>]
- [--os-auth-token <auth-token>]
- [--os-service-type <service-type>]
- [--os-endpoint-type <endpoint-type>] [--os-cacert <cacert>]
- [--os-insecure <insecure>] [--os-cert-file <cert-file>]
- [--os-key-file <key-file>] [--os-cert <cert>]
- [--os-key <key>] [--os-project-name <project-name>]
- [--os-project-id <project-id>]
- [--os-project-domain-id <project-domain-id>]
- [--os-project-domain-name <project-domain-name>]
- [--os-user-id <user-id>]
- [--os-user-domain-id <user-domain-id>]
- [--os-user-domain-name <user-domain-name>]
- [--os-endpoint <endpoint>] [--os-auth-system <auth-system>]
- [--os-username <username>] [--os-password <password>]
- [--os-tenant-name <tenant-name>] [--os-token <token>]
- [--os-auth-url <auth-url>]
- <subcommand> ...
-
-**Subcommands:**
-
-``alarm-combination-create``
- Create a new alarm based on state of other
- alarms.
-
-``alarm-combination-update``
- Update an existing alarm based on state of
- other alarms.
-
-``alarm-create``
- Create a new alarm (Deprecated). Use alarm-threshold-create instead.
-
-``alarm-delete``
- Delete an alarm.
-
-``alarm-event-create``
- Create a new alarm based on events.
-
-``alarm-event-update``
- Update an existing alarm based on events.
-
-``alarm-gnocchi-aggregation-by-metrics-threshold-create``
- Create a new alarm based on computed
- statistics.
-
-``alarm-gnocchi-aggregation-by-metrics-threshold-update``
- Update an existing alarm based on computed
- statistics.
-
-``alarm-gnocchi-aggregation-by-resources-threshold-create``
- Create a new alarm based on computed
- statistics.
-
-``alarm-gnocchi-aggregation-by-resources-threshold-update``
- Update an existing alarm based on computed
- statistics.
-
-``alarm-gnocchi-resources-threshold-create``
- Create a new alarm based on computed
- statistics.
-
-``alarm-gnocchi-resources-threshold-update``
- Update an existing alarm based on computed
- statistics.
-
-``alarm-history``
- Display the change history of an alarm.
-
-``alarm-list``
- List the user's alarms.
-
-``alarm-show``
- Show an alarm.
-
-``alarm-state-get``
- Get the state of an alarm.
-
-``alarm-state-set``
- Set the state of an alarm.
-
-``alarm-threshold-create``
- Create a new alarm based on computed
- statistics.
-
-``alarm-threshold-update``
- Update an existing alarm based on computed
- statistics.
-
-``alarm-update``
- Update an existing alarm (Deprecated).
-
-``capabilities``
- Print Ceilometer capabilities.
-
-``event-list``
- List events.
-
-``event-show``
- Show a particular event.
-
-``event-type-list``
- List event types.
-
-``meter-list``
- List the user's meters.
-
-``query-alarm-history``
- Query Alarm History.
-
-``query-alarms``
- Query Alarms.
-
-``query-samples``
- Query samples.
-
-``resource-list``
- List the resources.
-
-``resource-show``
- Show the resource.
-
-``sample-create``
- Create a sample.
-
-``sample-create-list``
- Create a sample list.
-
-``sample-list``
- List the samples (return OldSample objects if
- -m/--meter is set).
-
-``sample-show``
- Show a sample.
-
-``statistics``
- List the statistics for a meter.
-
-``trait-description-list``
- List trait info for an event type.
-
-``trait-list``
- List all traits with name <trait_name> for
- Event Type <event_type>.
-
-``bash-completion``
- Prints all of the commands and options to
- stdout.
-
-``help``
- Display help about this program or one of its
- subcommands.
-
-.. _ceilometer_command_options:
-
-ceilometer optional arguments
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-``--version``
- show program's version number and exit
-
-``-d, --debug``
- Defaults to ``env[CEILOMETERCLIENT_DEBUG]``.
-
-``-v, --verbose``
- Print more verbose output.
-
-``--timeout TIMEOUT``
- Number of seconds to wait for a response.
-
-``--ceilometer-url <CEILOMETER_URL>``
- **DEPRECATED**, use --os-endpoint instead.
- Defaults to ``env[CEILOMETER_URL]``.
-
-``--ceilometer-api-version CEILOMETER_API_VERSION``
- Defaults to ``env[CEILOMETER_API_VERSION]`` or 2.
-
-``--os-tenant-id <tenant-id>``
- Defaults to ``env[OS_TENANT_ID]``.
-
-``--os-region-name <region-name>``
- Defaults to ``env[OS_REGION_NAME]``.
-
-``--os-auth-token <auth-token>``
- Defaults to ``env[OS_AUTH_TOKEN]``.
-
-``--os-service-type <service-type>``
- Defaults to ``env[OS_SERVICE_TYPE]``.
-
-``--os-endpoint-type <endpoint-type>``
- Defaults to ``env[OS_ENDPOINT_TYPE]``.
-
-``--os-cacert <cacert>``
- Defaults to ``env[OS_CACERT]``.
-
-``--os-insecure <insecure>``
- Defaults to ``env[OS_INSECURE]``.
-
-``--os-cert-file <cert-file>``
- Defaults to ``env[OS_CERT_FILE]``.
-
-``--os-key-file <key-file>``
- Defaults to ``env[OS_KEY_FILE]``.
-
-``--os-cert <cert>``
- Defaults to ``env[OS_CERT]``.
-
-``--os-key <key>``
- Defaults to ``env[OS_KEY]``.
-
-``--os-project-name <project-name>``
- Defaults to ``env[OS_PROJECT_NAME]``.
-
-``--os-project-id <project-id>``
- Defaults to ``env[OS_PROJECT_ID]``.
-
-``--os-project-domain-id <project-domain-id>``
- Defaults to ``env[OS_PROJECT_DOMAIN_ID]``.
-
-``--os-project-domain-name <project-domain-name>``
- Defaults to ``env[OS_PROJECT_DOMAIN_NAME]``.
-
-``--os-user-id <user-id>``
- Defaults to ``env[OS_USER_ID]``.
-
-``--os-user-domain-id <user-domain-id>``
- Defaults to ``env[OS_USER_DOMAIN_ID]``.
-
-``--os-user-domain-name <user-domain-name>``
- Defaults to ``env[OS_USER_DOMAIN_NAME]``.
-
-``--os-endpoint <endpoint>``
- Defaults to ``env[OS_ENDPOINT]``.
-
-``--os-auth-system <auth-system>``
- Defaults to ``env[OS_AUTH_SYSTEM]``.
-
-``--os-username <username>``
- Defaults to ``env[OS_USERNAME]``.
-
-``--os-password <password>``
- Defaults to ``env[OS_PASSWORD]``.
-
-``--os-tenant-name <tenant-name>``
- Defaults to ``env[OS_TENANT_NAME]``.
-
-``--os-token <token>``
- Defaults to ``env[OS_TOKEN]``.
-
-``--os-auth-url <auth-url>``
- Defaults to ``env[OS_AUTH_URL]``.
-
-.. _ceilometer_alarm-combination-create:
-
-ceilometer alarm-combination-create
------------------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-combination-create --name <NAME>
- [--project-id <ALARM_PROJECT_ID>]
- [--user-id <ALARM_USER_ID>]
- [--description <DESCRIPTION>]
- [--state <STATE>]
- [--severity <SEVERITY>]
- [--enabled {True|False}]
- [--alarm-action <Webhook URL>]
- [--ok-action <Webhook URL>]
- [--insufficient-data-action <Webhook URL>]
- [--time-constraint <Time Constraint>]
- [--repeat-actions {True|False}]
- --alarm_ids <ALARM IDS>
- [--operator <OPERATOR>]
-
-Create a new alarm based on state of other alarms.
-
-**Optional arguments:**
-
-``--name <NAME>``
- Name of the alarm (must be unique per tenant).
- Required.
-
-``--project-id <ALARM_PROJECT_ID>``
- Tenant to associate with alarm (configurable
- by admin users only).
-
-``--user-id <ALARM_USER_ID>``
- User to associate with alarm (configurable by
- admin users only).
-
-``--description <DESCRIPTION>``
- Free text description of the alarm.
-
-``--state <STATE>``
- State of the alarm, one of: ['ok', 'alarm',
- 'insufficient data']
-
-``--severity <SEVERITY>``
- Severity of the alarm, one of: ['low',
- 'moderate', 'critical']
-
-``--enabled {True|False}``
- True if alarm evaluation/actioning is enabled.
-
-``--alarm-action <Webhook URL>``
- URL to invoke when state transitions to alarm.
- May be used multiple times. Defaults to None.
-
-``--ok-action <Webhook URL>``
- URL to invoke when state transitions to OK.
- May be used multiple times. Defaults to None.
-
-``--insufficient-data-action <Webhook URL>``
- URL to invoke when state transitions to
- insufficient data. May be used multiple times.
- Defaults to None.
-
-``--time-constraint <Time Constraint>``
- Only evaluate the alarm if the time at
- evaluation is within this time constraint.
- Start point(s) of the constraint are specified
- with a cron expression, whereas its duration
- is given in seconds. Can be specified multiple
- times for multiple time constraints, format
- is: name=<CONSTRAINT_NAME>;start=<CRON>;durati
- on=<SECONDS>;[description=<DESCRIPTION>;[timez
- one=<IANA Timezone>]] Defaults to None.
-
-``--repeat-actions {True|False}``
- True if actions should be repeatedly notified
- while alarm remains in target state.
-
-``--alarm_ids <ALARM IDS>``
- List of alarm IDs. Required.
-
-``--operator <OPERATOR>``
- Operator to compare with, one of: ['and',
- 'or'].
-
-.. _ceilometer_alarm-combination-update:
-
-ceilometer alarm-combination-update
------------------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-combination-update [--name <NAME>]
- [--project-id <ALARM_PROJECT_ID>]
- [--user-id <ALARM_USER_ID>]
- [--description <DESCRIPTION>]
- [--state <STATE>]
- [--severity <SEVERITY>]
- [--enabled {True|False}]
- [--alarm-action <Webhook URL>]
- [--ok-action <Webhook URL>]
- [--insufficient-data-action <Webhook URL>]
- [--time-constraint <Time Constraint>]
- [--repeat-actions {True|False}]
- [--remove-time-constraint <Constraint names>]
- [--alarm_ids <ALARM IDS>]
- [--operator <OPERATOR>]
- [<ALARM_ID>]
-
-Update an existing alarm based on state of other alarms.
-
-**Positional arguments:**
-
-``<ALARM_ID>``
- ID of the alarm to update.
-
-**Optional arguments:**
-
-``--name <NAME>``
- Name of the alarm (must be unique per tenant).
-
-``--project-id <ALARM_PROJECT_ID>``
- Tenant to associate with alarm (configurable
- by admin users only).
-
-``--user-id <ALARM_USER_ID>``
- User to associate with alarm (configurable by
- admin users only).
-
-``--description <DESCRIPTION>``
- Free text description of the alarm.
-
-``--state <STATE>``
- State of the alarm, one of: ['ok', 'alarm',
- 'insufficient data']
-
-``--severity <SEVERITY>``
- Severity of the alarm, one of: ['low',
- 'moderate', 'critical']
-
-``--enabled {True|False}``
- True if alarm evaluation/actioning is enabled.
-
-``--alarm-action <Webhook URL>``
- URL to invoke when state transitions to alarm.
- May be used multiple times. Defaults to None.
-
-``--ok-action <Webhook URL>``
- URL to invoke when state transitions to OK.
- May be used multiple times. Defaults to None.
-
-``--insufficient-data-action <Webhook URL>``
- URL to invoke when state transitions to
- insufficient data. May be used multiple times.
- Defaults to None.
-
-``--time-constraint <Time Constraint>``
- Only evaluate the alarm if the time at
- evaluation is within this time constraint.
- Start point(s) of the constraint are specified
- with a cron expression, whereas its duration
- is given in seconds. Can be specified multiple
- times for multiple time constraints, format
- is: name=<CONSTRAINT_NAME>;start=<CRON>;durati
- on=<SECONDS>;[description=<DESCRIPTION>;[timez
- one=<IANA Timezone>]] Defaults to None.
-
-``--repeat-actions {True|False}``
- True if actions should be repeatedly notified
- while alarm remains in target state.
-
-``--remove-time-constraint <Constraint names>``
- Name or list of names of the time constraints
- to remove.
-
-``--alarm_ids <ALARM IDS>``
- List of alarm IDs.
-
-``--operator <OPERATOR>``
- Operator to compare with, one of: ['and',
- 'or'].
-
-.. _ceilometer_alarm-delete:
-
-ceilometer alarm-delete
------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-delete [<ALARM_ID>]
-
-Delete an alarm.
-
-**Positional arguments:**
-
-``<ALARM_ID>``
- ID of the alarm to delete.
-
-.. _ceilometer_alarm-event-create:
-
-ceilometer alarm-event-create
------------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-event-create --name <NAME>
- [--project-id <ALARM_PROJECT_ID>]
- [--user-id <ALARM_USER_ID>]
- [--description <DESCRIPTION>]
- [--state <STATE>] [--severity <SEVERITY>]
- [--enabled {True|False}]
- [--alarm-action <Webhook URL>]
- [--ok-action <Webhook URL>]
- [--insufficient-data-action <Webhook URL>]
- [--time-constraint <Time Constraint>]
- [--repeat-actions {True|False}]
- [--event-type <EVENT_TYPE>] [-q <QUERY>]
-
-Create a new alarm based on events.
-
-**Optional arguments:**
-
-``--name <NAME>``
- Name of the alarm (must be unique per tenant).
- Required.
-
-``--project-id <ALARM_PROJECT_ID>``
- Tenant to associate with alarm (configurable
- by admin users only).
-
-``--user-id <ALARM_USER_ID>``
- User to associate with alarm (configurable by
- admin users only).
-
-``--description <DESCRIPTION>``
- Free text description of the alarm.
-
-``--state <STATE>``
- State of the alarm, one of: ['ok', 'alarm',
- 'insufficient data']
-
-``--severity <SEVERITY>``
- Severity of the alarm, one of: ['low',
- 'moderate', 'critical']
-
-``--enabled {True|False}``
- True if alarm evaluation/actioning is enabled.
-
-``--alarm-action <Webhook URL>``
- URL to invoke when state transitions to alarm.
- May be used multiple times. Defaults to None.
-
-``--ok-action <Webhook URL>``
- URL to invoke when state transitions to OK.
- May be used multiple times. Defaults to None.
-
-``--insufficient-data-action <Webhook URL>``
- URL to invoke when state transitions to
- insufficient data. May be used multiple times.
- Defaults to None.
-
-``--time-constraint <Time Constraint>``
- Only evaluate the alarm if the time at
- evaluation is within this time constraint.
- Start point(s) of the constraint are specified
- with a cron expression, whereas its duration
- is given in seconds. Can be specified multiple
- times for multiple time constraints, format
- is: name=<CONSTRAINT_NAME>;start=<CRON>;durati
- on=<SECONDS>;[description=<DESCRIPTION>;[timez
- one=<IANA Timezone>]] Defaults to None.
-
-``--repeat-actions {True|False}``
- True if actions should be repeatedly notified
- while alarm remains in target state.
-
-``--event-type <EVENT_TYPE>``
- Event type for event alarm.
-
-``-q <QUERY>, --query <QUERY>``
- key[op]data_type::value; list for filtering
- events. data_type is optional, but if supplied
- must be string, integer, float or datetime.
-
-.. _ceilometer_alarm-event-update:
-
-ceilometer alarm-event-update
------------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-event-update [--name <NAME>]
- [--project-id <ALARM_PROJECT_ID>]
- [--user-id <ALARM_USER_ID>]
- [--description <DESCRIPTION>]
- [--state <STATE>] [--severity <SEVERITY>]
- [--enabled {True|False}]
- [--alarm-action <Webhook URL>]
- [--ok-action <Webhook URL>]
- [--insufficient-data-action <Webhook URL>]
- [--time-constraint <Time Constraint>]
- [--repeat-actions {True|False}]
- [--event-type <EVENT_TYPE>] [-q <QUERY>]
- [<ALARM_ID>]
-
-Update an existing alarm based on events.
-
-**Positional arguments:**
-
-``<ALARM_ID>``
- ID of the alarm to update.
-
-**Optional arguments:**
-
-``--name <NAME>``
- Name of the alarm (must be unique per tenant).
-
-``--project-id <ALARM_PROJECT_ID>``
- Tenant to associate with alarm (configurable
- by admin users only).
-
-``--user-id <ALARM_USER_ID>``
- User to associate with alarm (configurable by
- admin users only).
-
-``--description <DESCRIPTION>``
- Free text description of the alarm.
-
-``--state <STATE>``
- State of the alarm, one of: ['ok', 'alarm',
- 'insufficient data']
-
-``--severity <SEVERITY>``
- Severity of the alarm, one of: ['low',
- 'moderate', 'critical']
-
-``--enabled {True|False}``
- True if alarm evaluation/actioning is enabled.
-
-``--alarm-action <Webhook URL>``
- URL to invoke when state transitions to alarm.
- May be used multiple times. Defaults to None.
-
-``--ok-action <Webhook URL>``
- URL to invoke when state transitions to OK.
- May be used multiple times. Defaults to None.
-
-``--insufficient-data-action <Webhook URL>``
- URL to invoke when state transitions to
- insufficient data. May be used multiple times.
- Defaults to None.
-
-``--time-constraint <Time Constraint>``
- Only evaluate the alarm if the time at
- evaluation is within this time constraint.
- Start point(s) of the constraint are specified
- with a cron expression, whereas its duration
- is given in seconds. Can be specified multiple
- times for multiple time constraints, format
- is: name=<CONSTRAINT_NAME>;start=<CRON>;durati
- on=<SECONDS>;[description=<DESCRIPTION>;[timez
- one=<IANA Timezone>]] Defaults to None.
-
-``--repeat-actions {True|False}``
- True if actions should be repeatedly notified
- while alarm remains in target state.
-
-``--event-type <EVENT_TYPE>``
- Event type for event alarm.
-
-``-q <QUERY>, --query <QUERY>``
- key[op]data_type::value; list for filtering
- events. data_type is optional, but if supplied
- must be string, integer, float or datetime.
-
-.. _ceilometer_alarm-gnocchi-aggregation-by-metrics-threshold-create:
-
-ceilometer alarm-gnocchi-aggregation-by-metrics-threshold-create
-----------------------------------------------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-gnocchi-aggregation-by-metrics-threshold-create
- --name <NAME> [--project-id <ALARM_PROJECT_ID>]
- [--user-id <ALARM_USER_ID>] [--description <DESCRIPTION>]
- [--state <STATE>] [--severity <SEVERITY>] [--enabled {True|False}]
- [--alarm-action <Webhook URL>] [--ok-action <Webhook URL>]
- [--insufficient-data-action <Webhook URL>]
- [--time-constraint <Time Constraint>] [--repeat-actions {True|False}]
- [--granularity <GRANULARITY>] [--evaluation-periods <COUNT>]
- --aggregation-method <AGGREATION> [--comparison-operator <OPERATOR>]
- --threshold <THRESHOLD> -m <METRICS>
-
-Create a new alarm based on computed statistics.
-
-**Optional arguments:**
-
-``--name <NAME>``
- Name of the alarm (must be unique per tenant).
- Required.
-
-``--project-id <ALARM_PROJECT_ID>``
- Tenant to associate with alarm (configurable
- by admin users only).
-
-``--user-id <ALARM_USER_ID>``
- User to associate with alarm (configurable by
- admin users only).
-
-``--description <DESCRIPTION>``
- Free text description of the alarm.
-
-``--state <STATE>``
- State of the alarm, one of: ['ok', 'alarm',
- 'insufficient data']
-
-``--severity <SEVERITY>``
- Severity of the alarm, one of: ['low',
- 'moderate', 'critical']
-
-``--enabled {True|False}``
- True if alarm evaluation/actioning is enabled.
-
-``--alarm-action <Webhook URL>``
- URL to invoke when state transitions to alarm.
- May be used multiple times. Defaults to None.
-
-``--ok-action <Webhook URL>``
- URL to invoke when state transitions to OK.
- May be used multiple times. Defaults to None.
-
-``--insufficient-data-action <Webhook URL>``
- URL to invoke when state transitions to
- insufficient data. May be used multiple times.
- Defaults to None.
-
-``--time-constraint <Time Constraint>``
- Only evaluate the alarm if the time at
- evaluation is within this time constraint.
- Start point(s) of the constraint are specified
- with a cron expression, whereas its duration
- is given in seconds. Can be specified multiple
- times for multiple time constraints, format
- is: name=<CONSTRAINT_NAME>;start=<CRON>;durati
- on=<SECONDS>;[description=<DESCRIPTION>;[timez
- one=<IANA Timezone>]] Defaults to None.
-
-``--repeat-actions {True|False}``
- True if actions should be repeatedly notified
- while alarm remains in target state.
-
-``--granularity <GRANULARITY>``
- Length of each period (seconds) to evaluate
- over.
-
-``--evaluation-periods <COUNT>``
- Number of periods to evaluate over.
-
-``--aggregation-method <AGGREATION>``
- Aggregation method to use, one of: ['last',
- 'min', 'median', 'sum', 'std', 'first',
- 'mean', 'count', 'moving-average', 'max',
- '1pct', '2pct', '3pct', '4pct', '5pct',
- '6pct', '7pct', '8pct', '9pct', '10pct',
- '11pct', '12pct', '13pct', '14pct', '15pct',
- '16pct', '17pct', '18pct', '19pct', '20pct',
- '21pct', '22pct', '23pct', '24pct', '25pct',
- '26pct', '27pct', '28pct', '29pct', '30pct',
- '31pct', '32pct', '33pct', '34pct', '35pct',
- '36pct', '37pct', '38pct', '39pct', '40pct',
- '41pct', '42pct', '43pct', '44pct', '45pct',
- '46pct', '47pct', '48pct', '49pct', '50pct',
- '51pct', '52pct', '53pct', '54pct', '55pct',
- '56pct', '57pct', '58pct', '59pct', '60pct',
- '61pct', '62pct', '63pct', '64pct', '65pct',
- '66pct', '67pct', '68pct', '69pct', '70pct',
- '71pct', '72pct', '73pct', '74pct', '75pct',
- '76pct', '77pct', '78pct', '79pct', '80pct',
- '81pct', '82pct', '83pct', '84pct', '85pct',
- '86pct', '87pct', '88pct', '89pct', '90pct',
- '91pct', '92pct', '93pct', '94pct', '95pct',
- '96pct', '97pct', '98pct', '99pct']. Required.
-
-``--comparison-operator <OPERATOR>``
- Operator to compare with, one of: ['lt', 'le',
- 'eq', 'ne', 'ge', 'gt'].
-
-``--threshold <THRESHOLD>``
- Threshold to evaluate against. Required.
-
-``-m <METRICS>, --metrics <METRICS>``
- Metric to evaluate against. Required.
-
-.. _ceilometer_alarm-gnocchi-aggregation-by-metrics-threshold-update:
-
-ceilometer alarm-gnocchi-aggregation-by-metrics-threshold-update
-----------------------------------------------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-gnocchi-aggregation-by-metrics-threshold-update
- [--name <NAME>] [--project-id <ALARM_PROJECT_ID>]
- [--user-id <ALARM_USER_ID>] [--description <DESCRIPTION>]
- [--state <STATE>] [--severity <SEVERITY>] [--enabled {True|False}]
- [--alarm-action <Webhook URL>] [--ok-action <Webhook URL>]
- [--insufficient-data-action <Webhook URL>]
- [--time-constraint <Time Constraint>] [--repeat-actions {True|False}]
- [--granularity <GRANULARITY>] [--evaluation-periods <COUNT>]
- [--aggregation-method <AGGREATION>] [--comparison-operator <OPERATOR>]
- [--threshold <THRESHOLD>] [-m <METRICS>]
- [--remove-time-constraint <Constraint names>]
- [<ALARM_ID>]
-
-Update an existing alarm based on computed statistics.
-
-**Positional arguments:**
-
-``<ALARM_ID>``
- ID of the alarm to update.
-
-**Optional arguments:**
-
-``--name <NAME>``
- Name of the alarm (must be unique per tenant).
-
-``--project-id <ALARM_PROJECT_ID>``
- Tenant to associate with alarm (configurable
- by admin users only).
-
-``--user-id <ALARM_USER_ID>``
- User to associate with alarm (configurable by
- admin users only).
-
-``--description <DESCRIPTION>``
- Free text description of the alarm.
-
-``--state <STATE>``
- State of the alarm, one of: ['ok', 'alarm',
- 'insufficient data']
-
-``--severity <SEVERITY>``
- Severity of the alarm, one of: ['low',
- 'moderate', 'critical']
-
-``--enabled {True|False}``
- True if alarm evaluation/actioning is enabled.
-
-``--alarm-action <Webhook URL>``
- URL to invoke when state transitions to alarm.
- May be used multiple times. Defaults to None.
-
-``--ok-action <Webhook URL>``
- URL to invoke when state transitions to OK.
- May be used multiple times. Defaults to None.
-
-``--insufficient-data-action <Webhook URL>``
- URL to invoke when state transitions to
- insufficient data. May be used multiple times.
- Defaults to None.
-
-``--time-constraint <Time Constraint>``
- Only evaluate the alarm if the time at
- evaluation is within this time constraint.
- Start point(s) of the constraint are specified
- with a cron expression, whereas its duration
- is given in seconds. Can be specified multiple
- times for multiple time constraints, format
- is: name=<CONSTRAINT_NAME>;start=<CRON>;durati
- on=<SECONDS>;[description=<DESCRIPTION>;[timez
- one=<IANA Timezone>]] Defaults to None.
-
-``--repeat-actions {True|False}``
- True if actions should be repeatedly notified
- while alarm remains in target state.
-
-``--granularity <GRANULARITY>``
- Length of each period (seconds) to evaluate
- over.
-
-``--evaluation-periods <COUNT>``
- Number of periods to evaluate over.
-
-``--aggregation-method <AGGREATION>``
- Aggregation method to use, one of: ['last',
- 'min', 'median', 'sum', 'std', 'first',
- 'mean', 'count', 'moving-average', 'max',
- '1pct', '2pct', '3pct', '4pct', '5pct',
- '6pct', '7pct', '8pct', '9pct', '10pct',
- '11pct', '12pct', '13pct', '14pct', '15pct',
- '16pct', '17pct', '18pct', '19pct', '20pct',
- '21pct', '22pct', '23pct', '24pct', '25pct',
- '26pct', '27pct', '28pct', '29pct', '30pct',
- '31pct', '32pct', '33pct', '34pct', '35pct',
- '36pct', '37pct', '38pct', '39pct', '40pct',
- '41pct', '42pct', '43pct', '44pct', '45pct',
- '46pct', '47pct', '48pct', '49pct', '50pct',
- '51pct', '52pct', '53pct', '54pct', '55pct',
- '56pct', '57pct', '58pct', '59pct', '60pct',
- '61pct', '62pct', '63pct', '64pct', '65pct',
- '66pct', '67pct', '68pct', '69pct', '70pct',
- '71pct', '72pct', '73pct', '74pct', '75pct',
- '76pct', '77pct', '78pct', '79pct', '80pct',
- '81pct', '82pct', '83pct', '84pct', '85pct',
- '86pct', '87pct', '88pct', '89pct', '90pct',
- '91pct', '92pct', '93pct', '94pct', '95pct',
- '96pct', '97pct', '98pct', '99pct'].
-
-``--comparison-operator <OPERATOR>``
- Operator to compare with, one of: ['lt', 'le',
- 'eq', 'ne', 'ge', 'gt'].
-
-``--threshold <THRESHOLD>``
- Threshold to evaluate against.
-
-``-m <METRICS>, --metrics <METRICS>``
- Metric to evaluate against.
-
-``--remove-time-constraint <Constraint names>``
- Name or list of names of the time constraints
- to remove.
-
-.. _ceilometer_alarm-gnocchi-aggregation-by-resources-threshold-create:
-
-ceilometer alarm-gnocchi-aggregation-by-resources-threshold-create
-------------------------------------------------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-gnocchi-aggregation-by-resources-threshold-create
- --name <NAME> [--project-id <ALARM_PROJECT_ID>]
- [--user-id <ALARM_USER_ID>] [--description <DESCRIPTION>]
- [--state <STATE>] [--severity <SEVERITY>] [--enabled {True|False}]
- [--alarm-action <Webhook URL>] [--ok-action <Webhook URL>]
- [--insufficient-data-action <Webhook URL>]
- [--time-constraint <Time Constraint>] [--repeat-actions {True|False}]
- [--granularity <GRANULARITY>] [--evaluation-periods <COUNT>]
- --aggregation-method <AGGREATION> [--comparison-operator <OPERATOR>]
- --threshold <THRESHOLD> -m <METRIC> --resource-type <RESOURCE_TYPE>
- --query <QUERY>
-
-Create a new alarm based on computed statistics.
-
-**Optional arguments:**
-
-``--name <NAME>``
- Name of the alarm (must be unique per tenant).
- Required.
-
-``--project-id <ALARM_PROJECT_ID>``
- Tenant to associate with alarm (configurable
- by admin users only).
-
-``--user-id <ALARM_USER_ID>``
- User to associate with alarm (configurable by
- admin users only).
-
-``--description <DESCRIPTION>``
- Free text description of the alarm.
-
-``--state <STATE>``
- State of the alarm, one of: ['ok', 'alarm',
- 'insufficient data']
-
-``--severity <SEVERITY>``
- Severity of the alarm, one of: ['low',
- 'moderate', 'critical']
-
-``--enabled {True|False}``
- True if alarm evaluation/actioning is enabled.
-
-``--alarm-action <Webhook URL>``
- URL to invoke when state transitions to alarm.
- May be used multiple times. Defaults to None.
-
-``--ok-action <Webhook URL>``
- URL to invoke when state transitions to OK.
- May be used multiple times. Defaults to None.
-
-``--insufficient-data-action <Webhook URL>``
- URL to invoke when state transitions to
- insufficient data. May be used multiple times.
- Defaults to None.
-
-``--time-constraint <Time Constraint>``
- Only evaluate the alarm if the time at
- evaluation is within this time constraint.
- Start point(s) of the constraint are specified
- with a cron expression, whereas its duration
- is given in seconds. Can be specified multiple
- times for multiple time constraints, format
- is: name=<CONSTRAINT_NAME>;start=<CRON>;durati
- on=<SECONDS>;[description=<DESCRIPTION>;[timez
- one=<IANA Timezone>]] Defaults to None.
-
-``--repeat-actions {True|False}``
- True if actions should be repeatedly notified
- while alarm remains in target state.
-
-``--granularity <GRANULARITY>``
- Length of each period (seconds) to evaluate
- over.
-
-``--evaluation-periods <COUNT>``
- Number of periods to evaluate over.
-
-``--aggregation-method <AGGREATION>``
- Aggregation method to use, one of: ['last',
- 'min', 'median', 'sum', 'std', 'first',
- 'mean', 'count', 'moving-average', 'max',
- '1pct', '2pct', '3pct', '4pct', '5pct',
- '6pct', '7pct', '8pct', '9pct', '10pct',
- '11pct', '12pct', '13pct', '14pct', '15pct',
- '16pct', '17pct', '18pct', '19pct', '20pct',
- '21pct', '22pct', '23pct', '24pct', '25pct',
- '26pct', '27pct', '28pct', '29pct', '30pct',
- '31pct', '32pct', '33pct', '34pct', '35pct',
- '36pct', '37pct', '38pct', '39pct', '40pct',
- '41pct', '42pct', '43pct', '44pct', '45pct',
- '46pct', '47pct', '48pct', '49pct', '50pct',
- '51pct', '52pct', '53pct', '54pct', '55pct',
- '56pct', '57pct', '58pct', '59pct', '60pct',
- '61pct', '62pct', '63pct', '64pct', '65pct',
- '66pct', '67pct', '68pct', '69pct', '70pct',
- '71pct', '72pct', '73pct', '74pct', '75pct',
- '76pct', '77pct', '78pct', '79pct', '80pct',
- '81pct', '82pct', '83pct', '84pct', '85pct',
- '86pct', '87pct', '88pct', '89pct', '90pct',
- '91pct', '92pct', '93pct', '94pct', '95pct',
- '96pct', '97pct', '98pct', '99pct']. Required.
-
-``--comparison-operator <OPERATOR>``
- Operator to compare with, one of: ['lt', 'le',
- 'eq', 'ne', 'ge', 'gt'].
-
-``--threshold <THRESHOLD>``
- Threshold to evaluate against. Required.
-
-``-m <METRIC>, --metric <METRIC>``
- Metric to evaluate against. Required.
-
-``--resource-type <RESOURCE_TYPE>``
- Resource_type to evaluate against. Required.
-
-``--query <QUERY>``
- Gnocchi resources search query filter
- Required.
-
-.. _ceilometer_alarm-gnocchi-aggregation-by-resources-threshold-update:
-
-ceilometer alarm-gnocchi-aggregation-by-resources-threshold-update
-------------------------------------------------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-gnocchi-aggregation-by-resources-threshold-update
- [--name <NAME>] [--project-id <ALARM_PROJECT_ID>]
- [--user-id <ALARM_USER_ID>] [--description <DESCRIPTION>]
- [--state <STATE>] [--severity <SEVERITY>] [--enabled {True|False}]
- [--alarm-action <Webhook URL>] [--ok-action <Webhook URL>]
- [--insufficient-data-action <Webhook URL>]
- [--time-constraint <Time Constraint>] [--repeat-actions {True|False}]
- [--granularity <GRANULARITY>] [--evaluation-periods <COUNT>]
- [--aggregation-method <AGGREATION>] [--comparison-operator <OPERATOR>]
- [--threshold <THRESHOLD>] [-m <METRIC>]
- [--resource-type <RESOURCE_TYPE>] [--query <QUERY>]
- [--remove-time-constraint <Constraint names>]
- [<ALARM_ID>]
-
-Update an existing alarm based on computed statistics.
-
-**Positional arguments:**
-
-``<ALARM_ID>``
- ID of the alarm to update.
-
-**Optional arguments:**
-
-``--name <NAME>``
- Name of the alarm (must be unique per tenant).
-
-``--project-id <ALARM_PROJECT_ID>``
- Tenant to associate with alarm (configurable
- by admin users only).
-
-``--user-id <ALARM_USER_ID>``
- User to associate with alarm (configurable by
- admin users only).
-
-``--description <DESCRIPTION>``
- Free text description of the alarm.
-
-``--state <STATE>``
- State of the alarm, one of: ['ok', 'alarm',
- 'insufficient data']
-
-``--severity <SEVERITY>``
- Severity of the alarm, one of: ['low',
- 'moderate', 'critical']
-
-``--enabled {True|False}``
- True if alarm evaluation/actioning is enabled.
-
-``--alarm-action <Webhook URL>``
- URL to invoke when state transitions to alarm.
- May be used multiple times. Defaults to None.
-
-``--ok-action <Webhook URL>``
- URL to invoke when state transitions to OK.
- May be used multiple times. Defaults to None.
-
-``--insufficient-data-action <Webhook URL>``
- URL to invoke when state transitions to
- insufficient data. May be used multiple times.
- Defaults to None.
-
-``--time-constraint <Time Constraint>``
- Only evaluate the alarm if the time at
- evaluation is within this time constraint.
- Start point(s) of the constraint are specified
- with a cron expression, whereas its duration
- is given in seconds. Can be specified multiple
- times for multiple time constraints, format
- is: name=<CONSTRAINT_NAME>;start=<CRON>;durati
- on=<SECONDS>;[description=<DESCRIPTION>;[timez
- one=<IANA Timezone>]] Defaults to None.
-
-``--repeat-actions {True|False}``
- True if actions should be repeatedly notified
- while alarm remains in target state.
-
-``--granularity <GRANULARITY>``
- Length of each period (seconds) to evaluate
- over.
-
-``--evaluation-periods <COUNT>``
- Number of periods to evaluate over.
-
-``--aggregation-method <AGGREATION>``
- Aggregation method to use, one of: ['last',
- 'min', 'median', 'sum', 'std', 'first',
- 'mean', 'count', 'moving-average', 'max',
- '1pct', '2pct', '3pct', '4pct', '5pct',
- '6pct', '7pct', '8pct', '9pct', '10pct',
- '11pct', '12pct', '13pct', '14pct', '15pct',
- '16pct', '17pct', '18pct', '19pct', '20pct',
- '21pct', '22pct', '23pct', '24pct', '25pct',
- '26pct', '27pct', '28pct', '29pct', '30pct',
- '31pct', '32pct', '33pct', '34pct', '35pct',
- '36pct', '37pct', '38pct', '39pct', '40pct',
- '41pct', '42pct', '43pct', '44pct', '45pct',
- '46pct', '47pct', '48pct', '49pct', '50pct',
- '51pct', '52pct', '53pct', '54pct', '55pct',
- '56pct', '57pct', '58pct', '59pct', '60pct',
- '61pct', '62pct', '63pct', '64pct', '65pct',
- '66pct', '67pct', '68pct', '69pct', '70pct',
- '71pct', '72pct', '73pct', '74pct', '75pct',
- '76pct', '77pct', '78pct', '79pct', '80pct',
- '81pct', '82pct', '83pct', '84pct', '85pct',
- '86pct', '87pct', '88pct', '89pct', '90pct',
- '91pct', '92pct', '93pct', '94pct', '95pct',
- '96pct', '97pct', '98pct', '99pct'].
-
-``--comparison-operator <OPERATOR>``
- Operator to compare with, one of: ['lt', 'le',
- 'eq', 'ne', 'ge', 'gt'].
-
-``--threshold <THRESHOLD>``
- Threshold to evaluate against.
-
-``-m <METRIC>, --metric <METRIC>``
- Metric to evaluate against.
-
-``--resource-type <RESOURCE_TYPE>``
- Resource_type to evaluate against.
-
-``--query <QUERY>``
- Gnocchi resources search query filter
-
-``--remove-time-constraint <Constraint names>``
- Name or list of names of the time constraints
- to remove.
-
-.. _ceilometer_alarm-gnocchi-resources-threshold-create:
-
-ceilometer alarm-gnocchi-resources-threshold-create
----------------------------------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-gnocchi-resources-threshold-create --name <NAME>
- [--project-id <ALARM_PROJECT_ID>]
- [--user-id <ALARM_USER_ID>]
- [--description <DESCRIPTION>]
- [--state <STATE>]
- [--severity <SEVERITY>]
- [--enabled {True|False}]
- [--alarm-action <Webhook URL>]
- [--ok-action <Webhook URL>]
- [--insufficient-data-action <Webhook URL>]
- [--time-constraint <Time Constraint>]
- [--repeat-actions {True|False}]
- [--granularity <GRANULARITY>]
- [--evaluation-periods <COUNT>]
- --aggregation-method
- <AGGREATION>
- [--comparison-operator <OPERATOR>]
- --threshold
- <THRESHOLD> -m
- <METRIC>
- --resource-type
- <RESOURCE_TYPE>
- --resource-id
- <RESOURCE_ID>
-
-Create a new alarm based on computed statistics.
-
-**Optional arguments:**
-
-``--name <NAME>``
- Name of the alarm (must be unique per tenant).
- Required.
-
-``--project-id <ALARM_PROJECT_ID>``
- Tenant to associate with alarm (configurable
- by admin users only).
-
-``--user-id <ALARM_USER_ID>``
- User to associate with alarm (configurable by
- admin users only).
-
-``--description <DESCRIPTION>``
- Free text description of the alarm.
-
-``--state <STATE>``
- State of the alarm, one of: ['ok', 'alarm',
- 'insufficient data']
-
-``--severity <SEVERITY>``
- Severity of the alarm, one of: ['low',
- 'moderate', 'critical']
-
-``--enabled {True|False}``
- True if alarm evaluation/actioning is enabled.
-
-``--alarm-action <Webhook URL>``
- URL to invoke when state transitions to alarm.
- May be used multiple times. Defaults to None.
-
-``--ok-action <Webhook URL>``
- URL to invoke when state transitions to OK.
- May be used multiple times. Defaults to None.
-
-``--insufficient-data-action <Webhook URL>``
- URL to invoke when state transitions to
- insufficient data. May be used multiple times.
- Defaults to None.
-
-``--time-constraint <Time Constraint>``
- Only evaluate the alarm if the time at
- evaluation is within this time constraint.
- Start point(s) of the constraint are specified
- with a cron expression, whereas its duration
- is given in seconds. Can be specified multiple
- times for multiple time constraints, format
- is: name=<CONSTRAINT_NAME>;start=<CRON>;durati
- on=<SECONDS>;[description=<DESCRIPTION>;[timez
- one=<IANA Timezone>]] Defaults to None.
-
-``--repeat-actions {True|False}``
- True if actions should be repeatedly notified
- while alarm remains in target state.
-
-``--granularity <GRANULARITY>``
- Length of each period (seconds) to evaluate
- over.
-
-``--evaluation-periods <COUNT>``
- Number of periods to evaluate over.
-
-``--aggregation-method <AGGREATION>``
- Aggregation method to use, one of: ['last',
- 'min', 'median', 'sum', 'std', 'first',
- 'mean', 'count', 'moving-average', 'max',
- '1pct', '2pct', '3pct', '4pct', '5pct',
- '6pct', '7pct', '8pct', '9pct', '10pct',
- '11pct', '12pct', '13pct', '14pct', '15pct',
- '16pct', '17pct', '18pct', '19pct', '20pct',
- '21pct', '22pct', '23pct', '24pct', '25pct',
- '26pct', '27pct', '28pct', '29pct', '30pct',
- '31pct', '32pct', '33pct', '34pct', '35pct',
- '36pct', '37pct', '38pct', '39pct', '40pct',
- '41pct', '42pct', '43pct', '44pct', '45pct',
- '46pct', '47pct', '48pct', '49pct', '50pct',
- '51pct', '52pct', '53pct', '54pct', '55pct',
- '56pct', '57pct', '58pct', '59pct', '60pct',
- '61pct', '62pct', '63pct', '64pct', '65pct',
- '66pct', '67pct', '68pct', '69pct', '70pct',
- '71pct', '72pct', '73pct', '74pct', '75pct',
- '76pct', '77pct', '78pct', '79pct', '80pct',
- '81pct', '82pct', '83pct', '84pct', '85pct',
- '86pct', '87pct', '88pct', '89pct', '90pct',
- '91pct', '92pct', '93pct', '94pct', '95pct',
- '96pct', '97pct', '98pct', '99pct']. Required.
-
-``--comparison-operator <OPERATOR>``
- Operator to compare with, one of: ['lt', 'le',
- 'eq', 'ne', 'ge', 'gt'].
-
-``--threshold <THRESHOLD>``
- Threshold to evaluate against. Required.
-
-``-m <METRIC>, --metric <METRIC>``
- Metric to evaluate against. Required.
-
-``--resource-type <RESOURCE_TYPE>``
- Resource_type to evaluate against. Required.
-
-``--resource-id <RESOURCE_ID>``
- Resource id to evaluate against Required.
-
-.. _ceilometer_alarm-gnocchi-resources-threshold-update:
-
-ceilometer alarm-gnocchi-resources-threshold-update
----------------------------------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-gnocchi-resources-threshold-update [--name <NAME>]
- [--project-id <ALARM_PROJECT_ID>]
- [--user-id <ALARM_USER_ID>]
- [--description <DESCRIPTION>]
- [--state <STATE>]
- [--severity <SEVERITY>]
- [--enabled {True|False}]
- [--alarm-action <Webhook URL>]
- [--ok-action <Webhook URL>]
- [--insufficient-data-action <Webhook URL>]
- [--time-constraint <Time Constraint>]
- [--repeat-actions {True|False}]
- [--granularity <GRANULARITY>]
- [--evaluation-periods <COUNT>]
- [--aggregation-method <AGGREATION>]
- [--comparison-operator <OPERATOR>]
- [--threshold <THRESHOLD>]
- [-m <METRIC>]
- [--resource-type <RESOURCE_TYPE>]
- [--resource-id <RESOURCE_ID>]
- [--remove-time-constraint <Constraint names>]
- [<ALARM_ID>]
-
-Update an existing alarm based on computed statistics.
-
-**Positional arguments:**
-
-``<ALARM_ID>``
- ID of the alarm to update.
-
-**Optional arguments:**
-
-``--name <NAME>``
- Name of the alarm (must be unique per tenant).
-
-``--project-id <ALARM_PROJECT_ID>``
- Tenant to associate with alarm (configurable
- by admin users only).
-
-``--user-id <ALARM_USER_ID>``
- User to associate with alarm (configurable by
- admin users only).
-
-``--description <DESCRIPTION>``
- Free text description of the alarm.
-
-``--state <STATE>``
- State of the alarm, one of: ['ok', 'alarm',
- 'insufficient data']
-
-``--severity <SEVERITY>``
- Severity of the alarm, one of: ['low',
- 'moderate', 'critical']
-
-``--enabled {True|False}``
- True if alarm evaluation/actioning is enabled.
-
-``--alarm-action <Webhook URL>``
- URL to invoke when state transitions to alarm.
- May be used multiple times. Defaults to None.
-
-``--ok-action <Webhook URL>``
- URL to invoke when state transitions to OK.
- May be used multiple times. Defaults to None.
-
-``--insufficient-data-action <Webhook URL>``
- URL to invoke when state transitions to
- insufficient data. May be used multiple times.
- Defaults to None.
-
-``--time-constraint <Time Constraint>``
- Only evaluate the alarm if the time at
- evaluation is within this time constraint.
- Start point(s) of the constraint are specified
- with a cron expression, whereas its duration
- is given in seconds. Can be specified multiple
- times for multiple time constraints, format
- is: name=<CONSTRAINT_NAME>;start=<CRON>;durati
- on=<SECONDS>;[description=<DESCRIPTION>;[timez
- one=<IANA Timezone>]] Defaults to None.
-
-``--repeat-actions {True|False}``
- True if actions should be repeatedly notified
- while alarm remains in target state.
-
-``--granularity <GRANULARITY>``
- Length of each period (seconds) to evaluate
- over.
-
-``--evaluation-periods <COUNT>``
- Number of periods to evaluate over.
-
-``--aggregation-method <AGGREATION>``
- Aggregation method to use, one of: ['last',
- 'min', 'median', 'sum', 'std', 'first',
- 'mean', 'count', 'moving-average', 'max',
- '1pct', '2pct', '3pct', '4pct', '5pct',
- '6pct', '7pct', '8pct', '9pct', '10pct',
- '11pct', '12pct', '13pct', '14pct', '15pct',
- '16pct', '17pct', '18pct', '19pct', '20pct',
- '21pct', '22pct', '23pct', '24pct', '25pct',
- '26pct', '27pct', '28pct', '29pct', '30pct',
- '31pct', '32pct', '33pct', '34pct', '35pct',
- '36pct', '37pct', '38pct', '39pct', '40pct',
- '41pct', '42pct', '43pct', '44pct', '45pct',
- '46pct', '47pct', '48pct', '49pct', '50pct',
- '51pct', '52pct', '53pct', '54pct', '55pct',
- '56pct', '57pct', '58pct', '59pct', '60pct',
- '61pct', '62pct', '63pct', '64pct', '65pct',
- '66pct', '67pct', '68pct', '69pct', '70pct',
- '71pct', '72pct', '73pct', '74pct', '75pct',
- '76pct', '77pct', '78pct', '79pct', '80pct',
- '81pct', '82pct', '83pct', '84pct', '85pct',
- '86pct', '87pct', '88pct', '89pct', '90pct',
- '91pct', '92pct', '93pct', '94pct', '95pct',
- '96pct', '97pct', '98pct', '99pct'].
-
-``--comparison-operator <OPERATOR>``
- Operator to compare with, one of: ['lt', 'le',
- 'eq', 'ne', 'ge', 'gt'].
-
-``--threshold <THRESHOLD>``
- Threshold to evaluate against.
-
-``-m <METRIC>, --metric <METRIC>``
- Metric to evaluate against.
-
-``--resource-type <RESOURCE_TYPE>``
- Resource_type to evaluate against.
-
-``--resource-id <RESOURCE_ID>``
- Resource id to evaluate against
-
-``--remove-time-constraint <Constraint names>``
- Name or list of names of the time constraints
- to remove.
-
-.. _ceilometer_alarm-history:
-
-ceilometer alarm-history
-------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-history [-q <QUERY>] [<ALARM_ID>]
-
-Display the change history of an alarm.
-
-**Positional arguments:**
-
-``<ALARM_ID>``
- ID of the alarm for which history is shown.
-
-**Optional arguments:**
-
-``-q <QUERY>, --query <QUERY>``
- key[op]data_type::value; list. data_type is
- optional, but if supplied must be string,
- integer, float, or boolean.
-
-.. _ceilometer_alarm-list:
-
-ceilometer alarm-list
----------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-list [-q <QUERY>]
-
-List the user's alarms.
-
-**Optional arguments:**
-
-``-q <QUERY>, --query <QUERY>``
- key[op]data_type::value; list. data_type is
- optional, but if supplied must be string,
- integer, float, or boolean.
-
-.. _ceilometer_alarm-show:
-
-ceilometer alarm-show
----------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-show [<ALARM_ID>]
-
-Show an alarm.
-
-**Positional arguments:**
-
-``<ALARM_ID>``
- ID of the alarm to show.
-
-.. _ceilometer_alarm-state-get:
-
-ceilometer alarm-state-get
---------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-state-get [<ALARM_ID>]
-
-Get the state of an alarm.
-
-**Positional arguments:**
-
-``<ALARM_ID>``
- ID of the alarm state to show.
-
-.. _ceilometer_alarm-state-set:
-
-ceilometer alarm-state-set
---------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-state-set --state <STATE> [<ALARM_ID>]
-
-Set the state of an alarm.
-
-**Positional arguments:**
-
-``<ALARM_ID>``
- ID of the alarm state to set.
-
-**Optional arguments:**
-
-``--state <STATE>``
- State of the alarm, one of: ['ok', 'alarm', 'insufficient
- data']. Required.
-
-.. _ceilometer_alarm-threshold-create:
-
-ceilometer alarm-threshold-create
----------------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-threshold-create --name <NAME>
- [--project-id <ALARM_PROJECT_ID>]
- [--user-id <ALARM_USER_ID>]
- [--description <DESCRIPTION>]
- [--state <STATE>]
- [--severity <SEVERITY>]
- [--enabled {True|False}]
- [--alarm-action <Webhook URL>]
- [--ok-action <Webhook URL>]
- [--insufficient-data-action <Webhook URL>]
- [--time-constraint <Time Constraint>]
- [--repeat-actions {True|False}] -m
- <METRIC> [--period <PERIOD>]
- [--evaluation-periods <COUNT>]
- [--statistic <STATISTIC>]
- [--comparison-operator <OPERATOR>]
- --threshold <THRESHOLD> [-q <QUERY>]
-
-Create a new alarm based on computed statistics.
-
-**Optional arguments:**
-
-``--name <NAME>``
- Name of the alarm (must be unique per tenant).
- Required.
-
-``--project-id <ALARM_PROJECT_ID>``
- Tenant to associate with alarm (configurable
- by admin users only).
-
-``--user-id <ALARM_USER_ID>``
- User to associate with alarm (configurable by
- admin users only).
-
-``--description <DESCRIPTION>``
- Free text description of the alarm.
-
-``--state <STATE>``
- State of the alarm, one of: ['ok', 'alarm',
- 'insufficient data']
-
-``--severity <SEVERITY>``
- Severity of the alarm, one of: ['low',
- 'moderate', 'critical']
-
-``--enabled {True|False}``
- True if alarm evaluation/actioning is enabled.
-
-``--alarm-action <Webhook URL>``
- URL to invoke when state transitions to alarm.
- May be used multiple times. Defaults to None.
-
-``--ok-action <Webhook URL>``
- URL to invoke when state transitions to OK.
- May be used multiple times. Defaults to None.
-
-``--insufficient-data-action <Webhook URL>``
- URL to invoke when state transitions to
- insufficient data. May be used multiple times.
- Defaults to None.
-
-``--time-constraint <Time Constraint>``
- Only evaluate the alarm if the time at
- evaluation is within this time constraint.
- Start point(s) of the constraint are specified
- with a cron expression, whereas its duration
- is given in seconds. Can be specified multiple
- times for multiple time constraints, format
- is: name=<CONSTRAINT_NAME>;start=<CRON>;durati
- on=<SECONDS>;[description=<DESCRIPTION>;[timez
- one=<IANA Timezone>]] Defaults to None.
-
-``--repeat-actions {True|False}``
- True if actions should be repeatedly notified
- while alarm remains in target state.
-
-``-m <METRIC>, --meter-name <METRIC>``
- Metric to evaluate against. Required.
-
-``--period <PERIOD>``
- Length of each period (seconds) to evaluate
- over.
-
-``--evaluation-periods <COUNT>``
- Number of periods to evaluate over.
-
-``--statistic <STATISTIC>``
- Statistic to evaluate, one of: ['max', 'min',
- 'avg', 'sum', 'count'].
-
-``--comparison-operator <OPERATOR>``
- Operator to compare with, one of: ['lt', 'le',
- 'eq', 'ne', 'ge', 'gt'].
-
-``--threshold <THRESHOLD>``
- Threshold to evaluate against. Required.
-
-``-q <QUERY>, --query <QUERY>``
- key[op]data_type::value; list. data_type is
- optional, but if supplied must be string,
- integer, float, or boolean.
-
-.. _ceilometer_alarm-threshold-update:
-
-ceilometer alarm-threshold-update
----------------------------------
-
-.. code-block:: console
-
- usage: ceilometer alarm-threshold-update [--name <NAME>]
- [--project-id <ALARM_PROJECT_ID>]
- [--user-id <ALARM_USER_ID>]
- [--description <DESCRIPTION>]
- [--state <STATE>]
- [--severity <SEVERITY>]
- [--enabled {True|False}]
- [--alarm-action <Webhook URL>]
- [--ok-action <Webhook URL>]
- [--insufficient-data-action <Webhook URL>]
- [--time-constraint <Time Constraint>]
- [--repeat-actions {True|False}]
- [--remove-time-constraint <Constraint names>]
- [-m <METRIC>] [--period <PERIOD>]
- [--evaluation-periods <COUNT>]
- [--statistic <STATISTIC>]
- [--comparison-operator <OPERATOR>]
- [--threshold <THRESHOLD>]
- [-q <QUERY>]
- [<ALARM_ID>]
-
-Update an existing alarm based on computed statistics.
-
-**Positional arguments:**
-
-``<ALARM_ID>``
- ID of the alarm to update.
-
-**Optional arguments:**
-
-``--name <NAME>``
- Name of the alarm (must be unique per tenant).
-
-``--project-id <ALARM_PROJECT_ID>``
- Tenant to associate with alarm (configurable
- by admin users only).
-
-``--user-id <ALARM_USER_ID>``
- User to associate with alarm (configurable by
- admin users only).
-
-``--description <DESCRIPTION>``
- Free text description of the alarm.
-
-``--state <STATE>``
- State of the alarm, one of: ['ok', 'alarm',
- 'insufficient data']
-
-``--severity <SEVERITY>``
- Severity of the alarm, one of: ['low',
- 'moderate', 'critical']
-
-``--enabled {True|False}``
- True if alarm evaluation/actioning is enabled.
-
-``--alarm-action <Webhook URL>``
- URL to invoke when state transitions to alarm.
- May be used multiple times. Defaults to None.
-
-``--ok-action <Webhook URL>``
- URL to invoke when state transitions to OK.
- May be used multiple times. Defaults to None.
-
-``--insufficient-data-action <Webhook URL>``
- URL to invoke when state transitions to
- insufficient data. May be used multiple times.
- Defaults to None.
-
-``--time-constraint <Time Constraint>``
- Only evaluate the alarm if the time at
- evaluation is within this time constraint.
- Start point(s) of the constraint are specified
- with a cron expression, whereas its duration
- is given in seconds. Can be specified multiple
- times for multiple time constraints, format
- is: name=<CONSTRAINT_NAME>;start=<CRON>;durati
- on=<SECONDS>;[description=<DESCRIPTION>;[timez
- one=<IANA Timezone>]] Defaults to None.
-
-``--repeat-actions {True|False}``
- True if actions should be repeatedly notified
- while alarm remains in target state.
-
-``--remove-time-constraint <Constraint names>``
- Name or list of names of the time constraints
- to remove.
-
-``-m <METRIC>, --meter-name <METRIC>``
- Metric to evaluate against.
-
-``--period <PERIOD>``
- Length of each period (seconds) to evaluate
- over.
-
-``--evaluation-periods <COUNT>``
- Number of periods to evaluate over.
-
-``--statistic <STATISTIC>``
- Statistic to evaluate, one of: ['max', 'min',
- 'avg', 'sum', 'count'].
-
-``--comparison-operator <OPERATOR>``
- Operator to compare with, one of: ['lt', 'le',
- 'eq', 'ne', 'ge', 'gt'].
-
-``--threshold <THRESHOLD>``
- Threshold to evaluate against.
-
-``-q <QUERY>, --query <QUERY>``
- key[op]data_type::value; list. data_type is
- optional, but if supplied must be string,
- integer, float, or boolean.
-
-.. _ceilometer_capabilities:
-
-ceilometer capabilities
------------------------
-
-.. code-block:: console
-
- usage: ceilometer capabilities
-
-Print Ceilometer capabilities.
-
-.. _ceilometer_event-list:
-
-ceilometer event-list
----------------------
-
-.. code-block:: console
-
- usage: ceilometer event-list [-q <QUERY>] [--no-traits] [-l <NUMBER>]
-
-List events.
-
-**Optional arguments:**
-
-``-q <QUERY>, --query <QUERY>``
- key[op]data_type::value; list. data_type is
- optional, but if supplied must be string,
- integer, float or datetime.
-
-``--no-traits``
- If specified, traits will not be printed.
-
-``-l <NUMBER>, --limit <NUMBER>``
- Maximum number of events to return. API server
- limits result to <default_api_return_limit>
- rows if no limit provided. Option is
- configured in ceilometer.conf [api] group
-
-.. _ceilometer_event-show:
-
-ceilometer event-show
----------------------
-
-.. code-block:: console
-
- usage: ceilometer event-show <message_id>
-
-Show a particular event.
-
-**Positional arguments:**
-
-``<message_id>``
- The ID of the event. Should be a UUID.
-
-.. _ceilometer_event-type-list:
-
-ceilometer event-type-list
---------------------------
-
-.. code-block:: console
-
- usage: ceilometer event-type-list
-
-List event types.
-
-.. _ceilometer_meter-list:
-
-ceilometer meter-list
----------------------
-
-.. code-block:: console
-
- usage: ceilometer meter-list [-q <QUERY>] [-l <NUMBER>]
- [--unique {True|False}]
-
-List the user's meters.
-
-**Optional arguments:**
-
-``-q <QUERY>, --query <QUERY>``
- key[op]data_type::value; list. data_type is
- optional, but if supplied must be string,
- integer, float, or boolean.
-
-``-l <NUMBER>, --limit <NUMBER>``
- Maximum number of meters to return. API server
- limits result to <default_api_return_limit>
- rows if no limit provided. Option is
- configured in ceilometer.conf [api] group
-
-``--unique {True|False}``
- Retrieves unique list of meters.
-
-.. _ceilometer_query-alarm-history:
-
-ceilometer query-alarm-history
-------------------------------
-
-.. code-block:: console
-
- usage: ceilometer query-alarm-history [-f <FILTER>] [-o <ORDERBY>]
- [-l <LIMIT>]
-
-Query Alarm History.
-
-**Optional arguments:**
-
-``-f <FILTER>, --filter <FILTER>``
- {complex_op: [{simple_op: {field_name:
- value}}]} The complex_op is one of: ['and',
- 'or'], simple_op is one of: ['=', '!=', '<',
- '<=', '>', '>='].
-
-``-o <ORDERBY>, --orderby <ORDERBY>``
- [{field_name: direction}, {field_name:
- direction}] The direction is one of: ['asc',
- 'desc'].
-
-``-l <LIMIT>, --limit <LIMIT>``
- Maximum number of alarm history items to
- return. API server limits result to
- <default_api_return_limit> rows if no limit
- provided. Option is configured in
- ceilometer.conf [api] group
-
-.. _ceilometer_query-alarms:
-
-ceilometer query-alarms
------------------------
-
-.. code-block:: console
-
- usage: ceilometer query-alarms [-f <FILTER>] [-o <ORDERBY>] [-l <LIMIT>]
-
-Query Alarms.
-
-**Optional arguments:**
-
-``-f <FILTER>, --filter <FILTER>``
- {complex_op: [{simple_op: {field_name:
- value}}]} The complex_op is one of: ['and',
- 'or'], simple_op is one of: ['=', '!=', '<',
- '<=', '>', '>='].
-
-``-o <ORDERBY>, --orderby <ORDERBY>``
- [{field_name: direction}, {field_name:
- direction}] The direction is one of: ['asc',
- 'desc'].
-
-``-l <LIMIT>, --limit <LIMIT>``
- Maximum number of alarms to return. API server
- limits result to <default_api_return_limit>
- rows if no limit provided. Option is
- configured in ceilometer.conf [api] group
-
-.. _ceilometer_query-samples:
-
-ceilometer query-samples
-------------------------
-
-.. code-block:: console
-
- usage: ceilometer query-samples [-f <FILTER>] [-o <ORDERBY>] [-l <LIMIT>]
-
-Query samples.
-
-**Optional arguments:**
-
-``-f <FILTER>, --filter <FILTER>``
- {complex_op: [{simple_op: {field_name:
- value}}]} The complex_op is one of: ['and',
- 'or'], simple_op is one of: ['=', '!=', '<',
- '<=', '>', '>='].
-
-``-o <ORDERBY>, --orderby <ORDERBY>``
- [{field_name: direction}, {field_name:
- direction}] The direction is one of: ['asc',
- 'desc'].
-
-``-l <LIMIT>, --limit <LIMIT>``
- Maximum number of samples to return. API
- server limits result to
- <default_api_return_limit> rows if no limit
- provided. Option is configured in
- ceilometer.conf [api] group
-
-.. _ceilometer_resource-list:
-
-ceilometer resource-list
-------------------------
-
-.. code-block:: console
-
- usage: ceilometer resource-list [-q <QUERY>] [-l <NUMBER>]
-
-List the resources.
-
-**Optional arguments:**
-
-``-q <QUERY>, --query <QUERY>``
- key[op]data_type::value; list. data_type is
- optional, but if supplied must be string,
- integer, float, or boolean.
-
-``-l <NUMBER>, --limit <NUMBER>``
- Maximum number of resources to return. API
- server limits result to
- <default_api_return_limit> rows if no limit
- provided. Option is configured in
- ceilometer.conf [api] group
-
-.. _ceilometer_resource-show:
-
-ceilometer resource-show
-------------------------
-
-.. code-block:: console
-
- usage: ceilometer resource-show <RESOURCE_ID>
-
-Show the resource.
-
-**Positional arguments:**
-
-``<RESOURCE_ID>``
- ID of the resource to show.
-
-.. _ceilometer_sample-create:
-
-ceilometer sample-create
-------------------------
-
-.. code-block:: console
-
- usage: ceilometer sample-create [--project-id <SAMPLE_PROJECT_ID>]
- [--user-id <SAMPLE_USER_ID>] -r <RESOURCE_ID>
- -m <METER_NAME> --meter-type <METER_TYPE>
- --meter-unit <METER_UNIT> --sample-volume
- <SAMPLE_VOLUME>
- [--resource-metadata <RESOURCE_METADATA>]
- [--timestamp <TIMESTAMP>] [--direct <DIRECT>]
-
-Create a sample.
-
-**Optional arguments:**
-
-``--project-id <SAMPLE_PROJECT_ID>``
- Tenant to associate with sample (configurable
- by admin users only).
-
-``--user-id <SAMPLE_USER_ID>``
- User to associate with sample (configurable by
- admin users only).
-
-``-r <RESOURCE_ID>, --resource-id <RESOURCE_ID>``
- ID of the resource. Required.
-
-``-m <METER_NAME>, --meter-name <METER_NAME>``
- The meter name. Required.
-
-``--meter-type <METER_TYPE>``
- The meter type. Required.
-
-``--meter-unit <METER_UNIT>``
- The meter unit. Required.
-
-``--sample-volume <SAMPLE_VOLUME>``
- The sample volume. Required.
-
-``--resource-metadata <RESOURCE_METADATA>``
- Resource metadata. Provided value should be a
- set of key-value pairs e.g. {"key":"value"}.
-
-``--timestamp <TIMESTAMP>``
- The sample timestamp.
-
-``--direct <DIRECT>``
- Post sample to storage directly. Defaults to
- False.
-
-.. _ceilometer_sample-create-list:
-
-ceilometer sample-create-list
------------------------------
-
-.. code-block:: console
-
- usage: ceilometer sample-create-list [--direct <DIRECT>] <SAMPLES_LIST>
-
-Create a sample list.
-
-**Positional arguments:**
-
-``<SAMPLES_LIST>``
- Json array with samples to create.
-
-**Optional arguments:**
-
-``--direct <DIRECT>``
- Post samples to storage directly. Defaults to False.
-
-.. _ceilometer_sample-list:
-
-ceilometer sample-list
-----------------------
-
-.. code-block:: console
-
- usage: ceilometer sample-list [-q <QUERY>] [-m <NAME>] [-l <NUMBER>]
-
-List the samples (return OldSample objects if -m/--meter is set).
-
-**Optional arguments:**
-
-``-q <QUERY>, --query <QUERY>``
- key[op]data_type::value; list. data_type is
- optional, but if supplied must be string,
- integer, float, or boolean.
-
-``-m <NAME>, --meter <NAME>``
- Name of meter to show samples for.
-
-``-l <NUMBER>, --limit <NUMBER>``
- Maximum number of samples to return. API
- server limits result to
- <default_api_return_limit> rows if no limit
- provided. Option is configured in
- ceilometer.conf [api] group
-
-.. _ceilometer_sample-show:
-
-ceilometer sample-show
-----------------------
-
-.. code-block:: console
-
- usage: ceilometer sample-show <SAMPLE_ID>
-
-Show a sample.
-
-**Positional arguments:**
-
-``<SAMPLE_ID>``
- ID (aka message ID) of the sample to show.
-
-.. _ceilometer_statistics:
-
-ceilometer statistics
----------------------
-
-.. code-block:: console
-
- usage: ceilometer statistics [-q <QUERY>] -m <NAME> [-p <PERIOD>] [-g <FIELD>]
- [-a <FUNC>[<-<PARAM>]]
-
-List the statistics for a meter.
-
-**Optional arguments:**
-
-``-q <QUERY>, --query <QUERY>``
- key[op]data_type::value; list. data_type is
- optional, but if supplied must be string,
- integer, float, or boolean.
-
-``-m <NAME>, --meter <NAME>``
- Name of meter to list statistics for.
- Required.
-
-``-p <PERIOD>, --period <PERIOD>``
- Period in seconds over which to group samples.
-
-``-g <FIELD>, --groupby <FIELD>``
- Field for group by.
-
-``-a <FUNC>[<-<PARAM>], --aggregate <FUNC>[<-<PARAM>]``
- Function for data aggregation. Available
- aggregates are: count, cardinality, min, max,
- sum, stddev, avg. Defaults to [].
-
-.. _ceilometer_trait-description-list:
-
-ceilometer trait-description-list
----------------------------------
-
-.. code-block:: console
-
- usage: ceilometer trait-description-list -e <EVENT_TYPE>
-
-List trait info for an event type.
-
-**Optional arguments:**
-
-``-e <EVENT_TYPE>, --event_type <EVENT_TYPE>``
- Type of the event for which traits will be
- shown. Required.
-
-.. _ceilometer_trait-list:
-
-ceilometer trait-list
----------------------
-
-.. code-block:: console
-
- usage: ceilometer trait-list -e <EVENT_TYPE> -t <TRAIT_NAME>
-
-List all traits with name <trait_name> for Event Type <event_type>.
-
-**Optional arguments:**
-
-``-e <EVENT_TYPE>, --event_type <EVENT_TYPE>``
- Type of the event for which traits will
- listed. Required.
-
-``-t <TRAIT_NAME>, --trait_name <TRAIT_NAME>``
- The name of the trait to list. Required.
-
diff --git a/doc/source/conf.py b/doc/source/conf.py
deleted file mode 100644
index 00d4a79..0000000
--- a/doc/source/conf.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import os
-execfile(os.path.join("..", "ext", "gen_ref.py"))
-
-project = 'python-ceilometerclient'
-
-gen_ref("", "Client Reference", ["client", "exc"])
-gen_ref("v2", "Version 2 API Reference",
- ["meters", "samples", "statistics", "resources", "query", "alarms",
- "events", "event_types", "traits", "trait_descriptions"])
-
-# -- General configuration ----------------------------------------------------
-
-# Add any Sphinx extension module names here, as strings. They can be
-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'openstackdocstheme']
-
-# autodoc generation is a bit aggressive and a nuisance when doing heavy
-# text edit cycles.
-# execute "export SPHINX_DEBUG=1" in your terminal to disable
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-copyright = u'OpenStack Foundation'
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-add_module_names = True
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# -- Options for HTML output --------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. Major themes that come with
-# Sphinx are currently 'default' and 'sphinxdoc'.
-#html_theme = 'nature'
-html_theme = 'openstackdocs'
-
-# openstackdocstheme options
-repository_name = 'openstack/python-ceilometerclient'
-bug_project = 'python-ceilometerclient'
-bug_tag = ''
-
-# Must set this variable to include year, month, day, hours, and minutes.
-html_last_updated_fmt = '%Y-%m-%d %H:%M'
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = '%sdoc' % project
-
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass
-# [howto/manual]).
-latex_documents = [
- (
- 'index',
- '%s.tex' % project,
- u'%s Documentation' % project,
- u'OpenStack Foundation',
- 'manual'
- ),
-]
diff --git a/doc/source/index.rst b/doc/source/index.rst
deleted file mode 100644
index eabd851..0000000
--- a/doc/source/index.rst
+++ /dev/null
@@ -1,56 +0,0 @@
-Python bindings to the OpenStack Ceilometer API
-==================================================
-
-This is a client for OpenStack Ceilometer API. There's :doc:`a Python API
-<api>` (the :mod:`ceilometerclient` module), and a :doc:`command-line script
-<shell>` (installed as :program:`ceilometer`). Each implements the entire
-OpenStack Ceilometer API.
-
-.. seealso::
-
- You may want to read the `OpenStack Ceilometer Developer Guide`__ -- the overview, at
- least -- to get an idea of the concepts. By understanding the concepts
- this library should make more sense.
-
- __ https://docs.openstack.org/ceilometer/latest/
-
-Contents:
-
-.. toctree::
- :maxdepth: 2
-
- shell
- api
- ref/index
- ref/v2/index
-
-The command-line client
-=======================
-
-The ceilometer client is the command-line interface (CLI) for
-the Telemetry Data Collection service (ceilometer) API
-and its extensions.
-
-.. toctree::
-
- cli
-
-Contributing
-============
-
-Code is hosted at `git.openstack.org`_. Submit bugs to the Ceilometer project on
-`Launchpad`_. Submit code to the openstack/python-ceilometerclient project using
-`Gerrit`_.
-
-.. _git.openstack.org: https://git.openstack.org/cgit/openstack/python-ceilometerclient
-.. _Launchpad: https://launchpad.net/ceilometer
-.. _Gerrit: https://docs.openstack.org/infra/manual/developers.html#development-workflow
-
-Run tests with ``python setup.py test``.
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
diff --git a/doc/source/shell.rst b/doc/source/shell.rst
deleted file mode 100644
index a35a9a1..0000000
--- a/doc/source/shell.rst
+++ /dev/null
@@ -1,61 +0,0 @@
-The :program:`ceilometer` shell utility
-=========================================
-
-.. program:: ceilometer
-.. highlight:: bash
-
-The :program:`ceilometer` shell utility interacts with OpenStack Ceilometer API
-from the command line. It supports the entirety of the OpenStack Ceilometer API.
-
-You'll need to provide :program:`ceilometer` with your OpenStack credentials.
-You can do this with the :option:`--os-username`, :option:`--os-password`,
-:option:`--os-tenant-id` and :option:`--os-auth-url` options, but it's easier to
-just set them as environment variables:
-
-.. envvar:: OS_USERNAME
-
- Your OpenStack username.
-
-.. envvar:: OS_PASSWORD
-
- Your password.
-
-.. envvar:: OS_TENANT_NAME
-
- Project to work on.
-
-.. envvar:: OS_AUTH_URL
-
- The OpenStack auth server URL (keystone).
-
-For example, in Bash you would use::
-
- export OS_USERNAME=user
- export OS_PASSWORD=pass
- export OS_TENANT_NAME=myproject
- export OS_AUTH_URL=http://auth.example.com:5000/v2.0
-
-The command line tool will attempt to reauthenticate using your provided credentials
-for every request. You can override this behavior by manually supplying an auth
-token using :option:`--os-ceilometer-url` and :option:`--os-auth-token`. You can alternatively
-set these environment variables::
-
- export OS_CEILOMETER_URL=http://ceilometer.example.org:8777
- export OS_AUTH_TOKEN=3bcc3d3a03f44e3d8377f9247b0ad155
-
-From there, all shell commands take the form::
-
- ceilometer <command> [arguments...]
-
-Run :program:`ceilometer help` to get a full list of all possible commands,
-and run :program:`ceilometer help <command>` to get detailed help for that
-command.
-
-V2 client tips
-++++++++++++++
-
-Use queries to narrow your search (more info at `Ceilometer V2 API reference`__)::
-
- ceilometer sample-list --meter cpu_util --query 'resource_id=5a301761-f78b-46e2-8900-8b4f6fe6675a' --limit 10
-
-__ https://docs.openstack.org/ceilometer/latest/webapi/v2.html#Query
diff --git a/releasenotes/notes/.placeholder b/releasenotes/notes/.placeholder
deleted file mode 100644
index e69de29..0000000
--- a/releasenotes/notes/.placeholder
+++ /dev/null
diff --git a/releasenotes/notes/alarm_deprecated-74363d70d48a20e2.yaml b/releasenotes/notes/alarm_deprecated-74363d70d48a20e2.yaml
deleted file mode 100644
index f50901b..0000000
--- a/releasenotes/notes/alarm_deprecated-74363d70d48a20e2.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-deprecations:
- - Alarm commands are deprecated in favor of aodhclient.
diff --git a/releasenotes/notes/deprecation-44ae455f4ef3a81e.yaml b/releasenotes/notes/deprecation-44ae455f4ef3a81e.yaml
deleted file mode 100644
index 8a182a5..0000000
--- a/releasenotes/notes/deprecation-44ae455f4ef3a81e.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-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 --git a/releasenotes/notes/panko-redirect-9d03598dbf51f8fd.yaml b/releasenotes/notes/panko-redirect-9d03598dbf51f8fd.yaml
deleted file mode 100644
index 36f1c8e..0000000
--- a/releasenotes/notes/panko-redirect-9d03598dbf51f8fd.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-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 --git a/releasenotes/source/_static/.placeholder b/releasenotes/source/_static/.placeholder
deleted file mode 100644
index e69de29..0000000
--- a/releasenotes/source/_static/.placeholder
+++ /dev/null
diff --git a/releasenotes/source/_templates/.placeholder b/releasenotes/source/_templates/.placeholder
deleted file mode 100644
index e69de29..0000000
--- a/releasenotes/source/_templates/.placeholder
+++ /dev/null
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
deleted file mode 100644
index 9ddac03..0000000
--- a/releasenotes/source/conf.py
+++ /dev/null
@@ -1,284 +0,0 @@
-# -*- coding: utf-8 -*-
-# 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.
-#
-# Ceilometer Client Release Notes documentation build configuration file,
-# created by sphinx-quickstart on Mon Nov 23 20:38:38 2015.
-#
-# This file is execfile()d with the current directory set to its
-# containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-# sys.path.insert(0, os.path.abspath('.'))
-
-# -- General configuration ------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-# needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be
-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
-# ones.
-extensions = [
- 'reno.sphinxext',
- 'openstackdocstheme'
-]
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-# source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u'Ceilometer Client Release Notes'
-copyright = u'2015-present, Ceilometer developers'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-import pbr.version
-ceilometer_version = pbr.version.VersionInfo('python-ceilometerclient')
-# The short X.Y version.
-version = ceilometer_version.canonical_version_string()
-# The full version, including alpha/beta/rc tags.
-release = ceilometer_version.version_string_with_vcs()
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-# language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-# today = ''
-# Else, today_fmt is used as the format for a strftime call.
-# today_fmt = '%B %d, %Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-exclude_patterns = []
-
-# The reST default role (used for this markup: `text`) to use for all
-# documents.
-# default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-# add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-# add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-# show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-# A list of ignored prefixes for module index sorting.
-# modindex_common_prefix = []
-
-# If true, keep warnings as "system message" paragraphs in the built documents.
-# keep_warnings = False
-
-
-# -- Options for HTML output ----------------------------------------------
-
-# The theme to use for HTML and HTML Help pages. See the documentation for
-# a list of builtin themes.
-html_theme = 'openstackdocs'
-
-# openstackdocstheme options
-repository_name = 'openstack/python-ceilometerclient'
-bug_project = 'python-ceilometerclient'
-bug_tag = ''
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further. For a list of options available for each theme, see the
-# documentation.
-# html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-# html_theme_path = []
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-# html_title = None
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-# html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-# html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-# html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# Add any extra paths that contain custom files (such as robots.txt or
-# .htaccess) here, relative to this directory. These files are copied
-# directly to the root of the documentation.
-# html_extra_path = []
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-# html_last_updated_fmt = '%b %d, %Y'
-html_last_updated_fmt = '%Y-%m-%d %H:%M'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-# html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-# html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-# html_additional_pages = {}
-
-# If false, no module index is generated.
-# html_domain_indices = True
-
-# If false, no index is generated.
-# html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-# html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-# html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-# html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-# html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-# html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-# html_file_suffix = None
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'CeilometerClientReleaseNotestdoc'
-
-
-# -- Options for LaTeX output ---------------------------------------------
-
-latex_elements = {
- # The paper size ('letterpaper' or 'a4paper').
- # 'papersize': 'letterpaper',
-
- # The font size ('10pt', '11pt' or '12pt').
- # 'pointsize': '10pt',
-
- # Additional stuff for the LaTeX preamble.
- # 'preamble': '',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title,
-# author, documentclass [howto, manual, or own class]).
-latex_documents = [
- ('index', 'PythonCeilometerClient.tex',
- u'Ceilometer Client Release Notes Documentation',
- u'Ceilometer developers', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-# latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-# latex_use_parts = False
-
-# If true, show page references after internal links.
-# latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-# latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-# latex_appendices = []
-
-# If false, no module index is generated.
-# latex_domain_indices = True
-
-
-# -- Options for manual page output ---------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('index', 'pythonceilometerclient',
- u'Ceilometer Client Release Notes Documentation',
- [u'Ceilometer developers'], 1)
-]
-
-# If true, show URL addresses after external links.
-# man_show_urls = False
-
-
-# -- Options for Texinfo output -------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-# dir menu entry, description, category)
-texinfo_documents = [
- ('index', 'PythonCeilometerClient',
- u'Ceilometer Client Release Notes Documentation',
- u'Ceilometer developers', 'PythonCeilometerClient',
- 'One line description of project.', 'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-# texinfo_appendices = []
-
-# If false, no module index is generated.
-# texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-# texinfo_show_urls = 'footnote'
-
-# 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 --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
deleted file mode 100644
index 17fb7a5..0000000
--- a/releasenotes/source/index.rst
+++ /dev/null
@@ -1,21 +0,0 @@
-Welcome to Ceilometer Client Release Notes documentation!
-=========================================================
-
-Contents
-========
-
-.. toctree::
- :maxdepth: 2
-
- unreleased
- pike
- ocata
- newton
- mitaka
- liberty
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`search`
diff --git a/releasenotes/source/liberty.rst b/releasenotes/source/liberty.rst
deleted file mode 100644
index 36217be..0000000
--- a/releasenotes/source/liberty.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-==============================
- Liberty Series Release Notes
-==============================
-
-.. release-notes::
- :branch: origin/stable/liberty
diff --git a/releasenotes/source/mitaka.rst b/releasenotes/source/mitaka.rst
deleted file mode 100644
index e545609..0000000
--- a/releasenotes/source/mitaka.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-===================================
- Mitaka Series Release Notes
-===================================
-
-.. release-notes::
- :branch: origin/stable/mitaka
diff --git a/releasenotes/source/newton.rst b/releasenotes/source/newton.rst
deleted file mode 100644
index 97036ed..0000000
--- a/releasenotes/source/newton.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-===================================
- Newton Series Release Notes
-===================================
-
-.. release-notes::
- :branch: origin/stable/newton
diff --git a/releasenotes/source/ocata.rst b/releasenotes/source/ocata.rst
deleted file mode 100644
index ebe62f4..0000000
--- a/releasenotes/source/ocata.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-===================================
- Ocata Series Release Notes
-===================================
-
-.. release-notes::
- :branch: origin/stable/ocata
diff --git a/releasenotes/source/pike.rst b/releasenotes/source/pike.rst
deleted file mode 100644
index e43bfc0..0000000
--- a/releasenotes/source/pike.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-===================================
- Pike Series Release Notes
-===================================
-
-.. release-notes::
- :branch: stable/pike
diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst
deleted file mode 100644
index 875030f..0000000
--- a/releasenotes/source/unreleased.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-============================
-Current Series Release Notes
-============================
-
-.. release-notes::
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index f13ff9b..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-# The order of packages is significant, because pip processes them in the order
-# of appearance. Changing the order has an impact on the overall integration
-# process, which may cause wedges in the gate later.
-pbr>=1.6 # Apache-2.0
-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.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
-stevedore>=1.10.0 # Apache-2.0
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 5df04f3..0000000
--- a/setup.cfg
+++ /dev/null
@@ -1,42 +0,0 @@
-[metadata]
-name = python-ceilometerclient
-summary = OpenStack Telemetry API Client Library
-description-file =
- README.rst
-author = OpenStack
-author-email = openstack-dev@lists.openstack.org
-home-page = https://docs.openstack.org/python-ceilometerclient/latest/
-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
-
-[global]
-setup-hooks =
- pbr.hooks.setup_hook
-
-[entry_points]
-console_scripts =
- ceilometer = ceilometerclient.shell:main
-
-[build_sphinx]
-source-dir = doc/source
-build-dir = doc/build
-all_files = 1
-
-[upload_sphinx]
-upload-dir = doc/build/html
-
-[wheel]
-universal = 1
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 782bb21..0000000
--- a/setup.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
-#
-# 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 FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
-import setuptools
-
-# In python < 2.7.4, a lazy loading of package `pbr` will break
-# setuptools if some other modules registered functions in `atexit`.
-# solution from: http://bugs.python.org/issue15881#msg170215
-try:
- import multiprocessing # noqa
-except ImportError:
- pass
-
-setuptools.setup(
- setup_requires=['pbr>=1.8'],
- pbr=True)
diff --git a/test-requirements.txt b/test-requirements.txt
deleted file mode 100644
index b033e82..0000000
--- a/test-requirements.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-# The order of packages is significant, because pip processes them in the order
-# of appearance. Changing the order has an impact on the overall integration
-# process, which may cause wedges in the gate later.
-# Hacking already pins down pep8, pyflakes and flake8
-coverage>=3.6 # Apache-2.0
-fixtures<2.0,>=1.3.1 # Apache-2.0/BSD
-mock>=1.2 # BSD
-openstackdocstheme>=1.11.0 # Apache-2.0
-reno>=1.6.2 # Apache2
-python-subunit>=0.0.18 # Apache-2.0/BSD
-sphinx>=1.6.2 # BSD
-tempest>=11.0.0 # Apache-2.0
-testrepository>=0.0.18 # Apache-2.0/BSD
-testtools>=1.4.0 # MIT
diff --git a/tools/ceilometer.bash_completion b/tools/ceilometer.bash_completion
deleted file mode 100644
index b2b48b2..0000000
--- a/tools/ceilometer.bash_completion
+++ /dev/null
@@ -1,27 +0,0 @@
-# bash completion for openstack ceilometer
-
-_ceilometer_opts="" # lazy init
-_ceilometer_flags="" # lazy init
-_ceilometer_opts_exp="" # lazy init
-_ceilometer()
-{
- local cur prev kbc
- COMPREPLY=()
- cur="${COMP_WORDS[COMP_CWORD]}"
- prev="${COMP_WORDS[COMP_CWORD-1]}"
-
- if [ "x$_ceilometer_opts" == "x" ] ; then
- kbc="`ceilometer bash-completion | sed -e "s/ -h / /"`"
- _ceilometer_opts="`echo "$kbc" | sed -e "s/--[a-z0-9_-]*//g" -e "s/[ ][ ]*/ /g"`"
- _ceilometer_flags="`echo " $kbc" | sed -e "s/ [^-][^-][a-z0-9_-]*//g" -e "s/[ ][ ]*/ /g"`"
- _ceilometer_opts_exp="`echo $_ceilometer_opts | sed -e "s/[ ]/|/g"`"
- fi
-
- if [[ " ${COMP_WORDS[@]} " =~ " "($_ceilometer_opts_exp)" " && "$prev" != "help" ]] ; then
- COMPREPLY=($(compgen -W "${_ceilometer_flags}" -- ${cur}))
- else
- COMPREPLY=($(compgen -W "${_ceilometer_opts}" -- ${cur}))
- fi
- return 0
-}
-complete -F _ceilometer ceilometer
diff --git a/tox.ini b/tox.ini
deleted file mode 100644
index dccf6b5..0000000
--- a/tox.ini
+++ /dev/null
@@ -1,45 +0,0 @@
-[tox]
-envlist = py35,py27,pypy,pep8
-minversion = 1.6
-skipsdist = True
-
-[testenv]
-usedevelop = True
-install_command = pip install -U {opts} {packages}
-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.13,>=0.12
-commands = flake8
-
-[testenv:cover]
-commands =
- python setup.py testr --coverage --testr-args='{posargs}'
- coverage report
-
-[testenv:venv]
-commands = {posargs}
-
-[testenv:functional]
-setenv = OS_TEST_PATH=./ceilometerclient/tests/functional
-passenv = OS_*
-
-[testenv:docs]
-commands=
- python setup.py build_sphinx
-
-[testenv:releasenotes]
-commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
-
-[flake8]
-show-source = True
-exclude = .venv,.git,.tox,dist,doc,*lib/python*,*egg,build,tools
-
-[hacking]
-import_exceptions =
- ceilometerclient.i18n