Remove Ceilometer support

Our current Ceilometer driver relies on old version of ceilometer client,
which is in deprecated state and not compatible with the latest Telemetry
projects (Panko, Gnocchi). The functionality of the driver is not tested
automatically and most probably broken. So it's time to let it go and
clean the code.

This patch leaves "messaging" driver as default for notification and
makes "connection-string" a required parameter in CLI. In the future
we may consider to change default notification driver, though it
requires proper release note handling in all affected projects.

Change-Id: Id8442c4ff13c5cc33fd909b4757757cc5f396f50
This commit is contained in:
Ilya Shakhat 2018-01-11 17:07:16 +01:00
parent 599060387e
commit 0bb909c7a0
12 changed files with 17 additions and 719 deletions

View File

@ -10,11 +10,11 @@ that control this:
* ``OSPROFILER_COLLECTOR`` specifies which collector to install in DevStack.
By default OSProfiler plugin does not install anything, thus default
messaging driver with Ceilometer storage will be used.
messaging driver will be used.
Possible values:
* ``<empty>`` - default messaging driver with Ceilometer is used
* ``<empty>`` - default messaging driver is used
* ``redis`` - Redis is installed
The default value of ``OSPROFILER_CONNECTION_STRING`` is set automatically
@ -50,13 +50,6 @@ file and add the following to ``[[local|localrc]]`` section:
``OSPROFILER_CONNECTION_STRING`` variable (refer to the next section for
details)
* to use default Ceilometer driver::
enable_plugin panko https://git.openstack.org/openstack/panko master
enable_plugin ceilometer https://git.openstack.org/openstack/ceilometer master
enable_plugin osprofiler https://git.openstack.org/openstack/osprofiler master
Note: the order of enabling plugins matters.
Run DevStack as normal::
@ -74,7 +67,7 @@ a comma-separated list of string values::
OSPROFILER_HMAC_KEYS=swordfish,foxtrot,charlie
**OSPROFILER_CONNECTION_STRING** - connection string to identify the driver.
Default value is ``messaging://`` refers to Ceilometer driver. For a full
Default value is ``messaging://`` refers to messaging driver. For a full
list of drivers please refer to
``http://git.openstack.org/cgit/openstack/osprofiler/tree/osprofiler/drivers``.
Example: enable ElasticSearch driver with the server running on localhost::
@ -83,7 +76,7 @@ Example: enable ElasticSearch driver with the server running on localhost::
**OSPROFILER_COLLECTOR** - controls which collector to install into DevStack.
The driver is then chosen automatically based on the collector. Empty value assumes
that the default messaging driver with Ceilometer is used.
that the default messaging driver is used.
Example: enable Redis collector::
OSPROFILER_COLLECTOR=redis

View File

@ -36,9 +36,6 @@ for i in $(seq 1 ${NOVA_NUM_CELLS}); do
CONF_FILES+=(${conf})
done
# This will update CEILOMETER_NOTIFICATION_TOPICS in ceilometer.conf file
export CEILOMETER_NOTIFICATION_TOPICS=notifications,profiler
# Functions
# ---------
@ -86,11 +83,6 @@ function configure_osprofiler() {
VAL=${VAL/catch_errors/catch_errors osprofiler}
iniset $Q_API_PASTE_FILE composite:neutronapi_v2_0 keystone "$VAL"
fi
if [ -f $CEILOMETER_CONF ]
then
iniset $CEILOMETER_CONF event store_raw info
fi
}

View File

