Fix MON Stein Metrics 98/8798/1
authorbeierlm <mark.beierl@canonical.com>
Fri, 17 Apr 2020 17:08:11 +0000 (13:08 -0400)
committerbeierlm <mark.beierl@canonical.com>
Fri, 17 Apr 2020 17:08:39 +0000 (13:08 -0400)
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 <mark.beierl@canonical.com>
osm_mon/collector/vnf_collectors/openstack.py
osm_mon/tests/unit/collector/vnf_collectors/test_openstack.py

index 60b387c..1bb0fc8 100644 (file)
 # 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)
index 5493ae7..1f2d06a 100644 (file)
@@ -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')