else:
self.map_topic[topic] = topic_class(self.db, self.fs, self.msg, self.auth)
- self.map_topic["pm_jobs"] = PmJobsTopic(config["prometheus"].get("host"), config["prometheus"].get("port"))
+ self.map_topic["pm_jobs"] = PmJobsTopic(self.db, config["prometheus"].get("host"),
+ config["prometheus"].get("port"))
except (DbException, FsException, MsgException) as e:
raise EngineException(str(e), http_code=e.http_code)
# See the License for the specific language governing permissions and
# limitations under the License.
-
import asyncio
import aiohttp
+from http import HTTPStatus
+from urllib.parse import quote
from osm_nbi.base_topic import EngineException
__author__ = "Vijay R S <vijay.r@tataelxsi.co.in>"
class PmJobsTopic():
- def __init__(self, host=None, port=None):
+ def __init__(self, db, host=None, port=None):
+ self.db = db
self.url = 'http://{}:{}'.format(host, port)
- self.metric_list = ['cpu_utilization', 'average_memory_utilization', 'disk_read_ops',
- 'disk_write_ops', 'disk_read_bytes', 'disk_write_bytes', 'packets_dropped',
- 'packets_sent', 'packets_received']
+ self.nfvi_metric_list = ['cpu_utilization', 'average_memory_utilization', 'disk_read_ops',
+ 'disk_write_ops', 'disk_read_bytes', 'disk_write_bytes',
+ 'packets_dropped', 'packets_sent', 'packets_received']
+
+ def _get_vnf_metric_list(self, ns_id):
+ metric_list = self.nfvi_metric_list.copy()
+ vnfr_desc = self.db.get_list("vnfrs", {"nsr-id-ref": ns_id})
+ if not vnfr_desc:
+ raise EngineException("NS not found with id {}".format(ns_id), http_code=HTTPStatus.NOT_FOUND)
+ else:
+ for vnfr in vnfr_desc:
+ vnfd_desc = self.db.get_one("vnfds", {"_id": vnfr["vnfd-id"]}, fail_on_empty=True, fail_on_more=False)
+ if vnfd_desc.get("vdu"):
+ for vdu in vnfd_desc['vdu']:
+ # Checks for vdu metric in vdu-configuration
+ if 'vdu-configuration' in vdu and 'metrics' in vdu['vdu-configuration']:
+ metric_list.extend([quote(metric['name'])
+ for metric in vdu["vdu-configuration"]["metrics"]])
+ # Checks for vnf metric in vnf-configutaion
+ if 'vnf-configuration' in vnfd_desc and 'metrics' in vnfd_desc['vnf-configuration']:
+ metric_list.extend([quote(metric['name']) for metric in vnfd_desc["vnf-configuration"]["metrics"]])
+ metric_list = list(set(metric_list))
+ return metric_list
- async def _prom_metric_request(self, ns_id):
+ async def _prom_metric_request(self, ns_id, metrics_list):
try:
async with aiohttp.ClientSession() as session:
data = []
- for metlist in self.metric_list:
+ for metlist in metrics_list:
request_url = self.url+'/api/v1/query?query=osm_'+metlist+"{ns_id='"+ns_id+"'}"
async with session.get(request_url) as resp:
resp = await resp.json()
data.append(resp)
return data
except aiohttp.client_exceptions.ClientConnectorError as e:
- raise EngineException("Connection Failure: {}".format(e))
+ raise EngineException("Connection to '{}'Failure: {}".format(self.url, e))
def show(self, session, ns_id):
+ metrics_list = self._get_vnf_metric_list(ns_id)
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
- prom_metric = loop.run_until_complete(self._prom_metric_request(ns_id))
+ prom_metric = loop.run_until_complete(self._prom_metric_request(ns_id, metrics_list))
metric = {}
metric_temp = []
for index_list in prom_metric:
process_metric['performanceValue']['performanceValue']['performanceValue'] = index['value'][1]
process_metric['performanceValue']['performanceValue']['vnfMemberIndex'] \
= index['metric']['vnf_member_index']
- process_metric['performanceValue']['performanceValue']['vduName'] = index['metric']['vdu_name']
+ if 'vdu_name' not in index['metric']:
+ pass
+ else:
+ process_metric['performanceValue']['performanceValue']['vduName'] = index['metric']['vdu_name']
metric_temp.append(process_metric)
metric['entries'] = metric_temp
return metric
--- /dev/null
+# Copyright 2019 Preethika P(Tata Elxsi)
+#
+# 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.
+
+__author__ = "Preethika P,preethika.p@tataelxsi.co.in"
+
+"""Excepted results for pmjob functions and prometheus"""
+
+
+show_res = """
+---
+entries:
+- objectInstanceId: f48163a6-c807-47bc-9682-f72caef5af85
+ performanceMetric: osm_users
+ performanceValue:
+ performanceValue:
+ performanceValue: '1'
+ vduName: test_metric-1-ubuntuvdu1-1
+ vnfMemberIndex: '1'
+ timestamp: 1573552141.409
+- objectInstanceId: f48163a6-c807-47bc-9682-f72caef5af85
+ performanceMetric: osm_cpu_utilization
+ performanceValue:
+ performanceValue:
+ performanceValue: '0.7622979249'
+ vduName: test_metric-1-ubuntuvdu1-1
+ vnfMemberIndex: '1'
+ timestamp: 1573556383.439
+- objectInstanceId: f48163a6-c807-47bc-9682-f72caef5af85
+ performanceMetric: osm_load
+ performanceValue:
+ performanceValue:
+ performanceValue: '0'
+ vduName: test_metric-1-ubuntuvdu1-1
+ vnfMemberIndex: '1'
+ timestamp: 1573552060.035
+"""
+prom_res = """
+---
+- - metric:
+ __name__: osm_users
+ instance: mon:8000
+ job: prometheus
+ ns_id: f48163a6-c807-47bc-9682-f72caef5af85
+ vdu_name: test_metric-1-ubuntuvdu1-1
+ vnf_member_index: '1'
+ value:
+ - 1573552141.409
+ - '1'
+- - metric:
+ __name__: osm_load
+ instance: mon:8000
+ job: prometheus
+ ns_id: f48163a6-c807-47bc-9682-f72caef5af85
+ vdu_name: test_metric-1-ubuntuvdu1-1
+ vnf_member_index: '1'
+ value:
+ - 1573552060.035
+ - '0'
+- - metric:
+ __name__: osm_cpu_utilization
+ instance: mon:8000
+ job: prometheus
+ ns_id: f48163a6-c807-47bc-9682-f72caef5af85
+ vdu_name: test_metric-1-ubuntuvdu1-1
+ vnf_member_index: '1'
+ value:
+ - 1573556383.439
+ - '0.7622979249'
+"""
+cpu_utilization = """
+---
+status: success
+data:
+ resultType: vector
+ result:
+ - metric:
+ __name__: osm_cpu_utilization
+ instance: mon:8000
+ job: prometheus
+ ns_id: f48163a6-c807-47bc-9682-f72caef5af85
+ vdu_name: test_metric-1-ubuntuvdu1-1
+ vnf_member_index: '1'
+ value:
+ - 1573556383.439
+ - '0.7622979249'
+"""
+users = """
+---
+status: success
+data:
+ resultType: vector
+ result:
+ - metric:
+ __name__: osm_users
+ instance: mon:8000
+ job: prometheus
+ ns_id: f48163a6-c807-47bc-9682-f72caef5af85
+ vdu_name: test_metric-1-ubuntuvdu1-1
+ vnf_member_index: '1'
+ value:
+ - 1573552141.409
+ - '1'
+"""
+load = """
+---
+status: success
+data:
+ resultType: vector
+ result:
+ - metric:
+ __name__: osm_load
+ instance: mon:8000
+ job: prometheus
+ ns_id: f48163a6-c807-47bc-9682-f72caef5af85
+ vdu_name: test_metric-1-ubuntuvdu1-1
+ vnf_member_index: '1'
+ value:
+ - 1573552060.035
+ - '0'
+"""
+empty = """
+---
+status: success
+data:
+ resultType: vector
+ result: []
+"""
vdu-monitoring-param:
vdu-monitoring-param-ref: dataVM_cpu_util
vdu-ref: dataVM
+ - id: dataVM_users
+ aggregation-type: AVERAGE
+ name: dataVM_users
+ vdu-metric:
+ vdu-metric-name-ref: users
+ vdu-ref: dataVM
+ - id: dataVM_load
+ aggregation-type: AVERAGE
+ name: dataVM_load
+ vdu-metric:
+ vdu-metric-name-ref: load
+ vdu-ref: dataVM
name: hackfest3charmed-vnf
scaling-group-descriptor:
- max-instance-count: 10
- id: dataVM_cpu_util
nfvi-metric: cpu_utilization
name: dataVM
+ vdu-configuration:
+ initial-config-primitive:
+ - parameter:
+ - value: "<rw_mgmt_ip>"
+ name: ssh-hostname
+ - value: ubuntu
+ name: ssh-username
+ - value: osm2018
+ name: ssh-password
+ name: config
+ seq: '1'
+ metrics:
+ - name: users
+ - name: load
+ juju:
+ proxy: true
+ charm: testmetrics
vm-flavor:
memory-mb: '1024'
storage-gb: '10'
--- /dev/null
+# Copyright 2019 Preethika P(Tata Elxsi)
+#
+# 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.
+
+__author__ = "Preethika P,preethika.p@tataelxsi.co.in"
+
+import asynctest
+import yaml
+import re
+from aioresponses import aioresponses
+from http import HTTPStatus
+from osm_nbi.engine import EngineException
+from osm_common.dbmemory import DbMemory
+from osm_nbi.pmjobs_topics import PmJobsTopic
+from osm_nbi.tests.test_db_descriptors import db_nsds_text, db_vnfds_text, db_nsrs_text, db_vnfrs_text
+from osm_nbi.tests.pmjob_mocks.response import show_res, prom_res, cpu_utilization, users, load, empty
+
+
+class PmJobsTopicTest(asynctest.TestCase):
+
+ def setUp(self):
+ self.db = DbMemory()
+ self.pmjobs_topic = PmJobsTopic(self.db, host="prometheus", port=9091)
+ self.db.create_list("nsds", yaml.load(db_nsds_text, Loader=yaml.Loader))
+ self.db.create_list("vnfds", yaml.load(db_vnfds_text, Loader=yaml.Loader))
+ self.db.create_list("vnfrs", yaml.load(db_vnfrs_text, Loader=yaml.Loader))
+ self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
+ self.nsr = self.db.get_list("nsrs")[0]
+ self.nsr_id = self.nsr["_id"]
+ project_id = self.nsr["_admin"]["projects_write"]
+ """metric_check_list contains the vnf metric name used in descriptor i.e users,load"""
+ self.metric_check_list = ['cpu_utilization', 'average_memory_utilization', 'disk_read_ops',
+ 'disk_write_ops', 'disk_read_bytes', 'disk_write_bytes',
+ 'packets_dropped', 'packets_sent', 'packets_received', 'users', 'load']
+ self.session = {"username": "admin", "project_id": project_id, "method": None,
+ "admin": True, "force": False, "public": False, "allow_show_user_project_role": True}
+
+ def set_get_mock_res(self, mock_res, ns_id, metric_list):
+ site = "http://prometheus:9091/api/v1/query?query=osm_metric_name{ns_id='nsr'}"
+ site = re.sub(r'nsr', ns_id, site)
+ for metric in metric_list:
+ endpoint = re.sub(r'metric_name', metric, site)
+ if metric == 'cpu_utilization':
+ response = yaml.load(cpu_utilization, Loader=yaml.Loader)
+ elif metric == 'users':
+ response = yaml.load(users, Loader=yaml.Loader)
+ elif metric == 'load':
+ response = yaml.load(load, Loader=yaml.Loader)
+ else:
+ response = yaml.load(empty, Loader=yaml.Loader)
+ mock_res.get(endpoint, payload=response)
+
+ def test_get_vnf_metric_list(self):
+ with self.subTest("Test case1 failed in test_get_vnf_metric_list"):
+ metric_list = self.pmjobs_topic._get_vnf_metric_list(self.nsr_id)
+ self.assertCountEqual(metric_list, self.metric_check_list,
+ "VNF metric list is not correctly fetched")
+ with self.subTest("Test case2 failed in test_get_vnf_metric_list"):
+ wrong_ns_id = "88d90b0c-faff-4bbc-cccc-aaaaaaaaaaaa"
+ with self.assertRaises(EngineException, msg="ns not found") as e:
+ self.pmjobs_topic._get_vnf_metric_list(wrong_ns_id)
+ self.assertEqual(e.exception.http_code, HTTPStatus.NOT_FOUND, "Wrong HTTP status code")
+ self.assertIn("NS not found with id {}".format(wrong_ns_id),
+ str(e.exception), "Wrong exception text")
+
+ async def test_prom_metric_request(self):
+ with self.subTest("Test case1 failed in test_prom"):
+ prom_response = yaml.load(prom_res, Loader=yaml.Loader)
+ with aioresponses() as mock_res:
+ self.set_get_mock_res(mock_res, self.nsr_id, self.metric_check_list)
+ result = await self.pmjobs_topic._prom_metric_request(self.nsr_id, self.metric_check_list)
+ self.assertCountEqual(result, prom_response, "Metric Data is valid")
+ with self.subTest("Test case2 failed in test_prom"):
+ with self.assertRaises(EngineException, msg="Prometheus not reachable") as e:
+ await self.pmjobs_topic._prom_metric_request(self.nsr_id, self.metric_check_list)
+ self.assertIn("Connection to ", str(e.exception), "Wrong exception text")
+
+ def test_show(self):
+ with self.subTest("Test case1 failed in test_show"):
+ show_response = yaml.load(show_res, Loader=yaml.Loader)
+ with aioresponses() as mock_res:
+ self.set_get_mock_res(mock_res, self.nsr_id, self.metric_check_list)
+ result = self.pmjobs_topic.show(self.session, self.nsr_id)
+ self.assertEqual(len(result['entries']), 3, "Number of metrics returned")
+ self.assertCountEqual(result, show_response, "Response is valid")
+ with self.subTest("Test case2 failed in test_show"):
+ wrong_ns_id = "88d90b0c-faff-4bbc-cccc-aaaaaaaaaaaa"
+ with aioresponses() as mock_res:
+ self.set_get_mock_res(mock_res, wrong_ns_id, self.metric_check_list)
+ with self.assertRaises(EngineException, msg="ns not found") as e:
+ self.pmjobs_topic.show(self.session, wrong_ns_id)
+ self.assertEqual(e.exception.http_code, HTTPStatus.NOT_FOUND, "Wrong HTTP status code")
+ self.assertIn("NS not found with id {}".format(wrong_ns_id), str(e.exception),
+ "Wrong exception text")
requests
git+https://osm.etsi.org/gerrit/osm/common.git#egg=osm-common
git+https://osm.etsi.org/gerrit/osm/IM.git#egg=osm-im
-aiohttp==0.20.2
+aiohttp==2.3.10
# mock
# pyangbind
pyang
+aioresponses
+asynctest
usedevelop = True
basepython = python3
install_command = python3 -m pip install -r requirements.txt -U {opts} {packages}
-deps = -r{toxinidir}/test-requirements.txt
[testenv:flake8]
basepython = python3
[testenv:unittest]
basepython = python3
+deps = asynctest
+ aioresponses
commands = python3 -m unittest discover {toxinidir}/osm_nbi/tests -v