@ -232,8 +232,8 @@ Available commands:
$ osprofiler trace show <trace_id> --json/--html --out /path/to/file
* In latest versions of OSProfiler with storage drivers (e.g. MongoDB (URI:
``mongodb://``), Messaging (URI: ``messaging://``), and Ceilometer
(URI: ``ceilometer://``)) ``--connection-string`` parameter should be set up:
``mongodb://``), Messaging (URI: ``messaging://``))
``--connection-string`` parameter should be set up:
.. parsed-literal::

View File

@ -32,11 +32,10 @@ class TraceCommands(BaseCommand):
@cliutils.arg("trace", help="File with trace or trace id")
@cliutils.arg("--connection-string", dest="conn_str",
default=(cliutils.env("OSPROFILER_CONNECTION_STRING") or
"ceilometer://"),
default=(cliutils.env("OSPROFILER_CONNECTION_STRING")),
required=True,
help="Storage driver's connection string. Defaults to "
"env[OSPROFILER_CONNECTION_STRING] if set, else "
"ceilometer://")
"env[OSPROFILER_CONNECTION_STRING] if set")
@cliutils.arg("--transport-url", dest="transport_url",
help="Oslo.messaging transport URL (for messaging:// driver "
"only), e.g. rabbit://user:password@host:5672/")
@ -74,8 +73,6 @@ class TraceCommands(BaseCommand):
"used in the command." % args.trace)
raise exc.CommandError(msg)
# NOTE(ayelistratov): Ceilometer translates datetime objects to
# strings, other drivers store this data in ISO Date format.
# Since datetime.datetime is not JSON serializable by default,
# this method will handle that.
def datetime_json_serialize(obj):

View File

@ -25,7 +25,6 @@ import sys
from oslo_config import cfg
import osprofiler
from osprofiler.cmd import cliutils
from osprofiler.cmd import commands
from osprofiler import exc
from osprofiler import opts
@ -50,134 +49,10 @@ class OSProfilerShell(object):
action="version",
version=osprofiler.__version__)
self._append_ceilometer_args(parser)
self._append_identity_args(parser)
self._append_subcommands(parser)
return parser
def _append_ceilometer_args(self, parent_parser):
parser = parent_parser.add_argument_group("ceilometer")
parser.add_argument(
"--ceilometer-url", default=cliutils.env("CEILOMETER_URL"),
help="Defaults to env[CEILOMETER_URL].")
parser.add_argument(
"--ceilometer-api-version",
default=cliutils.env("CEILOMETER_API_VERSION", default="2"),
help="Defaults to env[CEILOMETER_API_VERSION] or 2.")
def _append_identity_args(self, parent_parser):
# FIXME(fabgia): identity related parameters should be passed by the
# Keystone client itself to avoid constant update in all the services
# clients. When this fix is merged this method can be made obsolete.
# Bug: https://bugs.launchpad.net/python-keystoneclient/+bug/1332337
parser = parent_parser.add_argument_group("identity")
parser.add_argument("-k", "--insecure",
default=False,
action="store_true",
help="Explicitly allow osprofiler to "
"perform \"insecure\" SSL (https) requests. "
"The server's certificate will "
"not be verified against any certificate "
"authorities. This option should be used with "
"caution.")
# User related options
parser.add_argument("--os-username",
default=cliutils.env("OS_USERNAME"),
help="Defaults to env[OS_USERNAME].")
parser.add_argument("--os-user-id",
default=cliutils.env("OS_USER_ID"),
help="Defaults to env[OS_USER_ID].")
parser.add_argument("--os-password",
default=cliutils.env("OS_PASSWORD"),
help="Defaults to env[OS_PASSWORD].")
# Domain related options
parser.add_argument("--os-user-domain-id",
default=cliutils.env("OS_USER_DOMAIN_ID"),
help="Defaults to env[OS_USER_DOMAIN_ID].")
parser.add_argument("--os-user-domain-name",
default=cliutils.env("OS_USER_DOMAIN_NAME"),
help="Defaults to env[OS_USER_DOMAIN_NAME].")
parser.add_argument("--os-project-domain-id",
default=cliutils.env("OS_PROJECT_DOMAIN_ID"),
help="Defaults to env[OS_PROJECT_DOMAIN_ID].")
parser.add_argument("--os-project-domain-name",
default=cliutils.env("OS_PROJECT_DOMAIN_NAME"),
help="Defaults to env[OS_PROJECT_DOMAIN_NAME].")
# Project V3 or Tenant V2 related options
parser.add_argument("--os-project-id",
default=cliutils.env("OS_PROJECT_ID"),
help="Another way to specify tenant ID. "
"This option is mutually exclusive with "
" --os-tenant-id. "
"Defaults to env[OS_PROJECT_ID].")
parser.add_argument("--os-project-name",
default=cliutils.env("OS_PROJECT_NAME"),
help="Another way to specify tenant name. "
"This option is mutually exclusive with "
" --os-tenant-name. "
"Defaults to env[OS_PROJECT_NAME].")
parser.add_argument("--os-tenant-id",
default=cliutils.env("OS_TENANT_ID"),
help="This option is mutually exclusive with "
" --os-project-id. "
"Defaults to env[OS_PROJECT_ID].")
parser.add_argument("--os-tenant-name",
default=cliutils.env("OS_TENANT_NAME"),
help="Defaults to env[OS_TENANT_NAME].")
# Auth related options
parser.add_argument("--os-auth-url",
default=cliutils.env("OS_AUTH_URL"),
help="Defaults to env[OS_AUTH_URL].")
parser.add_argument("--os-auth-token",
default=cliutils.env("OS_AUTH_TOKEN"),
help="Defaults to env[OS_AUTH_TOKEN].")
parser.add_argument("--os-cacert",
metavar="<ca-certificate-file>",
dest="os_cacert",
default=cliutils.env("OS_CACERT"),
help="Path of CA TLS certificate(s) used to verify"
" the remote server\"s certificate. Without this "
"option ceilometer looks for the default system CA"
" certificates.")
parser.add_argument("--os-cert",
help="Path of certificate file to use in SSL "
"connection. This file can optionally be "
"prepended with the private key.")
parser.add_argument("--os-key",
help="Path of client key to use in SSL "
"connection. This option is not necessary "
"if your key is prepended to your cert file.")
# Service Catalog related options
parser.add_argument("--os-service-type",
default=cliutils.env("OS_SERVICE_TYPE"),
help="Defaults to env[OS_SERVICE_TYPE].")
parser.add_argument("--os-endpoint-type",
default=cliutils.env("OS_ENDPOINT_TYPE"),
help="Defaults to env[OS_ENDPOINT_TYPE].")
parser.add_argument("--os-region-name",
default=cliutils.env("OS_REGION_NAME"),
help="Defaults to env[OS_REGION_NAME].")
def _append_subcommands(self, parent_parser):
subcommands = parent_parser.add_subparsers(help="<subcommands>")
for group_cls in commands.BaseCommand.__subclasses__():

