--- /dev/null
+# -*- coding: utf-8 -*-
+
+##
+# Copyright 2016-2017 VMware Inc.
+# This file is part of ETSI OSM
+# All Rights Reserved.
+#
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact: osslegalrouting@vmware.com
+##
+
+import json
+import logging
+
+from keystoneauth1 import session
+from keystoneauth1.identity import v3
+from novaclient import client as nClient
+import re
+import requests
+import time
+import traceback
+import six
+
+from osm_mon.collector.vnf_collectors.base_vim import BaseVimCollector
+from osm_mon.collector.vnf_metric import VnfMetric
+from osm_mon.core.auth import AuthManager
+from osm_mon.core.common_db import CommonDbClient
+from osm_mon.core.config import Config
+
+log = logging.getLogger(__name__)
+
+PERIOD_MSEC = {'HR': 3600000,
+ 'DAY': 86400000,
+ 'WEEK': 604800000,
+ 'MONTH': 2678400000,
+ 'YEAR': 31536000000}
+
+METRIC_MAPPINGS = {
+ "average_memory_utilization": "mem|usage_average",
+ "cpu_utilization": "cpu|usage_average",
+ "read_latency_0": "virtualDisk:scsi0:0|totalReadLatency_average",
+ "write_latency_0": "virtualDisk:scsi0:0|totalWriteLatency_average",
+ "read_latency_1": "virtualDisk:scsi0:1|totalReadLatency_average",
+ "write_latency_1": "virtualDisk:scsi0:1|totalWriteLatency_average",
+ "packets_dropped_0": "net:4000|dropped",
+ "packets_dropped_1": "net:4001|dropped",
+ "packets_dropped_2": "net:4002|dropped",
+ "packets_received": "net:Aggregate of all instances|packetsRxPerSec",
+ "packets_sent": "net:Aggregate of all instances|packetsTxPerSec",
+}
+
+
+class VIOCollector(BaseVimCollector):
+ def __init__(self, config: Config, vim_account_id: str):
+ super().__init__(config, vim_account_id)
+ self.common_db = CommonDbClient()
+ self.auth_manager = AuthManager()
+ vim_account_info = self.auth_manager.get_credentials(vim_account_id)
+ cfg = json.loads(vim_account_info.config)
+ self.vrops_site = cfg['vrops_site']
+ self.vrops_user = cfg['vrops_user']
+ self.vrops_password = cfg['vrops_password']
+ self.client = self.connect_client(vim_account_id)
+
+ def connect_client(self, vim_account_id: str):
+ vim_account_details = self.auth_manager.get_credentials(vim_account_id)
+ verify_ssl = self.auth_manager.is_verify_ssl(vim_account_id)
+ auth = v3.Password(auth_url=vim_account_details.url,
+ username=vim_account_details.user,
+ password=vim_account_details.password,
+ project_name=vim_account_details.tenant_name,
+ project_domain_id='default',
+ user_domain_id='default')
+ sess = session.Session(auth=auth, verify=verify_ssl)
+ client = nClient.Client('2.1', session=sess, endpoint_type=None)
+ return client
+
+ def _get_resource_uuid(self, nsr_id, vnf_member_index, vdur_name) -> str:
+ vdur = self.common_db.get_vdur(nsr_id, vnf_member_index, vdur_name)
+ return vdur['vim-id']
+
+ def get_vm_name_and_id(self, resource_uuid):
+ """ Method to find vm name and id using resource_uuid
+ """
+ server = self.client.servers.find(id=resource_uuid)
+ name = server.to_dict()['name']
+ _id = server.to_dict()['id']
+ return name, _id
+
+ def get_vm_resource_id(self, name, _id):
+ """ Find resource ID in vROPs
+ """
+ api_url = '/suite-api/api/resources?resourceKind=VirtualMachine'
+ headers = {'Accept': 'application/json'}
+
+ resp = requests.get(self.vrops_site + api_url,
+ auth=(self.vrops_user, self.vrops_password),
+ verify=False, headers=headers)
+
+ if resp.status_code != 200:
+ log.error("Failed to get resource details for{} {} {}".format(name,
+ resp.status_code,
+ resp.content))
+ return None
+
+ vm_resource_id = None
+ try:
+ resp_data = json.loads(resp.content.decode('utf-8'))
+ if resp_data.get('resourceList') is not None:
+ resource_list = resp_data.get('resourceList')
+ for resource in resource_list:
+ if resource.get('resourceKey') is not None:
+ m = re.match(r"(.*?)\s\((.*?)\)", resource['resourceKey']['name'])
+ if m:
+ v_name = m.group(1)
+ v_id = m.group(2)
+ if name == v_name and _id == v_id:
+ vm_resource_id = resource['identifier']
+ log.info("Found VM resource ID: {} for vm: {}".format(vm_resource_id,
+ v_name))
+
+ except Exception as exp:
+ log.info("get_vm_resource_id: Error in parsing {}\n{}".format(exp, traceback.format_exc()))
+
+ return vm_resource_id
+
+ def collect(self, vnfr: dict):
+ nsr_id = vnfr['nsr-id-ref']
+ vnf_member_index = vnfr['member-vnf-index-ref']
+ vnfd = self.common_db.get_vnfd(vnfr['vnfd-id'])
+ metrics = []
+ for vdur in vnfr['vdur']:
+ # This avoids errors when vdur records have not been completely filled
+ if 'name' not in vdur:
+ continue
+ vdu = next(
+ filter(lambda vdu: vdu['id'] == vdur['vdu-id-ref'], vnfd['vdu'])
+
+ )
+ if 'monitoring-param' in vdu:
+ for param in vdu['monitoring-param']:
+ metric_name = param['nfvi-metric']
+ vrops_metric_name = METRIC_MAPPINGS[metric_name]
+ resource_uuid = self._get_resource_uuid(nsr_id, vnf_member_index, vdur['name'])
+
+ name, _id = self.get_vm_name_and_id(resource_uuid)
+ if name and _id is not None:
+ resource_id = self.get_vm_resource_id(name, _id)
+ else:
+ return
+ try:
+ end_time = int(round(time.time() * 1000))
+ time_diff = PERIOD_MSEC['YEAR']
+ begin_time = end_time - time_diff
+
+ api_url = "/suite-api/api/resources/{}/stats?statKey={}&begin={}&end={}".format(
+ resource_id, vrops_metric_name, str(begin_time), str(end_time))
+
+ headers = {'Accept': 'application/json'}
+
+ resp = requests.get(self.vrops_site + api_url,
+ auth=(self.vrops_user, self.vrops_password), verify=False, headers=headers
+ )
+
+ if resp.status_code != 200:
+ log.info("Failed to get Metrics data from vROPS for {} {} {}".format(vrops_metric_name,
+ resp.status_code,
+ resp.content))
+ return
+
+ metrics_data = {}
+ m_data = json.loads(resp.content.decode('utf-8'))
+
+ for resp_key, resp_val in six.iteritems(m_data):
+ if resp_key == 'values':
+ data = m_data['values'][0]
+ for data_k, data_v in six.iteritems(data):
+ if data_k == 'stat-list':
+ stat_list = data_v
+ for stat_list_k, stat_list_v in six.iteritems(stat_list):
+ for stat_keys, stat_vals in six.iteritems(stat_list_v[0]):
+ if stat_keys == 'timestamps':
+ metrics_data['time_series'] = stat_list_v[0]['timestamps']
+ if stat_keys == 'data':
+ metrics_data['metrics_series'] = stat_list_v[0]['data']
+
+ if metrics_data:
+ metric = VnfMetric(nsr_id,
+ vnf_member_index,
+ vdur['name'],
+ metric_name,
+ metrics_data['metrics_series'][-1])
+
+ metrics.append(metric)
+
+ except Exception as e:
+ log.debug("No metric found: %s", e)
+ pass
+
+ return metrics