X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FMON.git;a=blobdiff_plain;f=osm_mon%2Fcollector%2Fvnf_collectors%2Fopenstack.py;h=df0424b48c2bb6c1f7f6de86f785b3b43cfb809f;hp=a13380ad623cd9fa879fc57f8dda0825a9077e62;hb=ef8ee1eca6ac4b9aa4f04e96cf11fdfa56dcdfcf;hpb=94a96efdb03e39d133790197bd7b73747105f9d8 diff --git a/osm_mon/collector/vnf_collectors/openstack.py b/osm_mon/collector/vnf_collectors/openstack.py index a13380a..df0424b 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'] @@ -85,7 +95,10 @@ class OpenstackCollector(BaseVimCollector): # Populate extra tags for metrics tags = {} tags['ns_name'] = self.common_db.get_nsr(nsr_id)['name'] - tags['project_id'] = vnfr['_admin']['projects_read'][0] + if vnfr['_admin']['projects_read']: + tags['project_id'] = vnfr['_admin']['projects_read'][0] + else: + tags['project_id'] = '' metrics = [] for vdur in vnfr['vdur']: @@ -110,25 +123,33 @@ class OpenstackCollector(BaseVimCollector): vdur['name'], vnf_member_index, nsr_id) continue try: + log.info("Collecting metric type: %s and metric_name: %s and resource_id %s and " + "interface_name: %s", metric_type, metric_name, resource_id, interface_name) value = self.backend.collect_metric(metric_type, openstack_metric_name, resource_id, interface_name) if value is not None: + log.info("value: %s", value) if interface_name: tags['interface'] = interface_name metric = VnfMetric(nsr_id, vnf_member_index, vdur['name'], metric_name, value, tags) metrics.append(metric) - except Exception: + else: + log.info("metric value is empty") + except Exception as e: log.exception("Error collecting metric %s for vdu %s" % (metric_name, vdur['name'])) + log.info("Error in metric collection: %s" % e) return metrics def _get_backend(self, vim_account: dict): try: ceilometer = CeilometerBackend(vim_account) ceilometer.client.capabilities.get() + log.info("Using ceilometer backend to collect metric") return ceilometer except (HTTPException, EndpointNotFound): gnocchi = GnocchiBackend(vim_account) gnocchi.client.metric.list(limit=1) + log.info("Using gnocchi backend to collect metric") return gnocchi def _get_metric_type(self, metric_name: str, interface_name: str) -> MetricType: @@ -209,11 +230,41 @@ class GnocchiBackend(OpenstackBackend): def _collect_instance_metric(self, openstack_metric_name, resource_id): value = None try: - measures = self.client.metric.get_measures(openstack_metric_name, - resource_id=resource_id, - limit=1) - if measures: - value = measures[-1][2] + aggregation = METRIC_AGGREGATORS.get(openstack_metric_name) + + try: + measures = self.client.metric.get_measures(openstack_metric_name, + aggregation=aggregation, + start=time.time() - 1200, + resource_id=resource_id) + if measures: + value = measures[-1][2] + except gnocchiclient.exceptions.NotFound as e: + # CPU metric in previous Openstack versions do not support rate:mean aggregation method + if openstack_metric_name == "cpu": + log.debug("No metric %s found for instance %s: %s", openstack_metric_name, resource_id, e) + log.debug("Retrying to get metric %s for instance %s without aggregation", + openstack_metric_name, resource_id) + measures = self.client.metric.get_measures(openstack_metric_name, + resource_id=resource_id, + limit=1) + else: + raise e + # measures[-1] is the last measure + # measures[-2] is the previous measure + # measures[x][2] is the value of the metric + if measures and len(measures) >= 2: + value = measures[-1][2] - measures[-2][2] + if value: + # measures[-1][0] is the time of the reporting interval + # measures[-1][1] is the duration of the reporting interval + if aggregation: + # If this is an aggregate, we need to divide the total over the reported time period. + # Even if the aggregation method is not supported by Openstack, the code will execute it + # because aggregation is specified in METRIC_AGGREGATORS + 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)