diff --git a/watcher_dashboard/utils/metering.py b/watcher_dashboard/utils/metering.py deleted file mode 100644 index 49476fa..0000000 --- a/watcher_dashboard/utils/metering.py +++ /dev/null @@ -1,297 +0,0 @@ -# -*- coding: utf8 -*- -# -# 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 unicode_literals - -import copy - -from django.utils.http import urlencode -from django.utils.translation import ugettext_lazy as _ -from horizon import exceptions -from openstack_dashboard.api import ceilometer -from openstack_dashboard.utils import metering - -SETTINGS = { - 'settings': { - 'renderer': 'StaticAxes', - 'xMin': None, - 'xMax': None, - 'higlight_last_point': True, - 'auto_size': False, - 'auto_resize': False, - 'axes_x': False, - 'axes_y': True, - 'axes_y_label': False, - 'bar_chart_settings': { - 'orientation': 'vertical', - 'used_label_placement': 'left', - 'width': 30, - 'color_scale_domain': [0, 80, 80, 100], - 'color_scale_range': [ - '#0000FF', - '#0000FF', - '#FF0000', - '#FF0000' - ], - 'average_color_scale_domain': [0, 100], - 'average_color_scale_range': ['#0000FF', '#0000FF'] - } - }, - 'stats': { - 'average': None, - 'used': None, - 'tooltip_average': None, - } -} - -LABELS = { - 'hardware.cpu.load.1min': _("CPU load 1 min average"), - 'hardware.system_stats.cpu.util': _("CPU utilization"), - 'hardware.system_stats.io.outgoing.blocks': _("IO raw sent"), - 'hardware.system_stats.io.incoming.blocks': _("IO raw received"), - 'hardware.network.ip.outgoing.datagrams': _("IP out requests"), - 'hardware.network.ip.incoming.datagrams': _("IP in requests"), - 'hardware.memory.swap.util': _("Swap utilization"), - 'hardware.ipmi.fan': _("Fan Speed"), - 'hardware.ipmi.voltage': _("Votage"), - 'hardware.ipmi.temperature': _("Temperature"), - 'hardware.ipmi.current': _("Current") -} - - -# TODO(lsmola) this should probably live in Horizon common -def query_data(request, - date_from, - date_to, - group_by, - meter, - period=None, - query=None, - additional_query=None): - - if not period: - period = metering.calc_period(date_from, date_to, 50) - if additional_query is None: - additional_query = [] - if date_from: - additional_query += [{'field': 'timestamp', - 'op': 'ge', - 'value': date_from}] - if date_to: - additional_query += [{'field': 'timestamp', - 'op': 'le', - 'value': date_to}] - - # TODO(lsmola) replace this by logic implemented in I1 in bugs - # 1226479 and 1226482, this is just a quick fix for RC1 - ceilometer_usage = ceilometer.CeilometerUsage(request) - try: - if group_by: - resources = ceilometer_usage.resource_aggregates_with_statistics( - query, [meter], period=period, stats_attr=None, - additional_query=additional_query) - else: - resources = ceilometer_usage.resources_with_statistics( - query, [meter], period=period, stats_attr=None, - additional_query=additional_query) - except Exception: - resources = [] - exceptions.handle(request, - _('Unable to retrieve statistics.')) - return resources - - -def url_part(meter_name, barchart): - d = {'meter': meter_name} - if barchart: - d['barchart'] = True - return urlencode(d) - - -def get_meter_name(meter): - return meter.replace('.', '_') - - -def get_meter_list_and_unit(request, meter): - try: - meter_list = [m for m in ceilometer.meter_list(request) - if m.name == meter] - unit = meter_list[0].unit - except Exception: - meter_list = [] - unit = '' - - return meter_list, unit - - -def get_meters(meters): - return [(m, get_meter_name(m)) for m in meters] - - -def get_barchart_stats(series, unit): - values = [point['y'] for point in series[0]['data']] - average = sum(values) / float(len(values)) # Python 2/3 compatibility - used = values[-1] - first_date = series[0]['data'][0]['x'] - last_date = series[0]['data'][-1]['x'] - tooltip_average = _('Average %(average)s %(unit)s
From: ' - '%(first_date)s, to: %(last_date)s') % ( - dict(average=average, unit=unit, - first_date=first_date, - last_date=last_date)) - return average, used, tooltip_average - - -def create_json_output(series, barchart, unit, date_from, date_to): - start_datetime = end_datetime = '' - if date_from: - start_datetime = date_from.strftime("%Y-%m-%dT%H:%M:%S") - if date_to: - end_datetime = date_to.strftime("%Y-%m-%dT%H:%M:%S") - - settings = copy.deepcopy(SETTINGS) - settings['settings']['xMin'] = start_datetime - settings['settings']['xMax'] = end_datetime - - if series and barchart: - average, used, tooltip_average = get_barchart_stats(series, unit) - settings['settings']['yMin'] = 0 - settings['settings']['yMax'] = 100 - settings['stats']['average'] = average - settings['stats']['used'] = used - settings['stats']['tooltip_average'] = tooltip_average - else: - del settings['settings']['bar_chart_settings'] - del settings['stats'] - - json_output = {'series': series} - json_output.update(settings) - return json_output - - -def get_nodes_stats(request, node_uuid, instance_uuid, meter, - date_options=None, date_from=None, date_to=None, - stats_attr=None, barchart=None, group_by=None): - series = [] - meter_list, unit = get_meter_list_and_unit(request, meter) - - if instance_uuid: - if 'ipmi' in meter: - # For IPMI metrics, a resource ID is made of node UUID concatenated - # with the metric description. E.g: - # 1dcf1896-f581-4027-9efa-973eef3380d2-fan_2a_tach_(0x42) - resource_ids = [m.resource_id for m in meter_list - if m.resource_id.startswith(node_uuid)] - queries = [ - [{'field': 'resource_id', - 'op': 'eq', - 'value': resource_id}] - for resource_id in resource_ids - ] - else: - # For SNMP metrics, a resource ID matches exactly the UUID of the - # associated instance - if group_by == "image_id": - query = {} - image_query = [{"field": "metadata.%s" % group_by, - "op": "eq", - "value": instance_uuid}] - query[instance_uuid] = image_query - else: - query = [{'field': 'resource_id', - 'op': 'eq', - 'value': instance_uuid}] - queries = [query] - else: - # query will be aggregated across all resources - group_by = "all" - query = {'all': []} - queries = [query] - - # Disk and Network I/O: data from 2 meters in one chart - if meter == 'disk-io': - meters = get_meters([ - 'hardware.system_stats.io.outgoing.blocks', - 'hardware.system_stats.io.incoming.blocks' - ]) - elif meter == 'network-io': - meters = get_meters([ - 'hardware.network.ip.outgoing.datagrams', - 'hardware.network.ip.incoming.datagrams' - ]) - else: - meters = get_meters([meter]) - - date_from, date_to = metering.calc_date_args( - date_from, - date_to, - date_options) - - for meter_id, meter_name in meters: - label = str(LABELS.get(meter_id, meter_name)) - - for query in queries: - resources = query_data( - request=request, - date_from=date_from, - date_to=date_to, - group_by=group_by, - meter=meter_id, - query=query) - s = metering.series_for_meter(request, resources, group_by, - meter_id, meter_name, stats_attr, - unit, label) - series += s - - series = metering.normalize_series_by_unit(series) - - json_output = create_json_output( - series, - barchart, - unit, - date_from, - date_to) - - return json_output - - -def get_top_5(request, meter): - ceilometer_usage = ceilometer.CeilometerUsage(request) - meter_list, unit = get_meter_list_and_unit(request, meter) - top_5 = {'unit': unit, 'label': LABELS.get(meter, meter)} - data = [] - - for m in meter_list: - query = [{'field': 'resource_id', 'op': 'eq', 'value': m.resource_id}] - resource = ceilometer_usage.resources_with_statistics(query, [m.name], - period=600)[0] - node_uuid = resource.metadata['node'] - old_value, value = resource.get_meter(get_meter_name(m.name))[-2:] - old_value, value = old_value.max, value.max - - if value > old_value: - direction = 'up' - elif value < old_value: - direction = 'down' - else: - direction = None - - data.append({ - 'node_uuid': node_uuid, - 'value': value, - 'direction': direction - }) - - top_5['data'] = sorted(data, key=lambda d: d['value'], reverse=True)[:5] - return top_5 diff --git a/watcher_dashboard/utils/tests.py b/watcher_dashboard/utils/tests.py index eca41f3..d821431 100644 --- a/watcher_dashboard/utils/tests.py +++ b/watcher_dashboard/utils/tests.py @@ -13,13 +13,8 @@ # under the License. import collections -import datetime - -import mock from watcher_dashboard.test import helpers - -from watcher_dashboard.utils import metering from watcher_dashboard.utils import utils @@ -77,132 +72,3 @@ class UtilsTests(helpers.TestCase): self.assertEqual(ret, 0) ret = utils.safe_int_cast(object()) self.assertEqual(ret, 0) - - -class MeteringTests(helpers.TestCase): - def test_query_data(self): - Meter = collections.namedtuple('Meter', 'name unit') - request = 'request' - from_date = datetime.datetime(2015, 1, 1, 13, 45) - to_date = datetime.datetime(2015, 1, 2, 13, 45) - with mock.patch( - 'openstack_dashboard.api.ceilometer.meter_list', - return_value=[Meter('foo.bar', u'µD')], - ), mock.patch( - 'openstack_dashboard.api.ceilometer.CeilometerUsage', - return_value=mock.MagicMock(**{ - 'resource_aggregates_with_statistics.return_value': 'plonk', - }), - ): - ret = metering.query_data(request, from_date, to_date, - 'all', 'foo.bar') - self.assertEqual(ret, 'plonk') - - def test_url_part(self): - ret = metering.url_part('foo_bar_baz', True) - self.assertTrue('meter=foo_bar_baz' in ret) - self.assertTrue('barchart=True' in ret) - ret = metering.url_part('foo_bar_baz', False) - self.assertTrue('meter=foo_bar_baz' in ret) - self.assertFalse('barchart=True' in ret) - - def test_get_meter_name(self): - ret = metering.get_meter_name('foo.bar.baz') - self.assertEqual(ret, 'foo_bar_baz') - - def test_get_meters(self): - ret = metering.get_meters(['foo.bar', 'foo.baz']) - self.assertEqual(ret, [('foo.bar', 'foo_bar'), ('foo.baz', 'foo_baz')]) - - def test_get_barchart_stats(self): - series = [ - {'data': [{'x': 1, 'y': 1}, {'x': 4, 'y': 4}]}, - {'data': [{'x': 2, 'y': 2}, {'x': 5, 'y': 5}]}, - {'data': [{'x': 3, 'y': 3}, {'x': 6, 'y': 6}]}, - ] - # Arrogance is measured in IT in micro-Dijkstras, µD. - average, used, tooltip_average = metering.get_barchart_stats(series, - u'µD') - self.assertEqual(average, 2.5) - self.assertEqual(used, 4) - self.assertEqual(tooltip_average, u'Average 2.5 µD
From: 1, to: 4') - - def test_create_json_output(self): - ret = metering.create_json_output([], False, u'µD', None, None) - self.assertEqual(ret, { - 'series': [], - 'settings': { - 'higlight_last_point': True, - 'axes_x': False, - 'axes_y': True, - 'xMin': '', - 'renderer': 'StaticAxes', - 'xMax': '', - 'axes_y_label': False, - 'auto_size': False, - 'auto_resize': False, - }, - }) - - series = [ - {'data': [{'x': 1, 'y': 1}, {'x': 4, 'y': 4}]}, - {'data': [{'x': 2, 'y': 2}, {'x': 5, 'y': 5}]}, - {'data': [{'x': 3, 'y': 3}, {'x': 6, 'y': 6}]}, - ] - ret = metering.create_json_output(series, True, u'µD', None, None) - self.assertEqual(ret, { - 'series': series, - 'stats': { - 'average': 2.5, - 'used': 4, - 'tooltip_average': u'Average 2.5 µD
From: 1, to: 4', - }, - 'settings': { - 'yMin': 0, - 'yMax': 100, - 'higlight_last_point': True, - 'axes_x': False, - 'axes_y': True, - 'bar_chart_settings': { - 'color_scale_domain': [0, 80, 80, 100], - 'orientation': 'vertical', - 'color_scale_range': [ - '#0000FF', - '#0000FF', - '#FF0000', - '#FF0000', - ], - 'width': 30, - 'average_color_scale_domain': [0, 100], - 'used_label_placement': 'left', - 'average_color_scale_range': ['#0000FF', '#0000FF'], - }, - 'xMin': '', - 'renderer': 'StaticAxes', - 'xMax': '', - 'axes_y_label': False, - 'auto_size': False, - 'auto_resize': False, - }, - }) - - def test_get_nodes_stats(self): - request = 'request' - with mock.patch( - 'watcher_dashboard.utils.metering.create_json_output', - return_value='', - ) as create_json_output, mock.patch( - 'watcher_dashboard.utils.metering.query_data', - return_value=[], - ), mock.patch( - 'openstack_dashboard.utils.metering.series_for_meter', - return_value=[], - ), mock.patch( - 'openstack_dashboard.utils.metering.calc_date_args', - return_value=('from date', 'to date'), - ): - ret = metering.get_nodes_stats(request, 'abc', 'def', 'foo.bar') - self.assertEqual(ret, '') - self.assertEqual(create_json_output.call_args_list, [ - mock.call([], None, '', 'from date', 'to date') - ])