1 # -*- coding: utf-8 -*-
3 # Copyright 2018 Whitestack, LLC
4 # *************************************************************
6 # This file is part of OSM Monitoring module
7 # All Rights Reserved to Whitestack, LLC
9 # Licensed under the Apache License, Version 2.0 (the "License"); you may
10 # not use this file except in compliance with the License. You may obtain
11 # a copy of the License at
13 # http://www.apache.org/licenses/LICENSE-2.0
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18 # License for the specific language governing permissions and limitations
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact: bdiaz@whitestack.com or glavado@whitestack.com
28 from n2vc
.vnf
import N2VC
29 from prometheus_client
.core
import GaugeMetricFamily
31 from osm_mon
.common
.common_db_client
import CommonDbClient
32 from osm_mon
.core
.message_bus
.consumer
import Consumer
33 from osm_mon
.core
.message_bus
.producer
import Producer
34 from osm_mon
.core
.settings
import Config
36 log
= logging
.getLogger(__name__
)
41 cfg
= Config
.instance()
42 self
.kafka_server
= cfg
.BROKER_URI
43 self
.common_db_client
= CommonDbClient()
44 self
.n2vc
= N2VC(server
=cfg
.OSMMON_VCA_HOST
, user
=cfg
.OSMMON_VCA_USER
, secret
=cfg
.OSMMON_VCA_SECRET
)
45 self
.producer_timeout
= 5
47 async def collect_metrics(self
):
49 Collects vdu metrics. These can be vim and/or n2vc metrics.
50 It checks for monitoring-params or metrics inside vdu section of vnfd, then collects the metric accordingly.
51 If vim related, it sends a metric read request through Kafka, to be handled by mon-proxy.
52 If n2vc related, it uses the n2vc client to obtain the readings.
53 :return: lists of metrics
55 # TODO(diazb): Remove dependencies on prometheus_client
56 log
.debug("collect_metrics")
58 consumer
= Consumer('mon-collector-' + str(uuid
.uuid4()),
59 consumer_timeout_ms
=10000,
60 enable_auto_commit
=False)
61 consumer
.subscribe(['metric_response'])
63 vnfrs
= self
.common_db_client
.get_vnfrs()
64 vca_model_name
= 'default'
66 nsr_id
= vnfr
['nsr-id-ref']
67 nsr
= self
.common_db_client
.get_nsr(nsr_id
)
68 vnfd
= self
.common_db_client
.get_vnfd(vnfr
['vnfd-id'])
69 for vdur
in vnfr
['vdur']:
70 # This avoids errors when vdur records have not been completely filled
71 if 'name' not in vdur
:
74 filter(lambda vdu
: vdu
['id'] == vdur
['vdu-id-ref'], vnfd
['vdu'])
76 vnf_member_index
= vnfr
['member-vnf-index-ref']
77 vdu_name
= vdur
['name']
78 if 'monitoring-param' in vdu
:
79 for param
in vdu
['monitoring-param']:
80 metric_name
= param
['nfvi-metric']
81 payload
= self
._generate
_read
_metric
_payload
(metric_name
,
85 producer
.send(topic
='metric_request', key
='read_metric_data_request',
86 value
=json
.dumps(payload
))
87 producer
.flush(self
.producer_timeout
)
88 for message
in consumer
:
89 if message
.key
== 'read_metric_data_response':
90 content
= json
.loads(message
.value
)
91 if content
['correlation_id'] == payload
['correlation_id']:
92 log
.debug("Found read_metric_data_response with same correlation_id")
93 if len(content
['metrics_data']['metrics_series']):
94 metric_reading
= content
['metrics_data']['metrics_series'][-1]
95 if metric_name
not in metrics
.keys():
96 metrics
[metric_name
] = GaugeMetricFamily(
99 labels
=['ns_id', 'vnf_member_index', 'vdu_name']
101 metrics
[metric_name
].add_metric([nsr_id
, vnf_member_index
, vdu_name
],
104 if 'vdu-configuration' in vdu
and 'metrics' in vdu
['vdu-configuration']:
105 vnf_name_vca
= self
.n2vc
.FormatApplicationName(nsr
['name'], vnf_member_index
, vdur
['vdu-id-ref'])
106 vnf_metrics
= await self
.n2vc
.GetMetrics(vca_model_name
, vnf_name_vca
)
107 log
.debug('VNF Metrics: %s', vnf_metrics
)
108 for vnf_metric_list
in vnf_metrics
.values():
109 for vnf_metric
in vnf_metric_list
:
110 log
.debug("VNF Metric: %s", vnf_metric
)
111 if vnf_metric
['key'] not in metrics
.keys():
112 metrics
[vnf_metric
['key']] = GaugeMetricFamily(
115 labels
=['ns_id', 'vnf_member_index', 'vdu_name']
117 metrics
[vnf_metric
['key']].add_metric([nsr_id
, vnf_member_index
, vdu_name
],
118 float(vnf_metric
['value']))
120 producer
.close(self
.producer_timeout
)
121 log
.debug("metric.values = %s", metrics
.values())
122 return metrics
.values()
125 def _generate_read_metric_payload(metric_name
, nsr_id
, vdu_name
, vnf_member_index
) -> dict:
127 Builds JSON payload for asking for a metric measurement in MON. It follows the model defined in core.models.
128 :param metric_name: OSM metric name (e.g.: cpu_utilization)
129 :param nsr_id: NSR ID
130 :param vdu_name: Vdu name according to the vdur
131 :param vnf_member_index: Index of the VNF in the NS according to the vnfr
132 :return: JSON payload as dict
134 cor_id
= random
.randint(1, 10e7
)
136 'correlation_id': cor_id
,
137 'metric_name': metric_name
,
139 'vnf_member_index': vnf_member_index
,
140 'vdu_name': vdu_name
,
141 'collection_period': 1,
142 'collection_unit': 'DAY',