From 31181aa29c6c0489b1629877e25fdafb62e3f4e2 Mon Sep 17 00:00:00 2001 From: magnussonl Date: Wed, 25 Nov 2020 09:04:51 +0100 Subject: [PATCH] Bug 1212 Change-Id: Ibc5da0e568f4b856146ecaca6fdce4ea7417208b Signed-off-by: magnussonl --- Dockerfile | 2 +- osm_pla/server/server.py | 37 +++++++++++++++++++++++++++++++++---- osm_pla/test/test_server.py | 34 +++++++++++++++++++++++++--------- 3 files changed, 59 insertions(+), 14 deletions(-) diff --git a/Dockerfile b/Dockerfile index 234679c..64e8f27 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM ubuntu:16.04 +FROM ubuntu:18.04 RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get -y install git tox make python3 python3-pip python-all && \ diff --git a/osm_pla/server/server.py b/osm_pla/server/server.py index 674e9b6..a1b7b64 100644 --- a/osm_pla/server/server.py +++ b/osm_pla/server/server.py @@ -18,6 +18,7 @@ import asyncio import logging +import itertools from pathlib import Path import yaml @@ -152,6 +153,21 @@ class Server: data = yaml.safe_load_all(pil_fd) return next(data) + def _create_vnf_id_maps(self, nsd): + """ + map identifier for 'member-vnf-index' in nsd to syntax that is safe for mzn + + return tuples with mappings {: } and {: } + """ + next_idx = itertools.count() + member_vnf_index2mzn = {e['member-vnf-index']: 'VNF' + str(next(next_idx)) for e in + nsd['constituent-vnfd']} + + # reverse the name map dictionary, used when the placement result is remapped + mzn_name2member_vnf_index = {v: k for k, v in member_vnf_index2mzn.items()} + + return member_vnf_index2mzn, mzn_name2member_vnf_index + async def get_placement(self, nslcmop_id): """ - Collects and prepares placement information. @@ -166,7 +182,14 @@ class Server: try: nslcmop = self._get_nslcmop(nslcmop_id) nsd = self._get_nsd(nslcmop['operationParams']['nsdId']) - self.log.info("nsd: {}".format(nsd)) + member_vnf_index2mzn, mzn2member_vnf_index = self._create_vnf_id_maps(nsd) + # adjust vnf identifiers + for e in nsd['constituent-vnfd']: + e['member-vnf-index'] = member_vnf_index2mzn[e['member-vnf-index']] + for vld in nsd['vld']: + for cp_ref in vld['vnfd-connection-point-ref']: + cp_ref['member-vnf-index-ref'] = member_vnf_index2mzn[cp_ref['member-vnf-index-ref']] + self.log.info("adjusted nsd: {}".format(nsd)) projects = self._get_projects() self.log.info("projects: {}".format(projects)) nslcmop_project = nslcmop['_admin']['projects_read'][0] @@ -176,8 +199,11 @@ class Server: vims_information = {_['name']: _['_id'] for _ in vim_accounts_data} price_list = self._get_vnf_price_list(Server.vnf_price_list_file, projects[nslcmop_project]) pil_info = self._get_pil_info(Server.pil_price_list_file) - pinning = nslcmop['operationParams'].get('vnf') - self.log.info("pinning: {}".format(pinning)) + pinnings = nslcmop['operationParams'].get('vnf') + # remap member-vnf-index values according to id map + for pinning in pinnings: + pinning['member-vnf-index'] = member_vnf_index2mzn[pinning['member-vnf-index']] + self.log.info("pinnings: {}".format(pinnings)) order_constraints = nslcmop['operationParams'].get('placement-constraints') self.log.info("order constraints: {}".format(order_constraints)) @@ -185,7 +211,7 @@ class Server: price_list, nsd, pil_info, - pinning, order_constraints).create_ns_placement_data() + pinnings, order_constraints).create_ns_placement_data() vnf_placement = MznPlacementConductor(self.log).do_placement_computation(nspd) @@ -194,6 +220,9 @@ class Server: self.log.exception("PLA fault. Exception: {}".format(e)) vnf_placement = [] finally: + # remap names in vnf_placement + for e in vnf_placement: + e['member-vnf-index'] = mzn2member_vnf_index[e['member-vnf-index']] await self.msgBus.aiowrite("pla", "placement", {'placement': {'vnf': vnf_placement, 'nslcmopId': nslcmop_id}}) diff --git a/osm_pla/test/test_server.py b/osm_pla/test/test_server.py index bac8647..737ca68 100644 --- a/osm_pla/test/test_server.py +++ b/osm_pla/test/test_server.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import asyncio +import copy import os import sys from unittest import TestCase, mock @@ -309,6 +310,18 @@ class TestServer(TestCase): _ = server._get_nsd(nslcmop_record_wo_pinning['operationParams']['nsdId']) server.db.get_one.assert_called_with("nsds", {'_id': nslcmop_record_wo_pinning['operationParams']['nsdId']}) + def test__create_vnf_id_maps(self): + server = self.serverSetup() + server.db = Mock() + expected_mvi2mzn = {'one': 'VNF0', 'two': 'VNF1', 'three': 'VNF2'} + expected_mzn2mvi = {'VNF0': 'one', 'VNF1': 'two', 'VNF2': 'three'} + + nsd_for_test = copy.deepcopy(nsd_from_db) + mvi2mzn, mzn2mvi = server._create_vnf_id_maps(nsd_for_test) + + self.assertDictEqual(expected_mvi2mzn, mvi2mzn, 'Faulty mzn2member-vnf-index mapping') + self.assertDictEqual(expected_mzn2mvi, mzn2mvi, 'Faulty mzn2member-vnf-index mapping') + def test__get_vim_accounts(self): # OK server = self.serverSetup() server.db = Mock() @@ -368,13 +381,14 @@ class TestServer(TestCase): run _get_placement and check that things get called as expected :return: """ - placement_ret_val = [{'vimAccountId': 'bbbbbbbb-38f5-438d-b8ee-3f93b3531f87', 'member-vnf-index': 'one'}, - {'vimAccountId': 'aaaaaaaa-38f5-438d-b8ee-3f93b3531f87', 'member-vnf-index': 'two'}, - {'vimAccountId': 'aaaaaaaa-38f5-438d-b8ee-3f93b3531f87', 'member-vnf-index': 'three'}] + placement_ret_val = [{'vimAccountId': 'bbbbbbbb-38f5-438d-b8ee-3f93b3531f87', 'member-vnf-index': 'VNF0'}, + {'vimAccountId': 'aaaaaaaa-38f5-438d-b8ee-3f93b3531f87', 'member-vnf-index': 'VNF1'}, + {'vimAccountId': 'aaaaaaaa-38f5-438d-b8ee-3f93b3531f87', 'member-vnf-index': 'VNF2'}] server = self.serverSetup() server.msgBus.aiowrite = _async_mock() - mock__get_nsd.return_value = nsd_from_db + nsd_for_test = copy.deepcopy(nsd_from_db) + mock__get_nsd.return_value = nsd_for_test mock__get_vim_accounts.return_value = list_of_vims # FIXME need update to match nslcmop, not for test but for consistency @@ -437,13 +451,14 @@ class TestServer(TestCase): run _get_placement and check that things get called as expected :return: """ - placement_ret_val = [{'vimAccountId': 'bbbbbbbb-38f5-438d-b8ee-3f93b3531f87', 'member-vnf-index': 'one'}, - {'vimAccountId': 'aaaaaaaa-38f5-438d-b8ee-3f93b3531f87', 'member-vnf-index': 'two'}, - {'vimAccountId': 'aaaaaaaa-38f5-438d-b8ee-3f93b3531f87', 'member-vnf-index': 'three'}] + placement_ret_val = [{'vimAccountId': 'bbbbbbbb-38f5-438d-b8ee-3f93b3531f87', 'member-vnf-index': 'VNF0'}, + {'vimAccountId': 'aaaaaaaa-38f5-438d-b8ee-3f93b3531f87', 'member-vnf-index': 'VNF1'}, + {'vimAccountId': 'aaaaaaaa-38f5-438d-b8ee-3f93b3531f87', 'member-vnf-index': 'VNF2'}] server = self.serverSetup() server.msgBus.aiowrite = _async_mock() - mock__get_nsd.return_value = nsd_from_db + nsd_for_test = copy.deepcopy(nsd_from_db) + mock__get_nsd.return_value = nsd_for_test mock__get_vim_accounts.return_value = list_of_vims # FIXME need update to match nslcmop, not for test but for consistency @@ -506,7 +521,8 @@ class TestServer(TestCase): server = self.serverSetup() server.msgBus.aiowrite = _async_mock() - mock__get_nsd.return_value = nsd_from_db + nsd_for_test = copy.deepcopy(nsd_from_db) + mock__get_nsd.return_value = nsd_for_test mock__get_nsd.side_effect = RuntimeError('kaboom!') mock__get_vim_accounts.return_value = list_of_vims mock_do_placement_computation.return_value = \ -- 2.17.1