From: magnussonl Date: Tue, 30 Jun 2020 14:48:08 +0000 (+0200) Subject: Support two layouts for vnf_price_list.yaml, ignore single endpoint vlds, new vim... X-Git-Tag: v8.0.0rc2~2 X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=refs%2Fchanges%2F71%2F9271%2F1;p=osm%2FPLA.git Support two layouts for vnf_price_list.yaml, ignore single endpoint vlds, new vim identification key. Change-Id: I14f9f5d3ecefec27ed68a2475149a49f0ece9208 Signed-off-by: magnussonl (cherry picked from commit d8c1b391e9b8b9531c647a422495c94ca3373ed0) --- diff --git a/docs/pla_users_guide.md b/docs/pla_users_guide.md index d7ec810..3227cb4 100644 --- a/docs/pla_users_guide.md +++ b/docs/pla_users_guide.md @@ -31,7 +31,14 @@ PLA is an optional module in OSM. It is installed together with OSM by adding `` `$ ./install_osm.sh --pla` ## Create the price lists -The price list for compute determines the price for each VNF at each VIM (or Point of Presence - PoP). The file (vnf_price_list.yaml) is written in Yaml and is exemplified below. +The price list for compute determines the price for each VNF at each VIM (or Point of Presence - PoP). +The file (vnf_price_list.yaml) is written in Yaml. There are two different structures possible for the price list file. +In the first alternative prices for a specific VIM are directly associated with a vnfd. +In the second alternative prices for a specific VIM are also associated with a OSM project id. +The latter alternative makes it possible for different OMS users to have different price models depending on their +associated OMS project. + +###vnf_price_lists.yaml - Alternative one ``` - vnfd: testVnfOne @@ -42,12 +49,6 @@ The price list for compute determines the price for each VNF at each VIM (or Poi - vim_url: http://10.234.12.44:5000/v3 vim_name: OpenStack2 price: 9 - - vim_url: http://10.234.12.46:5000/v3 - vim_name: OpenStack3 - price: 8 - - vim_url: http://10.234.12.43:5000/v3 - vim_name: OpenStack4 - price: 7 - vnfd: hackfest_multivdu-vnf prices: - vim_url: http://10.234.12.47:5000/v3 @@ -56,12 +57,43 @@ The price list for compute determines the price for each VNF at each VIM (or Poi - vim_url: http://10.234.12.44:5000/v3 vim_name: OpenStack2 price: 18 - - vim_url: http://10.234.12.46:5000/v3 - vim_name: OpenStack3 - price: 19 - - vim_url: http://10.234.12.43:5000/v3 - vim_name: OpenStack4 - price: 20 +``` +###vnf_price_list.yaml - Alternative two +``` +- vnfd: testVnfOne + project_alfa: + prices: + - vim_url: http://10.234.12.47:5000/v3 + vim_name: OpenStack1 + price: 10 + - vim_url: http://10.234.12.44:5000/v3 + vim_name: OpenStack2 + price: 9 + project_beta: + prices: + - vim_url: http://10.234.12.47:5000/v3 + vim_name: OpenStack1 + price: 9 + - vim_url: http://10.234.12.44:5000/v3 + vim_name: OpenStack2 + price: 10 +- vnfd: hackfest_multivdu-vnf + project_alfa: + prices: + - vim_url: http://10.234.12.47:5000/v3 + vim_name: OpenStack1 + price: 17 + - vim_url: http://10.234.12.44:5000/v3 + vim_name: OpenStack2 + price: 18 + project_beta: + prices: + - vim_url: http://10.234.12.47:5000/v3 + vim_name: OpenStack1 + price: 7 + - vim_url: http://10.234.12.44:5000/v3 + vim_name: OpenStack2 + price: 8 ``` The price list for transport links between VIMs (PoP Interconnecting Link – PiL). In current release the price is given per link without any consideration to BW or other QoS parameter. The file (pil_price_list.yaml) is written in Yaml and is exemplified below. Note: In current OSM release the link characteristics are hard coded into this file, in future releases this data should be retrieved from the infrastructure by monitoring mechanisms. @@ -73,43 +105,43 @@ pil: pil_latency: 120 pil_jitter: 12 pil_endpoints: - - http://10.234.12.47:5000/v3 - - http://10.234.12.44:5000/v3 + - OpenStack1 + - OpenStack2 - pil_description: Link between OpenStack1 and OpenStack3 pil_price: 13 pil_latency: 130 pil_jitter: 13 pil_endpoints: - - http://10.234.12.47:5000/v3 - - http://10.234.12.46:5000/v3 + - OpenStack1 + - OpenStack3 - pil_description: Link between OpenStack1 and OpenStack4 pil_price: 14 pil_latency: 140 pil_jitter: 14 pil_endpoints: - - http://10.234.12.47:5000/v3 - - http://10.234.12.43:5000/v3 + - OpenStack1 + - OpenStack4 - pil_description: Link between OpenStack2 and OpenStack3 pil_price: 23 pil_latency: 230 pil_jitter: 23 pil_endpoints: - - http://10.234.12.44:5000/v3 - - http://10.234.12.46:5000/v3 + - OpenStack2 + - OpenStack3 - pil_description: Link between OpenStack2 and OpenStack4 pil_price: 24 pil_latency: 240 pil_jitter: 24 pil_endpoints: - - http://10.234.12.44:5000/v3 - - http://10.234.12.43:5000/v3 + - OpenStack2 + - OpenStack4 - pil_description: Link between OpenStack3 and OpenStack4 pil_price: 34 pil_latency: 340 pil_jitter: 34 pil_endpoints: - - http://10.234.12.46:5000/v3 - - http://10.234.12.43:5000/v3 + - OpenStack3 + - OpenStack4 ``` diff --git a/osm_pla/placement/mznplacement.py b/osm_pla/placement/mznplacement.py index cf6236a..56a448d 100755 --- a/osm_pla/placement/mznplacement.py +++ b/osm_pla/placement/mznplacement.py @@ -151,12 +151,12 @@ class NsPlacementDataFactory(object): trp_link_characteristics = [[0 if col == row else 0x7fff for col in range(num_vims)] for row in range(num_vims)] for pil in self._pil_info['pil']: if characteristics in pil.keys(): - url1 = pil['pil_endpoints'][0] - url2 = pil['pil_endpoints'][1] + ep1 = pil['pil_endpoints'][0] + ep2 = pil['pil_endpoints'][1] # only consider links between applicable vims - if url1 in self._vim_accounts_info and url2 in self._vim_accounts_info: - idx1 = self._vim_accounts_info[url1]['idx'] - idx2 = self._vim_accounts_info[url2]['idx'] + if ep1 in self._vim_accounts_info and ep2 in self._vim_accounts_info: + idx1 = self._vim_accounts_info[ep1]['idx'] + idx2 = self._vim_accounts_info[ep2]['idx'] trp_link_characteristics[idx1][idx2] = pil[characteristics] trp_link_characteristics[idx2][idx1] = pil[characteristics] @@ -170,17 +170,18 @@ class NsPlacementDataFactory(object): """ vld_desc = [] for vld in self._nsd['vld']: - if vld['mgmt-network'] is False: + if vld.get('mgmt-network', False) is False: vld_desc_entry = {} cp_refs = [ep_ref['member-vnf-index-ref'] for ep_ref in vld['vnfd-connection-point-ref']] - vld_desc_entry['cp_refs'] = cp_refs - if 'link-constraint' in vld.keys(): - for constraint in vld['link-constraint']: - if constraint['constraint-type'] == 'LATENCY': - vld_desc_entry['latency'] = constraint['value'] - elif constraint['constraint-type'] == 'JITTER': - vld_desc_entry['jitter'] = constraint['value'] - vld_desc.append(vld_desc_entry) + if len(cp_refs) == 2: + vld_desc_entry['cp_refs'] = cp_refs + if 'link-constraint' in vld.keys(): + for constraint in vld['link-constraint']: + if constraint['constraint-type'] == 'LATENCY': + vld_desc_entry['latency'] = constraint['value'] + elif constraint['constraint-type'] == 'JITTER': + vld_desc_entry['jitter'] = constraint['value'] + vld_desc.append(vld_desc_entry) # create candidates from instantiate params if self._order_constraints is not None: @@ -242,8 +243,9 @@ class NsPlacementDataFactory(object): def create_ns_placement_data(self): """populate NsPlacmentData object """ - ns_placement_data = {'vim_accounts': [vim_data['id'] for - vim_data in self._vim_accounts_info.values()], + ns_placement_data = {'vim_accounts': [vim_data['id'] for _, vim_data in sorted(self._vim_accounts_info.items(), + key=lambda item: item[1][ + 'idx'])], 'trp_link_latency': self._produce_trp_link_characteristics_data('pil_latency'), 'trp_link_jitter': self._produce_trp_link_characteristics_data('pil_jitter'), 'trp_link_price_list': self._produce_trp_link_characteristics_data('pil_price'), diff --git a/osm_pla/server/server.py b/osm_pla/server/server.py index 8d25879..674e9b6 100644 --- a/osm_pla/server/server.py +++ b/osm_pla/server/server.py @@ -18,10 +18,8 @@ import asyncio import logging -# import platform from pathlib import Path -# import pkg_resources import yaml from osm_common import dbmemory, dbmongo, msglocal, msgkafka @@ -74,6 +72,13 @@ class Server: nslcmop = self.db.get_one("nslcmops", db_filter) return nslcmop + def _get_projects(self): + """ + :return: project name to project id mapping + """ + projects = self.db.get_list("projects") + return {project['_id']: project['name'] for project in projects} + def _get_nsd(self, nsd_id): """ :param nsd_id: @@ -90,16 +95,52 @@ class Server: db_filter = {"_id": vim_account_ids} return self.db.get_list("vim_accounts", db_filter) - def _get_vnf_price_list(self, price_list_file_path): + def _read_vnf_price_list(self, price_list_file_path): + """ + read vnf price list configuration file + :param price_list_file_path: + :return: + """ + with open(str(price_list_file_path)) as pl_fd: + price_list = yaml.safe_load_all(pl_fd) + return next(price_list) + + def _price_list_with_project(self, price_list): + """ + Figure out if this price list is with project or not. + Note: to handle the unlikely event that a project is called 'prices' we do not simply check if 'prices' + is in the dict keys for a price list sequence but rather go down one step in the nesting + in which we either have + 1) 'prices:{vim_url:...}' if prices are also per project, or + 2) '{vim_url:...}' if prices are only per vim + + :param price_list: + :return: True if project part of price list, else False + """ + price_list_entry_keys = set(price_list[0].keys()) + price_list_entry_keys.remove('vnfd') + pl_key = price_list_entry_keys.pop() + entry_to_check = price_list[0][pl_key][0].keys() + return True if 'prices' in entry_to_check else False + + def _get_vnf_price_list(self, price_list_file_path, project_name=None): """ - read vnf price list configuration file and reformat its content + read vnf price list configuration file, determine its type and reformat content accordingly - :param: price_list_file: Path to price list file + :param price_list_file_path: + :param project_name: :return: dictionary formatted as {'': {'':''}} """ - with open(str(price_list_file_path)) as pl_fd: - price_list_data = yaml.safe_load_all(pl_fd) - return {i['vnfd']: {i1['vim_url']: i1['price'] for i1 in i['prices']} for i in next(price_list_data)} + price_list_data = self._read_vnf_price_list(price_list_file_path) + if self._price_list_with_project(price_list_data): + res = {} + for i in price_list_data: + price_data = i[project_name] if type(i[project_name]) is dict else i[project_name][0] + res_component = {i['vim_name']: i['price'] for i in price_data['prices']} + res.update({i['vnfd']: res_component}) + return res + else: + return {i['vnfd']: {i1['vim_name']: i1['price'] for i1 in i['prices']} for i in price_list_data} def _get_pil_info(self, pil_info_file_path): """ @@ -126,10 +167,14 @@ class Server: nslcmop = self._get_nslcmop(nslcmop_id) nsd = self._get_nsd(nslcmop['operationParams']['nsdId']) self.log.info("nsd: {}".format(nsd)) + projects = self._get_projects() + self.log.info("projects: {}".format(projects)) + nslcmop_project = nslcmop['_admin']['projects_read'][0] + self.log.info("nslcmop_project: {}".format(nslcmop_project)) valid_vim_accounts = nslcmop['operationParams']['validVimAccounts'] vim_accounts_data = self._get_vim_accounts(valid_vim_accounts) - vims_information = {_['vim_url']: _['_id'] for _ in vim_accounts_data} - price_list = self._get_vnf_price_list(Server.vnf_price_list_file) + 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)) diff --git a/osm_pla/test/pil_price_list_hackfest.yaml b/osm_pla/test/pil_price_list_hackfest.yaml new file mode 100644 index 0000000..83d24b9 --- /dev/null +++ b/osm_pla/test/pil_price_list_hackfest.yaml @@ -0,0 +1,47 @@ +# Copyright 2020 ArctosLabs Scandinavia AB +# +# 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. + +# POP Interconnecting Link (PIL), price list and latency +pil: + - pil_description: Link between OpenStack1 and OpenStack2 + pil_price: 5 + pil_latency: 20 + pil_endpoints: + - OpenStack1 + - OpenStack2 + - pil_description: Link between OpenStack1 and OpenStack3 + pil_price: 30 + pil_latency: 30 + pil_endpoints: + - OpenStack1 + - OpenStack3 + - pil_description: Link between OpenStack1 and OpenStack4 + pil_price: 30 + pil_latency: 30 + pil_endpoints: + - OpenStack1 + - OpenStack4 + - pil_description: Link between OpenStack2 and OpenStack3 + pil_price: 10 + pil_latency: 10 + pil_endpoints: + - OpenStack2 + - OpenStack3 + - pil_description: Link between OpenStack2 and OpenStack4 + pil_price: 10 + pil_latency: 10 + pil_endpoints: + - OpenStack2 + - OpenStack4 diff --git a/osm_pla/test/pil_unittest1_keys.yaml b/osm_pla/test/pil_unittest1_keys.yaml new file mode 100644 index 0000000..a222687 --- /dev/null +++ b/osm_pla/test/pil_unittest1_keys.yaml @@ -0,0 +1,65 @@ +# Copyright 2020 ArctosLabs Scandinavia AB +# +# 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. + +# POP Interconnecting Link (PIL), price list and latency +pil: + - pil_description: Link between OpenStack1 and OpenStack2 + pil_price: 12 + pil_latency: 120 + pil_jitter: 1200 + project: hackfest_project_a + pil_endpoints: + - OpenStack1 + - OpenStack2 + - pil_description: Link between OpenStack1 and OpenStack3 + pil_price: 13 + pil_latency: 130 + pil_jitter: 1300 + project: hackfest_project_a + pil_endpoints: + - OpenStack1 + - OpenStack3 + - pil_description: Link between OpenStack1 and OpenStack4 + pil_price: 14 + pil_latency: 140 + pil_jitter: 1400 + project: hackfest_project_a + pil_endpoints: + - OpenStack1 + - OpenStack4 + - pil_description: Link between OpenStack2 and OpenStack3 + pil_price: 23 + pil_latency: 230 + pil_jitter: 2300 + project: hackfest_project_a + pil_endpoints: + - OpenStack2 + - OpenStack3 + - pil_description: Link between OpenStack2 and OpenStack4 + pil_price: 24 + pil_latency: 240 + pil_jitter: 2400 + project: hackfest_project_a + pil_endpoints: + - OpenStack2 + - OpenStack4 + - pil_description: Link between OpenStack3 and OpenStack4 + pil_price: 34 + pil_latency: 340 + pil_jitter: 3400 + project: hackfest_project_a + pil_endpoints: + - OpenStack3 + - OpenStack4 diff --git a/osm_pla/test/pil_unittest2_keys.yaml b/osm_pla/test/pil_unittest2_keys.yaml new file mode 100644 index 0000000..f490082 --- /dev/null +++ b/osm_pla/test/pil_unittest2_keys.yaml @@ -0,0 +1,61 @@ +# Copyright 2020 ArctosLabs Scandinavia AB +# +# 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. + +# POP Interconnecting Link (PIL), price list and latency +pil: + - pil_description: Link between OpenStack1 and OpenStack2 + pil_price: 12 + pil_latency: 120 + pil_jitter: 1200 + project: hackfest_project_a + pil_endpoints: + - OpenStack1 + - OpenStack2 + - pil_description: Link between OpenStack1 and OpenStack3 + pil_price: 13 + pil_latency: 130 + project: hackfest_project_a + pil_endpoints: + - OpenStack1 + - OpenStack3 + - pil_description: Link between OpenStack1 and OpenStack4 + pil_price: 14 + pil_jitter: 1400 + project: hackfest_project_a + pil_endpoints: + - OpenStack1 + - OpenStack4 + - pil_description: Link between OpenStack2 and OpenStack3 + pil_price: 23 + project: hackfest_project_a + pil_endpoints: + - OpenStack2 + - OpenStack3 + - pil_description: Link between OpenStack2 and OpenStack4 + pil_price: 24 + pil_latency: 240 + pil_jitter: 2400 + project: hackfest_project_a + pil_endpoints: + - OpenStack2 + - OpenStack4 + - pil_description: Link between OpenStack3 and OpenStack4 + pil_price: 34 + pil_latency: 340 + pil_jitter: 3400 + project: hackfest_project_a + pil_endpoints: + - OpenStack3 + - OpenStack4 diff --git a/osm_pla/test/slice_hackfest_middle_nsd.yaml b/osm_pla/test/slice_hackfest_middle_nsd.yaml new file mode 100644 index 0000000..f8fa102 --- /dev/null +++ b/osm_pla/test/slice_hackfest_middle_nsd.yaml @@ -0,0 +1,63 @@ +# 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. + +nsd-catalog: + nsd: + - id: slice_hackfest_middle_nsd + name: slice_hackfest_middle_nsd + short-name: slice_hackfest_middle_ns + description: NSD to be used on Slice Session of the 8th hackfest + vendor: OSM + version: '1.0' + logo: osm_2x.png + + constituent-vnfd: + - member-vnf-index: "1" + vnfd-id-ref: slice_hackfest_middle_vnfd + + connection-point: + - name: nsd_cp_mgmt + vld-id-ref: nsd_vnfd_vld_mgmt + - name: nsd_cp_data1 + vld-id-ref: nsd_vnfd_vld_data1 + - name: nsd_cp_data2 + vld-id-ref: nsd_vnfd_vld_data2 + + vld: + - id: nsd_vnfd_vld_mgmt + name: nsd_vnfd_vld_mgmt + short-name: nsd_vnfd_vld_mgmt + type: ELAN + mgmt-network: !!bool True + vnfd-connection-point-ref: + - member-vnf-index-ref: "1" + vnfd-id-ref: slice_hackfest_middle_vnfd + vnfd-connection-point-ref: eth0 + - id: nsd_vnfd_vld_data1 + name: nsd_vnfd_vld_data1 + short-name: nsd_vnfd_vld_data1 + type: ELAN + mgmt-network: !!bool False + vnfd-connection-point-ref: + - member-vnf-index-ref: "1" + vnfd-id-ref: slice_hackfest_middle_vnfd + vnfd-connection-point-ref: eth1 + - id: nsd_vnfd_vld_data2 + name: nsd_vnfd_vld_data2 + short-name: nsd_vnfd_vld_data2 + type: ELAN + mgmt-network: !!bool False + vnfd-connection-point-ref: + - member-vnf-index-ref: "1" + vnfd-id-ref: slice_hackfest_middle_vnfd + vnfd-connection-point-ref: eth2 \ No newline at end of file diff --git a/osm_pla/test/test_nsPlacementDataFactory.py b/osm_pla/test/test_nsPlacementDataFactory.py index c53ad57..73cbac4 100644 --- a/osm_pla/test/test_nsPlacementDataFactory.py +++ b/osm_pla/test/test_nsPlacementDataFactory.py @@ -169,7 +169,7 @@ class TestNsPlacementDataFactory(TestCase): FIXME temporary, we will need more control over vim_urls and _id for test purpose - make a generator :return: vim_url and _id as dict, i.e. extract these from vim_accounts data """ - return {_['vim_url']: _['_id'] for _ in vim_accounts} + return {_['name']: _['_id'] for _ in vim_accounts} def _adjust_path(self, file): """In case we are not running from test directory, @@ -211,13 +211,13 @@ class TestNsPlacementDataFactory(TestCase): price_list_file = "vnf_price_list.yaml" with open(str(Path(self._adjust_path(price_list_file)))) as pl_fd: price_list_data = yaml.safe_load_all(pl_fd) - return {i['vnfd']: {i1['vim_url']: i1['price'] for i1 in i['prices']} for i in next(price_list_data)} + return {i['vnfd']: {i1['vim_name']: i1['price'] for i1 in i['prices']} for i in next(price_list_data)} def _produce_ut_vnf_test_price_list(self, price_list): price_list_file = price_list with open(str(Path(self._adjust_path(price_list_file)))) as pl_fd: price_list_data = yaml.safe_load_all(pl_fd) - return {i['vnfd']: {i1['vim_url']: i1['price'] for i1 in i['prices']} for i in next(price_list_data)} + return {i['vnfd']: {i1['vim_name']: i1['price'] for i1 in i['prices']} for i in next(price_list_data)} def test__produce_trp_link_characteristics_link_latency_with_more_vims(self): """ @@ -229,7 +229,7 @@ class TestNsPlacementDataFactory(TestCase): self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts_more_vims), self._produce_ut_vnf_price_list(), nsd=None, - pil_info=self._populate_pil_info('pil_unittest1.yaml'), + pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None) pil_latencies = nspdf._produce_trp_link_characteristics_data('pil_latency') content_produced = [i for row in pil_latencies for i in row] @@ -245,7 +245,7 @@ class TestNsPlacementDataFactory(TestCase): self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts_fewer_vims), self._produce_ut_vnf_price_list(), nsd=None, - pil_info=self._populate_pil_info('pil_unittest1.yaml'), + pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None) pil_latencies = nspdf._produce_trp_link_characteristics_data('pil_latency') content_produced = [i for row in pil_latencies for i in row] @@ -279,7 +279,7 @@ class TestNsPlacementDataFactory(TestCase): nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts), self._produce_ut_vnf_price_list(), nsd=None, - pil_info=self._populate_pil_info('pil_unittest1.yaml'), pinning=None) + pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None) pil_latencies = nspdf._produce_trp_link_characteristics_data('pil_latency') content_produced = [i for row in pil_latencies for i in row] self.assertEqual(Counter(content_expected), Counter(content_produced), 'trp_link_latency incorrect') @@ -293,7 +293,7 @@ class TestNsPlacementDataFactory(TestCase): nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts), self._produce_ut_vnf_price_list(), nsd=None, - pil_info=self._populate_pil_info('pil_unittest1.yaml'), pinning=None) + pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None) pil_jitter = nspdf._produce_trp_link_characteristics_data('pil_jitter') content_produced = [i for row in pil_jitter for i in row] self.assertEqual(Counter(content_expected), Counter(content_produced), 'trp_link_jitter incorrect') @@ -306,7 +306,7 @@ class TestNsPlacementDataFactory(TestCase): nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(self.vim_accounts_fewer_vims), self._produce_ut_vnf_price_list(), nsd=None, - pil_info=self._populate_pil_info('pil_unittest1.yaml'), pinning=None) + pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None) pil_latencies = nspdf._produce_trp_link_characteristics_data('pil_jitter') content_produced = [i for row in pil_latencies for i in row] self.assertEqual(Counter(content_expected), Counter(content_produced), 'trp_link_jitter incorrect') @@ -320,7 +320,7 @@ class TestNsPlacementDataFactory(TestCase): nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(self.vim_accounts_more_vims), self._produce_ut_vnf_price_list(), nsd=None, - pil_info=self._populate_pil_info('pil_unittest1.yaml'), pinning=None) + pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None) pil_latencies = nspdf._produce_trp_link_characteristics_data('pil_jitter') content_produced = [i for row in pil_latencies for i in row] self.assertEqual(Counter(content_expected), Counter(content_produced), 'trp_link_jitter incorrect') @@ -333,7 +333,7 @@ class TestNsPlacementDataFactory(TestCase): nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts), self._produce_ut_vnf_price_list(), nsd=None, - pil_info=self._populate_pil_info('pil_unittest1.yaml'), pinning=None) + pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None) pil_prices = nspdf._produce_trp_link_characteristics_data('pil_price') content_produced = [i for row in pil_prices for i in row] self.assertEqual(Counter(content_expected), Counter(content_produced), 'invalid trp link prices') @@ -346,7 +346,7 @@ class TestNsPlacementDataFactory(TestCase): nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(self.vim_accounts_fewer_vims), self._produce_ut_vnf_price_list(), nsd=None, - pil_info=self._populate_pil_info('pil_unittest1.yaml'), pinning=None) + pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None) pil_prices = nspdf._produce_trp_link_characteristics_data('pil_price') content_produced = [i for row in pil_prices for i in row] self.assertEqual(Counter(content_expected), Counter(content_produced), 'invalid trp link prices') @@ -356,7 +356,7 @@ class TestNsPlacementDataFactory(TestCase): nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts), self._produce_ut_vnf_price_list(), nsd=None, - pil_info=self._populate_pil_info('pil_unittest2.yaml'), pinning=None) + pil_info=self._populate_pil_info('pil_unittest2_keys.yaml'), pinning=None) pil_jitter = nspdf._produce_trp_link_characteristics_data('pil_jitter') content_produced = [i for row in pil_jitter for i in row] self.assertEqual(Counter(content_expected), Counter(content_produced), @@ -582,6 +582,18 @@ class TestNsPlacementDataFactory(TestCase): self.assertEqual(vld_desc_expected, nspdf._produce_vld_desc(), "vld_desc_incorrect") + def test__produce_vld_desc_slice_nsd(self): + vld_desc_expected = [] + nsd = self._get_ut_nsd_from_file('slice_hackfest_middle_nsd.yaml') + nsd = nsd['nsd-catalog']['nsd'][0] + nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts), + self._produce_ut_vnf_price_list(), + nsd=nsd, + pil_info=None, pinning=None, + order_constraints=None) + + self.assertEqual(vld_desc_expected, nspdf._produce_vld_desc(), "vld_desc_incorrect") + def test__produce_vld_desc(self): """ diff --git a/osm_pla/test/test_server.py b/osm_pla/test/test_server.py index 56cf212..bac8647 100644 --- a/osm_pla/test/test_server.py +++ b/osm_pla/test/test_server.py @@ -13,15 +13,11 @@ # See the License for the specific language governing permissions and # limitations under the License. import asyncio -# import platform -# import random import os import sys -# import unittest from unittest import TestCase, mock from unittest.mock import Mock -# import pkg_resources import yaml from osm_pla.placement.mznplacement import NsPlacementDataFactory, MznPlacementConductor @@ -264,13 +260,13 @@ class TestServer(TestCase): FIXME temporary, we will need more control over vim_urls and _id for test purpose - make a generator :return: vim_url and _id as dict, i.e. extract these from vim_accounts data """ - return {_['vim_url']: _['_id'] for _ in list_of_vims} + return {_['name']: _['_id'] for _ in list_of_vims} def _produce_ut_vnf_price_list(self): price_list_file = "vnf_price_list.yaml" with open(str(Path(price_list_file))) as pl_fd: price_list_data = yaml.safe_load_all(pl_fd) - return {i['vnfd']: {i1['vim_url']: i1['price'] for i1 in i['prices']} for i in next(price_list_data)} + return {i['vnfd']: {i1['vim_name']: i1['price'] for i1 in i['prices']} for i in next(price_list_data)} def _populate_pil_info(self, file): """ @@ -322,11 +318,17 @@ class TestServer(TestCase): def test__get_vnf_price_list(self): server = self.serverSetup() - pl = server._get_vnf_price_list(Path(self._adjust_path('./vnf_price_list.yaml'))) - self.assertIs(type(pl), dict, "price list not a dictionary") - for k, v in pl.items(): + pl1 = server._get_vnf_price_list(Path(self._adjust_path('./vnf_price_list.yaml'))) + self.assertIs(type(pl1), dict, "price list not a dictionary") + for k, v in pl1.items(): self.assertIs(type(v), dict, "price list values not a dict") + pl2 = server._get_vnf_price_list(Path(self._adjust_path('./vnf_price_list_keys.yaml')), 'hackfest_project_a') + self.assertIs(type(pl2), dict, "price list not a dictionary") + for k, v in pl2.items(): + self.assertIs(type(v), dict, "price list values not a dict") + self.assertEqual(pl1, pl2, "non-project and project price lists differ") + def test__get_pil_info(self): server = self.serverSetup() ppi = server._get_pil_info(Path(self._adjust_path('./pil_price_list.yaml'))) @@ -356,7 +358,9 @@ class TestServer(TestCase): @mock.patch.object(Server, '_get_nslcmop') @mock.patch.object(Server, '_get_vnf_price_list') @mock.patch.object(Server, '_get_pil_info') - def test_get_placement(self, mock_get_pil_info, mock_get_vnf_price_list, mock__get_nslcmop, mock__get_nsd, + @mock.patch.object(Server, '_get_projects') + def test_get_placement(self, mock_get_projects, mock_get_pil_info, mock_get_vnf_price_list, mock__get_nslcmop, + mock__get_nsd, mock__get_vim_accounts, mock_create_ns_placement_data, mock_do_placement_computation): @@ -377,6 +381,7 @@ class TestServer(TestCase): mock_do_placement_computation.return_value = placement_ret_val _run(server.get_placement(nslcmop_record_wo_pinning['id'])) + self.assertTrue(mock_get_projects.called, '_get_projects not called as expected') self.assertTrue(mock_get_vnf_price_list.called, '_get_vnf_price_list not called as expected') self.assertTrue(mock_get_pil_info.called, '_get_pil_info not called as expected') self.assertTrue(mock__get_nslcmop.called, '_get_nslcmop not called as expected') @@ -422,7 +427,9 @@ class TestServer(TestCase): @mock.patch.object(Server, '_get_nslcmop') @mock.patch.object(Server, '_get_vnf_price_list') @mock.patch.object(Server, '_get_pil_info') - def test_get_placement_with_pinning(self, mock_get_pil_info, mock_get_vnf_price_list, mock__get_nslcmop, + @mock.patch.object(Server, '_get_projects') + def test_get_placement_with_pinning(self, mock_get_projects, mock_get_pil_info, mock_get_vnf_price_list, + mock__get_nslcmop, mock__get_nsd, mock__get_vim_accounts, mock_create_ns_placement_data, mock_do_placement_computation): @@ -443,6 +450,7 @@ class TestServer(TestCase): mock_do_placement_computation.return_value = placement_ret_val _run(server.get_placement(nslcmop_record_w_pinning['id'])) + self.assertTrue((mock_get_projects.called, '_get_projects not called as expected')) self.assertTrue(mock_get_vnf_price_list.called, '_get_vnf_price_list not called as expected') self.assertTrue(mock_get_pil_info.called, '_get_pil_info not called as expected') self.assertTrue(mock__get_nslcmop.called, '_get_nslcmop not called as expected') diff --git a/osm_pla/test/vnf_price_list_keys.yaml b/osm_pla/test/vnf_price_list_keys.yaml new file mode 100644 index 0000000..ac78183 --- /dev/null +++ b/osm_pla/test/vnf_price_list_keys.yaml @@ -0,0 +1,103 @@ +# Copyright 2020 ArctosLabs Scandinavia AB +# +# 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. +- vnfd: cirros_vnfd_v2 + hackfest_project_a: + - prices: + - vim_url: http://10.234.12.47:5000/v3 + vim_name: OpenStack1 + price: 5 + - vim_url: http://10.234.12.44:5000/v3 + vim_name: OpenStack2 + price: 10 + - vim_url: http://10.234.12.46:5000/v3 + vim_name: OpenStack3 + price: 30 + - vim_url: http://10.234.12.43:5000/v3 + vim_name: OpenStack4 + price: 30 + hackfest_project_b: + - prices: + - vim_url: http://10.234.12.47:5000/v3 + vim_name: OpenStack1 + price: 5 + - vim_url: http://10.234.12.44:5000/v3 + vim_name: OpenStack2 + price: 10 + - vim_url: http://10.234.12.46:5000/v3 + vim_name: OpenStack3 + price: 30 + - vim_url: http://10.234.12.43:5000/v3 + vim_name: OpenStack4 + price: 30 +- vnfd: hackfest_multivdu-vnf + hackfest_project_a: + prices: + - vim_url: http://10.234.12.47:5000/v3 + vim_name: OpenStack1 + price: 17 + - vim_url: http://10.234.12.44:5000/v3 + vim_name: OpenStack2 + price: 18 + - vim_url: http://10.234.12.46:5000/v3 + vim_name: OpenStack3 + price: 19 + - vim_url: http://10.234.12.43:5000/v3 + vim_name: OpenStack4 + price: 20 +- vnfd: test_one_a_vnfd + hackfest_project_a: + prices: + - vim_url: http://10.234.12.47:5000/v3 + vim_name: OpenStack1 + price: 10 + - vim_url: http://10.234.12.44:5000/v3 + vim_name: OpenStack2 + price: 20 + - vim_url: http://10.234.12.46:5000/v3 + vim_name: OpenStack3 + price: 30 + - vim_url: http://10.234.12.43:5000/v3 + vim_name: OpenStack4 + price: 30 +- vnfd: test_one_b_vnfd + hackfest_project_a: + prices: + - vim_url: http://10.234.12.47:5000/v3 + vim_name: OpenStack1 + price: 10 + - vim_url: http://10.234.12.44:5000/v3 + vim_name: OpenStack2 + price: 20 + - vim_url: http://10.234.12.46:5000/v3 + vim_name: OpenStack3 + price: 30 + - vim_url: http://10.234.12.43:5000/v3 + vim_name: OpenStack4 + price: 30 +- vnfd: test_one_c_vnfd + hackfest_project_a: + prices: + - vim_url: http://10.234.12.47:5000/v3 + vim_name: OpenStack1 + price: 10 + - vim_url: http://10.234.12.44:5000/v3 + vim_name: OpenStack2 + price: 20 + - vim_url: http://10.234.12.46:5000/v3 + vim_name: OpenStack3 + price: 30 + - vim_url: http://10.234.12.43:5000/v3 + vim_name: OpenStack4 + price: 30 diff --git a/setup.py b/setup.py index 3c80986..97658f1 100755 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ from setuptools import setup def parse_requirements(requirements): with open(requirements) as f: - return [l.strip('\n') for l in f if l.strip('\n') and not l.startswith('#') and '://' not in l] + return [req.strip('\n') for req in f if req.strip('\n') and not req.startswith('#') and '://' not in req] _name = 'osm_pla'