View File

@ -1,5 +1,4 @@
from osprofiler.drivers import base # noqa
from osprofiler.drivers import ceilometer # noqa
from osprofiler.drivers import elasticsearch_driver # noqa
from osprofiler.drivers import loginsight # noqa
from osprofiler.drivers import messaging # noqa

View File

@ -1,79 +0,0 @@
# Copyright 2016 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# 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 osprofiler.drivers import base
from osprofiler import exc
class Ceilometer(base.Driver):
def __init__(self, connection_str, **kwargs):
"""Driver receiving profiled information from ceilometer."""
super(Ceilometer, self).__init__(connection_str)
try:
import ceilometerclient.client
except ImportError:
raise exc.CommandError(
"To use this command, you should install "
"'ceilometerclient' manually. Use command:\n "
"'pip install python-ceilometerclient'.")
try:
self.client = ceilometerclient.client.get_client(
kwargs["ceilometer_api_version"], **kwargs)
except Exception as e:
if hasattr(e, "http_status") and e.http_status == 401:
msg = "Invalid OpenStack Identity credentials."
else:
msg = "Error occurred while connecting to Ceilometer: %s." % e
raise exc.CommandError(msg)
@classmethod
def get_name(cls):
return "ceilometer"
def get_report(self, base_id):
"""Retrieves and parses notification from ceilometer.
:param base_id: Base id of trace elements.
"""
_filter = [{"field": "base_id", "op": "eq", "value": base_id}]
# limit is hardcoded in this code state. Later that will be changed via
# connection string usage
notifications = [n.to_dict()
for n in self.client.events.list(_filter,
limit=100000)]
for n in notifications:
traits = n["traits"]
def find_field(f_name):
return [t["value"] for t in traits if t["name"] == f_name][0]
trace_id = find_field("trace_id")
parent_id = find_field("parent_id")
name = find_field("name")
project = find_field("project")
service = find_field("service")
host = find_field("host")
timestamp = find_field("timestamp")
payload = n.get("raw", {}).get("payload", {})
self._append_results(trace_id, parent_id, name, project, service,
host, timestamp, payload)
return self._parse_results()

