From: beierlm Date: Fri, 17 Apr 2020 17:08:11 +0000 (-0400) Subject: Fix MON Stein Metrics X-Git-Tag: release-v8.0-start~4 X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FMON.git;a=commitdiff_plain;h=8a77165ce022c148d39cfa45a5090cb19bcb3833 Fix MON Stein Metrics Gnocchi deprecated the use of the cpu_util parameter after Rocky. What is needed instead is to use the ceilometer-low-rate cpu metric and covert that to a percentage using value/time interval. This metric was introduced in Mitaka, and has been shown to work with Rocky as part of the Whitestack WhiteCloud Rocky deployment, as well as Stein with Canonical Charmed OpenStack Stein deployment. Bug 790 Change-Id: I1a895e3569f9206c39ce3c77636d1b45a1a1bd3a Signed-off-by: beierlm --- diff --git a/osm_mon/collector/vnf_collectors/openstack.py b/osm_mon/collector/vnf_collectors/openstack.py index 60b387c..1bb0fc8 100644 --- a/osm_mon/collector/vnf_collectors/openstack.py +++ b/osm_mon/collector/vnf_collectors/openstack.py @@ -19,16 +19,17 @@ # For those usages not covered by the Apache License, Version 2.0 please # contact: bdiaz@whitestack.com or glavado@whitestack.com ## -import logging from enum import Enum +import logging +import time from typing import List -import gnocchiclient.exceptions from ceilometerclient import client as ceilometer_client from ceilometerclient.exc import HTTPException +import gnocchiclient.exceptions from gnocchiclient.v1 import client as gnocchi_client -from keystoneclient.v3 import client as keystone_client from keystoneauth1.exceptions.catalog import EndpointNotFound +from keystoneclient.v3 import client as keystone_client from neutronclient.v2_0 import client as neutron_client from osm_mon.collector.metric import Metric @@ -38,6 +39,7 @@ from osm_mon.collector.vnf_metric import VnfMetric from osm_mon.core.common_db import CommonDbClient from osm_mon.core.config import Config + log = logging.getLogger(__name__) METRIC_MAPPINGS = { @@ -50,7 +52,15 @@ METRIC_MAPPINGS = { "packets_out_dropped": "network.incoming.packets.drop", "packets_received": "network.incoming.packets.rate", "packets_sent": "network.outgoing.packets.rate", - "cpu_utilization": "cpu_util", + "cpu_utilization": "cpu", +} + +METRIC_MULTIPLIERS = { + "cpu": 0.0000001 +} + +METRIC_AGGREGATORS = { + "cpu": "rate:mean" } INTERFACE_METRICS = ['packets_in_dropped', 'packets_out_dropped', 'packets_received', 'packets_sent'] @@ -212,11 +222,22 @@ class GnocchiBackend(OpenstackBackend): def _collect_instance_metric(self, openstack_metric_name, resource_id): value = None try: + aggregation = METRIC_AGGREGATORS.get(openstack_metric_name) + measures = self.client.metric.get_measures(openstack_metric_name, - resource_id=resource_id, - limit=1) + aggregation=aggregation, + start=time.time() - 1200, + resource_id=resource_id) + # measures[-1][0] is the time of the reporting interval + # measures[-1][1] is the durcation of the reporting interval + # measures[-1][2] is the value of the metric if measures: value = measures[-1][2] + if aggregation: + # If this is an aggregate, we need to divide the total over the reported time period. + value = value / measures[-1][1] + if openstack_metric_name in METRIC_MULTIPLIERS: + value = value * METRIC_MULTIPLIERS[openstack_metric_name] except gnocchiclient.exceptions.NotFound as e: log.debug("No metric %s found for instance %s: %s", openstack_metric_name, resource_id, e) diff --git a/osm_mon/tests/unit/collector/vnf_collectors/test_openstack.py b/osm_mon/tests/unit/collector/vnf_collectors/test_openstack.py index 5493ae7..1f2d06a 100644 --- a/osm_mon/tests/unit/collector/vnf_collectors/test_openstack.py +++ b/osm_mon/tests/unit/collector/vnf_collectors/test_openstack.py @@ -23,6 +23,8 @@ import datetime from unittest import TestCase, mock +import gnocchiclient + from osm_mon.collector.vnf_collectors.openstack import GnocchiBackend from osm_mon.core.config import Config @@ -37,7 +39,7 @@ class CollectorTest(TestCase): @mock.patch.object(GnocchiBackend, '_build_neutron_client') @mock.patch.object(GnocchiBackend, '_build_gnocchi_client') - def test_collect_gnocchi_instance(self, build_gnocchi_client, build_neutron_client): + def test_collect_gnocchi_rate_instance(self, build_gnocchi_client, _): mock_gnocchi_client = mock.Mock() mock_gnocchi_client.metric.get_measures.return_value = [(datetime.datetime(2019, 4, 12, 15, 43, tzinfo=datetime.timezone( @@ -46,14 +48,52 @@ class CollectorTest(TestCase): (datetime.datetime(2019, 4, 12, 15, 44, tzinfo=datetime.timezone( datetime.timedelta(0), - '+00:00')), 60.0, 0.0333070363)] + '+00:00')), 60.0, 600000000)] build_gnocchi_client.return_value = mock_gnocchi_client backend = GnocchiBackend({'_id': 'test_uuid'}) - value = backend._collect_instance_metric('cpu_utilization', 'test_resource_id') - self.assertEqual(value, 0.0333070363) - mock_gnocchi_client.metric.get_measures.assert_called_once_with('cpu_utilization', - limit=1, + value = backend._collect_instance_metric('cpu', 'test_resource_id') + self.assertEqual(value, 1.0) + mock_gnocchi_client.metric.get_measures.assert_called_once_with('cpu', + aggregation="rate:mean", + start=mock.ANY, + resource_id='test_resource_id') + + @mock.patch.object(GnocchiBackend, '_build_neutron_client') + @mock.patch.object(GnocchiBackend, '_build_gnocchi_client') + def test_collect_gnocchi_non_rate_instance(self, build_gnocchi_client, _): + mock_gnocchi_client = mock.Mock() + mock_gnocchi_client.metric.get_measures.return_value = [(datetime.datetime(2019, 4, 12, 15, 43, + tzinfo=datetime.timezone( + datetime.timedelta(0), + '+00:00')), 60.0, 0.0345442539), + (datetime.datetime(2019, 4, 12, 15, 44, + tzinfo=datetime.timezone( + datetime.timedelta(0), + '+00:00')), 60.0, 128)] + build_gnocchi_client.return_value = mock_gnocchi_client + + backend = GnocchiBackend({'_id': 'test_uuid'}) + value = backend._collect_instance_metric('memory.usage', 'test_resource_id') + self.assertEqual(value, 128) + mock_gnocchi_client.metric.get_measures.assert_called_once_with('memory.usage', + aggregation=None, + start=mock.ANY, + resource_id='test_resource_id') + + @mock.patch.object(GnocchiBackend, '_build_neutron_client') + @mock.patch.object(GnocchiBackend, '_build_gnocchi_client') + def test_collect_gnocchi_no_metric(self, build_gnocchi_client, _): + mock_gnocchi_client = mock.Mock() + mock_gnocchi_client.metric.get_measures.side_effect = gnocchiclient.exceptions.NotFound() + build_gnocchi_client.return_value = mock_gnocchi_client + + backend = GnocchiBackend({'_id': 'test_uuid'}) + value = backend._collect_instance_metric('memory.usage', 'test_resource_id') + self.assertIsNone(value) + mock_gnocchi_client.metric.get_measures.assert_called_once_with('memory.usage', + aggregation=None, + start=mock.ANY, resource_id='test_resource_id') @mock.patch.object(GnocchiBackend, '_build_neutron_client')