View File

@ -83,9 +83,7 @@ class Messaging(base.Driver):
:param info: Contains information about trace element.
In payload dict there are always 3 ids:
"base_id" - uuid that is common for all notifications
related to one trace. Used to simplify
retrieving of all trace elements from
Ceilometer.
related to one trace.
"parent_id" - uuid of parent element in trace
"trace_id" - uuid of current element in trace

View File

@ -378,7 +378,7 @@ class _Profiler(object):
"""Start new event.
Adds new trace_id to trace stack and sends notification
to collector (may be ceilometer). With "info" and 3 ids:
to collector. With "info" and 3 ids:
base_id - to be able to retrieve all trace elements by one query
parent_id - to build tree of events (not just a list)
trace_id - current event id.

View File

@ -34,42 +34,13 @@ class ShellTestCase(test.TestCase):
def setUp(self):
super(ShellTestCase, self).setUp()
self.old_environment = os.environ.copy()
os.environ = {
"OS_USERNAME": "username",
"OS_USER_ID": "user_id",
"OS_PASSWORD": "password",
"OS_USER_DOMAIN_ID": "user_domain_id",
"OS_USER_DOMAIN_NAME": "user_domain_name",
"OS_PROJECT_DOMAIN_ID": "project_domain_id",
"OS_PROJECT_DOMAIN_NAME": "project_domain_name",
"OS_PROJECT_ID": "project_id",
"OS_PROJECT_NAME": "project_name",
"OS_TENANT_ID": "tenant_id",
"OS_TENANT_NAME": "tenant_name",
"OS_AUTH_URL": "http://127.0.0.1:5000/v3/",
"OS_AUTH_TOKEN": "pass",
"OS_CACERT": "/path/to/cacert",
"OS_SERVICE_TYPE": "service_type",
"OS_ENDPOINT_TYPE": "public",
"OS_REGION_NAME": "test"
}
self.ceiloclient = mock.MagicMock()
sys.modules["ceilometerclient"] = self.ceiloclient
self.addCleanup(sys.modules.pop, "ceilometerclient", None)
ceilo_modules = ["client", "shell"]
for module in ceilo_modules:
sys.modules["ceilometerclient.%s" % module] = getattr(
self.ceiloclient, module)
self.addCleanup(
sys.modules.pop, "ceilometerclient.%s" % module, None)
def tearDown(self):
super(ShellTestCase, self).tearDown()
os.environ = self.old_environment
def _trace_show_cmd(self, format_=None):
cmd = "trace show %s" % self.TRACE_ID
cmd = "trace show --connection-string redis:// %s" % self.TRACE_ID
return cmd if format_ is None else "%s --%s" % (cmd, format_)
@mock.patch("sys.stdout", six.StringIO())
@ -92,38 +63,14 @@ class ShellTestCase(test.TestCase):
"Expected: `osprofiler.exc.CommandError` is raised with "
"message: '%s'." % expected_message)
def test_trace_show_ceilometerclient_is_missed(self):
sys.modules["ceilometerclient"] = None
sys.modules["ceilometerclient.client"] = None
sys.modules["ceilometerclient.shell"] = None
msg = ("To use this command, you should install "
"'ceilometerclient' manually. Use command:\n "
"'pip install python-ceilometerclient'.")
self._test_with_command_error(self._trace_show_cmd(), msg)
def test_trace_show_unauthorized(self):
class FakeHTTPUnauthorized(Exception):
http_status = 401
self.ceiloclient.client.get_client.side_effect = FakeHTTPUnauthorized
msg = "Invalid OpenStack Identity credentials."
self._test_with_command_error(self._trace_show_cmd(), msg)
def test_trace_show_unknown_error(self):
self.ceiloclient.client.get_client.side_effect = Exception("test")
msg = "Error occurred while connecting to Ceilometer: test."
self._test_with_command_error(self._trace_show_cmd(), msg)
@mock.patch("osprofiler.drivers.ceilometer.Ceilometer.get_report")
@mock.patch("osprofiler.drivers.redis_driver.Redis.get_report")
def test_trace_show_no_selected_format(self, mock_get):
mock_get.return_value = self._create_mock_notifications()
msg = ("You should choose one of the following output formats: "
"json, html or dot.")
self._test_with_command_error(self._trace_show_cmd(), msg)
@mock.patch("osprofiler.drivers.ceilometer.Ceilometer.get_report")
@mock.patch("osprofiler.drivers.redis_driver.Redis.get_report")
@ddt.data(None, {"info": {"started": 0, "finished": 1, "name": "total"},
"children": []})
def test_trace_show_trace_id_not_found(self, notifications, mock_get):
@ -153,7 +100,7 @@ class ShellTestCase(test.TestCase):
return notifications
@mock.patch("sys.stdout", six.StringIO())
@mock.patch("osprofiler.drivers.ceilometer.Ceilometer.get_report")
@mock.patch("osprofiler.drivers.redis_driver.Redis.get_report")
def test_trace_show_in_json(self, mock_get):
notifications = self._create_mock_notifications()
mock_get.return_value = notifications
@ -164,7 +111,7 @@ class ShellTestCase(test.TestCase):
sys.stdout.getvalue())
@mock.patch("sys.stdout", six.StringIO())
@mock.patch("osprofiler.drivers.ceilometer.Ceilometer.get_report")
@mock.patch("osprofiler.drivers.redis_driver.Redis.get_report")
def test_trace_show_in_html(self, mock_get):
notifications = self._create_mock_notifications()
mock_get.return_value = notifications
@ -193,7 +140,7 @@ class ShellTestCase(test.TestCase):
sys.stdout.getvalue())
@mock.patch("sys.stdout", six.StringIO())
@mock.patch("osprofiler.drivers.ceilometer.Ceilometer.get_report")
@mock.patch("osprofiler.drivers.redis_driver.Redis.get_report")
def test_trace_show_write_to_file(self, mock_get):
notifications = self._create_mock_notifications()
mock_get.return_value = notifications

View File

@ -1,423 +0,0 @@
# Copyright 2016 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# 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 mock
from osprofiler.drivers.ceilometer import Ceilometer
from osprofiler.tests import test
class CeilometerParserTestCase(test.TestCase):
def setUp(self):
super(CeilometerParserTestCase, self).setUp()
self.ceilometer = Ceilometer("ceilometer://",
ceilometer_api_version="2")
def test_build_empty_tree(self):
self.assertEqual([], self.ceilometer._build_tree({}))
def test_build_complex_tree(self):
test_input = {
"2": {"parent_id": "0", "trace_id": "2", "info": {"started": 1}},
"1": {"parent_id": "0", "trace_id": "1", "info": {"started": 0}},
"21": {"parent_id": "2", "trace_id": "21", "info": {"started": 6}},
"22": {"parent_id": "2", "trace_id": "22", "info": {"started": 7}},
"11": {"parent_id": "1", "trace_id": "11", "info": {"started": 1}},
"113": {"parent_id": "11", "trace_id": "113",
"info": {"started": 3}},
"112": {"parent_id": "11", "trace_id": "112",
"info": {"started": 2}},
"114": {"parent_id": "11", "trace_id": "114",
"info": {"started": 5}}
}
expected_output = [
{
"parent_id": "0",
"trace_id": "1",
"info": {"started": 0},
"children": [
{
"parent_id": "1",
"trace_id": "11",
"info": {"started": 1},
"children": [
{"parent_id": "11", "trace_id": "112",
"info": {"started": 2}, "children": []},
{"parent_id": "11", "trace_id": "113",
"info": {"started": 3}, "children": []},
{"parent_id": "11", "trace_id": "114",
"info": {"started": 5}, "children": []}
]
}
]
},
{
"parent_id": "0",
"trace_id": "2",
"info": {"started": 1},
"children": [
{"parent_id": "2", "trace_id": "21",
"info": {"started": 6}, "children": []},
{"parent_id": "2", "trace_id": "22",
"info": {"started": 7}, "children": []}
]
}
]
result = self.ceilometer._build_tree(test_input)
self.assertEqual(expected_output, result)
def test_get_report_empty(self):
self.ceilometer.client = mock.MagicMock()
self.ceilometer.client.events.list.return_value = []
expected = {
"info": {
"name": "total",
"started": 0,
"finished": None,
"last_trace_started": None
},
"children": [],
"stats": {},
}
base_id = "10"
self.assertEqual(expected, self.ceilometer.get_report(base_id))
def test_get_report(self):
self.ceilometer.client = mock.MagicMock()
results = [mock.MagicMock(), mock.MagicMock(), mock.MagicMock(),
mock.MagicMock(), mock.MagicMock()]
self.ceilometer.client.events.list.return_value = results
results[0].to_dict.return_value = {
"traits": [
{
"type": "string",
"name": "base_id",
"value": "7253ca8c-33b3-4f84-b4f1-f5a4311ddfa4"
},
{
"type": "string",
"name": "host",
"value": "ubuntu"
},
{
"type": "string",
"name": "method",
"value": "POST"
},
{
"type": "string",
"name": "name",
"value": "wsgi-start"
},
{
"type": "string",
"name": "parent_id",
"value": "7253ca8c-33b3-4f84-b4f1-f5a4311ddfa4"
},
{
"type": "string",
"name": "project",
"value": "keystone"
},
{
"type": "string",
"name": "service",
"value": "main"
},
{
"type": "string",
"name": "timestamp",
"value": "2015-12-23T14:02:22.338776"
},
{
"type": "string",
"name": "trace_id",
"value": "06320327-2c2c-45ae-923a-515de890276a"
}
],
"raw": {},
"generated": "2015-12-23T10:41:38.415793",
"event_type": "profiler.main",
"message_id": "65fc1553-3082-4a6f-9d1e-0e3183f57a47"}
results[1].to_dict.return_value = {
"traits":
[
{
"type": "string",
"name": "base_id",
"value": "7253ca8c-33b3-4f84-b4f1-f5a4311ddfa4"
},
{
"type": "string",
"name": "host",
"value": "ubuntu"
},
{
"type": "string",
"name": "name",
"value": "wsgi-stop"
},
{
"type": "string",
"name": "parent_id",
"value": "7253ca8c-33b3-4f84-b4f1-f5a4311ddfa4"
},
{
"type": "string",
"name": "project",
"value": "keystone"
},
{
"type": "string",
"name": "service",
"value": "main"
},
{
"type": "string",
"name": "timestamp",
"value": "2015-12-23T14:02:22.380405"
},
{
"type": "string",
"name": "trace_id",
"value": "016c97fd-87f3-40b2-9b55-e431156b694b"
}
],
"raw": {},
"generated": "2015-12-23T10:41:38.406052",
"event_type": "profiler.main",
"message_id": "3256d9f1-48ba-4ac5-a50b-64fa42c6e264"}
results[2].to_dict.return_value = {
"traits":
[
{
"type": "string",
"name": "base_id",
"value": "7253ca8c-33b3-4f84-b4f1-f5a4311ddfa4"
},
{
"type": "string",
"name": "db.params",
"value": "[]"
},
{
"type": "string",
"name": "db.statement",
"value": "SELECT 1"
},
{
"type": "string",
"name": "host",
"value": "ubuntu"
},
{
"type": "string",
"name": "name",
"value": "db-start"
},
{
"type": "string",
"name": "parent_id",
"value": "06320327-2c2c-45ae-923a-515de890276a"
},
{
"type": "string",
"name": "project",
"value": "keystone"
},
{
"type": "string",
"name": "service",
"value": "main"
},
{
"type": "string",
"name": "timestamp",
"value": "2015-12-23T14:02:22.395365"
},
{
"type": "string",
"name": "trace_id",
"value": "1baf1d24-9ca9-4f4c-bd3f-01b7e0c0735a"
}
],
"raw": {},
"generated": "2015-12-23T10:41:38.984161",
"event_type": "profiler.main",
"message_id": "60368aa4-16f0-4f37-a8fb-89e92fdf36ff"}
results[3].to_dict.return_value = {
"traits":
[
{
"type": "string",
"name": "base_id",
"value": "7253ca8c-33b3-4f84-b4f1-f5a4311ddfa4"
},
{
"type": "string",
"name": "host",
"value": "ubuntu"
},
{
"type": "string",
"name": "name",
"value": "db-stop"
},
{
"type": "string",
"name": "parent_id",
"value": "06320327-2c2c-45ae-923a-515de890276a"
},
{
"type": "string",
"name": "project",
"value": "keystone"
},
{
"type": "string",
"name": "service",
"value": "main"
},
{
"type": "string",
"name": "timestamp",
"value": "2015-12-23T14:02:22.415486"
},
{
"type": "string",
"name": "trace_id",
"value": "1baf1d24-9ca9-4f4c-bd3f-01b7e0c0735a"
}
],
"raw": {},
"generated": "2015-12-23T10:41:39.019378",
"event_type": "profiler.main",
"message_id": "3fbeb339-55c5-4f28-88e4-15bee251dd3d"}
results[4].to_dict.return_value = {
"traits":
[
{
"type": "string",
"name": "base_id",
"value": "7253ca8c-33b3-4f84-b4f1-f5a4311ddfa4"
},
{
"type": "string",
"name": "host",
"value": "ubuntu"
},
{
"type": "string",
"name": "method",
"value": "GET"
},
{
"type": "string",
"name": "name",
"value": "wsgi-start"
},
{
"type": "string",
"name": "parent_id",
"value": "7253ca8c-33b3-4f84-b4f1-f5a4311ddfa4"
},
{
"type": "string",
"name": "project",
"value": "keystone"
},
{
"type": "string",
"name": "service",
"value": "main"
},
{
"type": "string",
"name": "timestamp",
"value": "2015-12-23T14:02:22.427444"
},
{
"type": "string",
"name": "trace_id",
"value": "016c97fd-87f3-40b2-9b55-e431156b694b"
}
],
"raw": {},
"generated": "2015-12-23T10:41:38.360409",
"event_type": "profiler.main",
"message_id": "57b971a9-572f-4f29-9838-3ed2564c6b5b"}
expected = {"children": [
{"children": [{"children": [],
"info": {"finished": 76,
"host": "ubuntu",
"meta.raw_payload.db-start": {},
"meta.raw_payload.db-stop": {},
"name": "db",
"project": "keystone",
"service": "main",
"started": 56,
"exception": "None"},
"parent_id": "06320327-2c2c-45ae-923a-515de890276a",
"trace_id": "1baf1d24-9ca9-4f4c-bd3f-01b7e0c0735a"}
],
"info": {"finished": 0,
"host": "ubuntu",
"meta.raw_payload.wsgi-start": {},
"name": "wsgi",
"project": "keystone",
"service": "main",
"started": 0},
"parent_id": "7253ca8c-33b3-4f84-b4f1-f5a4311ddfa4",
"trace_id": "06320327-2c2c-45ae-923a-515de890276a"},
{"children": [],
"info": {"finished": 41,
"host": "ubuntu",
"meta.raw_payload.wsgi-start": {},
"meta.raw_payload.wsgi-stop": {},
"name": "wsgi",
"project": "keystone",
"service": "main",
"started": 88,
"exception": "None"},
"parent_id": "7253ca8c-33b3-4f84-b4f1-f5a4311ddfa4",
"trace_id": "016c97fd-87f3-40b2-9b55-e431156b694b"}],
"info": {
"finished": 88,
"name": "total",
"started": 0,
"last_trace_started": 88
},
"stats": {"db": {"count": 1, "duration": 20},
"wsgi": {"count": 2, "duration": -47}},
}
base_id = "10"
result = self.ceilometer.get_report(base_id)
expected_filter = [{"field": "base_id", "op": "eq", "value": base_id}]
self.ceilometer.client.events.list.assert_called_once_with(
expected_filter, limit=100000)
self.assertEqual(expected, result)

View File

@ -12,7 +12,6 @@ sphinx>=1.6.2 # BSD
# Bandit security code scanner
bandit>=1.1.0 # Apache-2.0
python-ceilometerclient>=2.5.0 # Apache-2.0
pymongo>=3.0.2,!=3.1 # Apache-2.0
# Elasticsearch python client