# 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. import datetime import logging # import unittest from unittest import TestCase # import random # from operator import itemgetter import re from jinja2 import Template from osm_pla.placement.mznplacement import MznModelGenerator test_ns_placement_data_str = { "vim_accounts": [ "vim" + vim_account.replace("-", "_") for vim_account in [ "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87", "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87", "cccccccc-ed84-4e49-b5df-a9d117bd731f", "dddddddd-ed84-4e49-b5df-a9d117bd731f", "eeeeeeee-38f5-438d-b8ee-3f93b3531f87", ] ], "trp_link_latency": [ [0, 50, 100, 150, 200], [0, 0, 100, 150, 200], [0, 0, 0, 150, 200], [0, 0, 0, 0, 200], [0, 0, 0, 0, 0], ], "trp_link_jitter": [ [0, 5, 10, 15, 20], [0, 0, 10, 15, 20], [0, 0, 0, 15, 20], [0, 0, 0, 0, 20], [0, 0, 0, 0, 0], ], "trp_link_price_list": [ [0, 5, 6, 6, 7], [0, 0, 6, 6, 7], [0, 0, 0, 6, 7], [0, 0, 0, 0, 7], [0, 0, 0, 0, 0], ], "ns_desc": [ {"vnf_id": "one", "vnf_price_per_vim": [50, 51, 52, 53, 54]}, {"vnf_id": "two", "vnf_price_per_vim": [20, 21, 22, 23, 24]}, {"vnf_id": "three", "vnf_price_per_vim": [70, 71, 72, 73, 74]}, {"vnf_id": "four", "vnf_price_per_vim": [40, 41, 42, 43, 44]}, ], "vld_desc": [ {"cp_refs": ["one", "two"], "latency": 150, "jitter": 30}, {"cp_refs": ["two", "three"], "latency": 140, "jitter": 30}, {"cp_refs": ["three", "four"], "latency": 130, "jitter": 30}, ], "generator_data": {"file": __file__, "time": datetime.datetime.now()}, } test_ns_placement_data_str_no_vld_constraints = { "vim_accounts": [ "vim" + vim_account.replace("-", "_") for vim_account in [ "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87", "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87", "cccccccc-ed84-4e49-b5df-a9d117bd731f", "dddddddd-ed84-4e49-b5df-a9d117bd731f", "eeeeeeee-38f5-438d-b8ee-3f93b3531f87", ] ], "trp_link_latency": [ [0, 50, 100, 150, 200], [0, 0, 100, 150, 200], [0, 0, 0, 150, 200], [0, 0, 0, 0, 200], [0, 0, 0, 0, 0], ], "trp_link_jitter": [ [0, 5, 10, 15, 20], [0, 0, 10, 15, 20], [0, 0, 0, 15, 20], [0, 0, 0, 0, 20], [0, 0, 0, 0, 0], ], "trp_link_price_list": [ [0, 5, 6, 6, 7], [0, 0, 6, 6, 7], [0, 0, 0, 6, 7], [0, 0, 0, 0, 7], [0, 0, 0, 0, 0], ], "ns_desc": [ {"vnf_id": "one", "vnf_price_per_vim": [50, 51, 52, 53, 54]}, {"vnf_id": "two", "vnf_price_per_vim": [20, 21, 22, 23, 24]}, {"vnf_id": "three", "vnf_price_per_vim": [70, 71, 72, 73, 74]}, {"vnf_id": "four", "vnf_price_per_vim": [40, 41, 42, 43, 44]}, ], "vld_desc": [ {"cp_refs": ["one", "two"]}, {"cp_refs": ["two", "three"]}, {"cp_refs": ["three", "four"]}, ], "generator_data": {"file": __file__, "time": datetime.datetime.now()}, } test_ns_placement_data = { "vim_accounts": [ "vim" + vim_account.replace("-", "_") for vim_account in [ "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87", "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87", "cccccccc-ed84-4e49-b5df-a9d117bd731f", "dddddddd-ed84-4e49-b5df-a9d117bd731f", "eeeeeeee-38f5-438d-b8ee-3f93b3531f87", ] ], "trp_link_latency": [ [0, 50, 100, 150, 200], [0, 0, 100, 150, 200], [0, 0, 0, 150, 200], [0, 0, 0, 0, 200], [0, 0, 0, 0, 0], ], "trp_link_jitter": [ [0, 5, 10, 15, 20], [0, 0, 10, 15, 20], [0, 0, 0, 15, 20], [0, 0, 0, 0, 20], [0, 0, 0, 0, 0], ], "trp_link_price_list": [ [0, 5, 6, 6, 7], [0, 0, 6, 6, 7], [0, 0, 0, 6, 7], [0, 0, 0, 0, 7], [0, 0, 0, 0, 0], ], "ns_desc": [ {"vnf_id": "1", "vnf_price_per_vim": [50, 51, 52, 53, 54]}, {"vnf_id": "2", "vnf_price_per_vim": [20, 21, 22, 23, 24]}, {"vnf_id": "3", "vnf_price_per_vim": [70, 71, 72, 73, 74]}, {"vnf_id": "4", "vnf_price_per_vim": [40, 41, 42, 43, 44]}, ], "vld_desc": [ {"cp_refs": ["1", "2"], "latency": 150, "jitter": 30}, {"cp_refs": ["2", "3"], "latency": 140, "jitter": 30}, {"cp_refs": ["3", "4"], "latency": 130, "jitter": 30}, ], "generator_data": {"file": __file__, "time": datetime.datetime.now()}, } test_ns_placement_data_w_pinning = { "vim_accounts": [ "vim" + vim_account.replace("-", "_") for vim_account in [ "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87", "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87", "cccccccc-ed84-4e49-b5df-a9d117bd731f", "dddddddd-ed84-4e49-b5df-a9d117bd731f", "eeeeeeee-38f5-438d-b8ee-3f93b3531f87", ] ], "trp_link_latency": [ [0, 50, 100, 150, 200], [0, 0, 100, 150, 200], [0, 0, 0, 150, 200], [0, 0, 0, 0, 200], [0, 0, 0, 0, 0], ], "trp_link_jitter": [ [0, 5, 10, 15, 20], [0, 0, 10, 15, 20], [0, 0, 0, 15, 20], [0, 0, 0, 0, 20], [0, 0, 0, 0, 0], ], "trp_link_price_list": [ [0, 5, 6, 6, 7], [0, 0, 6, 6, 7], [0, 0, 0, 6, 7], [0, 0, 0, 0, 7], [0, 0, 0, 0, 0], ], "ns_desc": [ {"vnf_id": "1", "vnf_price_per_vim": [50, 51, 52, 53, 54]}, { "vnf_id": "2", "vnf_price_per_vim": [20, 21, 22, 23, 24], "vim_account": "vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87", }, {"vnf_id": "3", "vnf_price_per_vim": [70, 71, 72, 73, 74]}, { "vnf_id": "4", "vnf_price_per_vim": [40, 41, 42, 43, 44], "vim_account": "vimcccccccc_ed84_4e49_b5df_a9d117bd731f", }, ], "vld_desc": [ {"cp_refs": ["1", "2"], "latency": 150, "jitter": 30}, {"cp_refs": ["2", "3"], "latency": 140, "jitter": 30}, {"cp_refs": ["3", "4"], "latency": 130, "jitter": 30}, ], "generator_data": {"file": __file__, "time": datetime.datetime.now()}, } test_ns_placement_data_w_pinning_str = { "vim_accounts": [ "vim" + vim_account.replace("-", "_") for vim_account in [ "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87", "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87", "cccccccc-ed84-4e49-b5df-a9d117bd731f", "dddddddd-ed84-4e49-b5df-a9d117bd731f", "eeeeeeee-38f5-438d-b8ee-3f93b3531f87", ] ], "trp_link_latency": [ [0, 50, 100, 150, 200], [0, 0, 100, 150, 200], [0, 0, 0, 150, 200], [0, 0, 0, 0, 200], [0, 0, 0, 0, 0], ], "trp_link_jitter": [ [0, 5, 10, 15, 20], [0, 0, 10, 15, 20], [0, 0, 0, 15, 20], [0, 0, 0, 0, 20], [0, 0, 0, 0, 0], ], "trp_link_price_list": [ [0, 5, 6, 6, 7], [0, 0, 6, 6, 7], [0, 0, 0, 6, 7], [0, 0, 0, 0, 7], [0, 0, 0, 0, 0], ], "ns_desc": [ {"vnf_id": "one", "vnf_price_per_vim": [50, 51, 52, 53, 54]}, { "vnf_id": "two", "vnf_price_per_vim": [20, 21, 22, 23, 24], "vim_account": "vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87", }, {"vnf_id": "three", "vnf_price_per_vim": [70, 71, 72, 73, 74]}, { "vnf_id": "four", "vnf_price_per_vim": [40, 41, 42, 43, 44], "vim_account": "vimcccccccc_ed84_4e49_b5df_a9d117bd731f", }, ], "vld_desc": [ {"cp_refs": ["one", "two"], "latency": 150, "jitter": 30}, {"cp_refs": ["two", "three"], "latency": 140, "jitter": 30}, {"cp_refs": ["three", "four"], "latency": 130, "jitter": 30}, ], "generator_data": {"file": __file__, "time": datetime.datetime.now()}, } test_ns_placement_data_str_no_vld = { "vim_accounts": [ "vim" + vim_account.replace("-", "_") for vim_account in [ "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87", "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87", "cccccccc-ed84-4e49-b5df-a9d117bd731f", "dddddddd-ed84-4e49-b5df-a9d117bd731f", "eeeeeeee-38f5-438d-b8ee-3f93b3531f87", ] ], "trp_link_latency": [ [0, 50, 100, 150, 200], [0, 0, 100, 150, 200], [0, 0, 0, 150, 200], [0, 0, 0, 0, 200], [0, 0, 0, 0, 0], ], "trp_link_jitter": [ [0, 5, 10, 15, 20], [0, 0, 10, 15, 20], [0, 0, 0, 15, 20], [0, 0, 0, 0, 20], [0, 0, 0, 0, 0], ], "trp_link_price_list": [ [0, 5, 6, 6, 7], [0, 0, 6, 6, 7], [0, 0, 0, 6, 7], [0, 0, 0, 0, 7], [0, 0, 0, 0, 0], ], "ns_desc": [{"vnf_id": "one", "vnf_price_per_vim": [50, 51, 52, 53, 54]}], "vld_desc": [], "generator_data": {"file": __file__, "time": datetime.datetime.now()}, } expected_model_fragment = """ %This is the NETWORK RESOURCE MODEL enum Vims = { vimaaaaaaaa_38f5_438d_b8ee_3f93b3531f87, vimbbbbbbbb_38f5_438d_b8ee_3f93b3531f87, vimcccccccc_ed84_4e49_b5df_a9d117bd731f, vimdddddddd_ed84_4e49_b5df_a9d117bd731f, vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87}; % The vim-accounts array[Vims, Vims] of int: trp_link_latency = [|0,50,100,150,200, |0,0,100,150,200, |0,0,0,150,200, |0,0,0,0,200, |0,0,0,0,0, |]; % Transport link latency between data centers array[Vims, Vims] of int: trp_link_jitter = [|0,5,10,15,20, |0,0,10,15,20, |0,0,0,15,20, |0,0,0,0,20, |0,0,0,0,0, |]; % Transport link jitter between data centers array[Vims, Vims] of int: trp_link_price_list = [|0,5,6,6,7, |0,0,6,6,7, |0,0,0,6,7, |0,0,0,0,7, |0,0,0,0,0, |]; % Transport link price list array[Vims] of int: vim_price_list_1 = [50,51,52,53,54]; array[Vims] of int: vim_price_list_2 = [20,21,22,23,24]; array[Vims] of int: vim_price_list_3 = [70,71,72,73,74]; array[Vims] of int: vim_price_list_4 = [40,41,42,43,44]; % This is the NETWORK BASIC LOAD MODEL (CONSUMED) % NOTE. This is not applicable in OSM Release 7 % This is the SERVICE CONSUMPTION MODEL % These are the variables, i.e. which DC to select for each VNF var Vims: VNF1; var Vims: VNF2; var Vims: VNF3; var Vims: VNF4; % These are the set of rules for selecting DCs to VNFs constraint trp_link_latency[VNF1, VNF2] <= 150; constraint trp_link_latency[VNF2, VNF3] <= 140; constraint trp_link_latency[VNF3, VNF4] <= 130; constraint trp_link_jitter[VNF1, VNF2] <= 30; constraint trp_link_jitter[VNF2, VNF3] <= 30; constraint trp_link_jitter[VNF3, VNF4] <= 30; % Calculate the cost for VNFs and cost for transport link and total cost var int: used_transport_cost =trp_link_price_list[VNF1, VNF2]+ trp_link_price_list[VNF2, VNF3]+ trp_link_price_list[VNF3, VNF4]; var int: used_vim_cost =vim_price_list_1[VNF1]+ vim_price_list_2[VNF2]+ vim_price_list_3[VNF3]+ vim_price_list_4[VNF4]; var int: total_cost = used_transport_cost + used_vim_cost; solve minimize total_cost; """ expected_model_fragment_str = """ %This is the NETWORK RESOURCE MODEL enum Vims = { vimaaaaaaaa_38f5_438d_b8ee_3f93b3531f87, vimbbbbbbbb_38f5_438d_b8ee_3f93b3531f87, vimcccccccc_ed84_4e49_b5df_a9d117bd731f, vimdddddddd_ed84_4e49_b5df_a9d117bd731f, vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87}; % The vim-accounts array[Vims, Vims] of int: trp_link_latency = [|0,50,100,150,200, |0,0,100,150,200, |0,0,0,150,200, |0,0,0,0,200, |0,0,0,0,0, |]; % Transport link latency between data centers array[Vims, Vims] of int: trp_link_jitter = [|0,5,10,15,20, |0,0,10,15,20, |0,0,0,15,20, |0,0,0,0,20, |0,0,0,0,0, |]; % Transport link jitter between data centers array[Vims, Vims] of int: trp_link_price_list = [|0,5,6,6,7, |0,0,6,6,7, |0,0,0,6,7, |0,0,0,0,7, |0,0,0,0,0, |]; % Transport link price list array[Vims] of int: vim_price_list_one = [50,51,52,53,54]; array[Vims] of int: vim_price_list_two = [20,21,22,23,24]; array[Vims] of int: vim_price_list_three = [70,71,72,73,74]; array[Vims] of int: vim_price_list_four = [40,41,42,43,44]; % This is the NETWORK BASIC LOAD MODEL (CONSUMED) % NOTE. This is not applicable in OSM Release 7 % This is the SERVICE CONSUMPTION MODEL % These are the variables, i.e. which DC to select for each VNF var Vims: VNFone; var Vims: VNFtwo; var Vims: VNFthree; var Vims: VNFfour; % These are the set of rules for selecting DCs to VNFs constraint trp_link_latency[VNFone, VNFtwo] <= 150; constraint trp_link_latency[VNFtwo, VNFthree] <= 140; constraint trp_link_latency[VNFthree, VNFfour] <= 130; constraint trp_link_jitter[VNFone, VNFtwo] <= 30; constraint trp_link_jitter[VNFtwo, VNFthree] <= 30; constraint trp_link_jitter[VNFthree, VNFfour] <= 30; % Calculate the cost for VNFs and cost for transport link and total cost var int: used_transport_cost =trp_link_price_list[VNFone, VNFtwo]+ trp_link_price_list[VNFtwo, VNFthree]+ trp_link_price_list[VNFthree, VNFfour]; var int: used_vim_cost =vim_price_list_one[VNFone]+ vim_price_list_two[VNFtwo]+ vim_price_list_three[VNFthree]+ vim_price_list_four[VNFfour]; var int: total_cost = used_transport_cost + used_vim_cost; solve minimize total_cost; """ expected_model_fragment_str_no_vld_constraints = """ %This is the NETWORK RESOURCE MODEL enum Vims = { vimaaaaaaaa_38f5_438d_b8ee_3f93b3531f87, vimbbbbbbbb_38f5_438d_b8ee_3f93b3531f87, vimcccccccc_ed84_4e49_b5df_a9d117bd731f, vimdddddddd_ed84_4e49_b5df_a9d117bd731f, vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87}; % The vim-accounts array[Vims, Vims] of int: trp_link_latency = [|0,50,100,150,200, |0,0,100,150,200, |0,0,0,150,200, |0,0,0,0,200, |0,0,0,0,0, |]; % Transport link latency between data centers array[Vims, Vims] of int: trp_link_jitter = [|0,5,10,15,20, |0,0,10,15,20, |0,0,0,15,20, |0,0,0,0,20, |0,0,0,0,0, |]; % Transport link jitter between data centers array[Vims, Vims] of int: trp_link_price_list = [|0,5,6,6,7, |0,0,6,6,7, |0,0,0,6,7, |0,0,0,0,7, |0,0,0,0,0, |]; % Transport link price list array[Vims] of int: vim_price_list_one = [50,51,52,53,54]; array[Vims] of int: vim_price_list_two = [20,21,22,23,24]; array[Vims] of int: vim_price_list_three = [70,71,72,73,74]; array[Vims] of int: vim_price_list_four = [40,41,42,43,44]; % This is the NETWORK BASIC LOAD MODEL (CONSUMED) % NOTE. This is not applicable in OSM Release 7 % This is the SERVICE CONSUMPTION MODEL % These are the variables, i.e. which DC to select for each VNF var Vims: VNFone; var Vims: VNFtwo; var Vims: VNFthree; var Vims: VNFfour; % These are the set of rules for selecting DCs to VNFs % Calculate the cost for VNFs and cost for transport link and total cost var int: used_transport_cost =trp_link_price_list[VNFone, VNFtwo]+ trp_link_price_list[VNFtwo, VNFthree]+ trp_link_price_list[VNFthree, VNFfour]; var int: used_vim_cost =vim_price_list_one[VNFone]+ vim_price_list_two[VNFtwo]+ vim_price_list_three[VNFthree]+ vim_price_list_four[VNFfour]; var int: total_cost = used_transport_cost + used_vim_cost; solve minimize total_cost; """ expected_model_fragment_w_pinning = """ %This is the NETWORK RESOURCE MODEL enum Vims = { vimaaaaaaaa_38f5_438d_b8ee_3f93b3531f87, vimbbbbbbbb_38f5_438d_b8ee_3f93b3531f87, vimcccccccc_ed84_4e49_b5df_a9d117bd731f, vimdddddddd_ed84_4e49_b5df_a9d117bd731f, vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87}; % The vim-accounts array[Vims, Vims] of int: trp_link_latency = [|0,50,100,150,200, |0,0,100,150,200, |0,0,0,150,200, |0,0,0,0,200, |0,0,0,0,0, |]; % Transport link latency between data centers array[Vims, Vims] of int: trp_link_jitter = [|0,5,10,15,20, |0,0,10,15,20, |0,0,0,15,20, |0,0,0,0,20, |0,0,0,0,0, |]; % Transport link jitter between data centers array[Vims, Vims] of int: trp_link_price_list = [|0,5,6,6,7, |0,0,6,6,7, |0,0,0,6,7, |0,0,0,0,7, |0,0,0,0,0, |]; % Transport link price list array[Vims] of int: vim_price_list_1 = [50,51,52,53,54]; array[Vims] of int: vim_price_list_2 = [20,21,22,23,24]; array[Vims] of int: vim_price_list_3 = [70,71,72,73,74]; array[Vims] of int: vim_price_list_4 = [40,41,42,43,44]; % This is the NETWORK BASIC LOAD MODEL (CONSUMED) % NOTE. This is not applicable in OSM Release 7 % This is the SERVICE CONSUMPTION MODEL % These are the variables, i.e. which DC to select for each VNF var Vims: VNF1; Vims: VNF2 = vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87; var Vims: VNF3; Vims: VNF4 = vimcccccccc_ed84_4e49_b5df_a9d117bd731f; % These are the set of rules for selecting DCs to VNFs constraint trp_link_latency[VNF1, VNF2] <= 150; constraint trp_link_latency[VNF2, VNF3] <= 140; constraint trp_link_latency[VNF3, VNF4] <= 130; constraint trp_link_jitter[VNF1, VNF2] <= 30; constraint trp_link_jitter[VNF2, VNF3] <= 30; constraint trp_link_jitter[VNF3, VNF4] <= 30; % Calculate the cost for VNFs and cost for transport link and total cost var int: used_transport_cost =trp_link_price_list[VNF1, VNF2]+ trp_link_price_list[VNF2, VNF3]+ trp_link_price_list[VNF3, VNF4]; var int: used_vim_cost =vim_price_list_1[VNF1]+ vim_price_list_2[VNF2]+ vim_price_list_3[VNF3]+ vim_price_list_4[VNF4]; var int: total_cost = used_transport_cost + used_vim_cost; solve minimize total_cost; """ expected_model_fragment_w_pinning_str = """ %This is the NETWORK RESOURCE MODEL enum Vims = { vimaaaaaaaa_38f5_438d_b8ee_3f93b3531f87, vimbbbbbbbb_38f5_438d_b8ee_3f93b3531f87, vimcccccccc_ed84_4e49_b5df_a9d117bd731f, vimdddddddd_ed84_4e49_b5df_a9d117bd731f, vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87}; % The vim-accounts array[Vims, Vims] of int: trp_link_latency = [|0,50,100,150,200, |0,0,100,150,200, |0,0,0,150,200, |0,0,0,0,200, |0,0,0,0,0, |]; % Transport link latency between data centers array[Vims, Vims] of int: trp_link_jitter = [|0,5,10,15,20, |0,0,10,15,20, |0,0,0,15,20, |0,0,0,0,20, |0,0,0,0,0, |]; % Transport link jitter between data centers array[Vims, Vims] of int: trp_link_price_list = [|0,5,6,6,7, |0,0,6,6,7, |0,0,0,6,7, |0,0,0,0,7, |0,0,0,0,0, |]; % Transport link price list array[Vims] of int: vim_price_list_one = [50,51,52,53,54]; array[Vims] of int: vim_price_list_two = [20,21,22,23,24]; array[Vims] of int: vim_price_list_three = [70,71,72,73,74]; array[Vims] of int: vim_price_list_four = [40,41,42,43,44]; % This is the NETWORK BASIC LOAD MODEL (CONSUMED) % NOTE. This is not applicable in OSM Release 7 % This is the SERVICE CONSUMPTION MODEL % These are the variables, i.e. which DC to select for each VNF var Vims: VNFone; Vims: VNFtwo = vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87; var Vims: VNFthree; Vims: VNFfour = vimcccccccc_ed84_4e49_b5df_a9d117bd731f; % These are the set of rules for selecting DCs to VNFs constraint trp_link_latency[VNFone, VNFtwo] <= 150; constraint trp_link_latency[VNFtwo, VNFthree] <= 140; constraint trp_link_latency[VNFthree, VNFfour] <= 130; constraint trp_link_jitter[VNFone, VNFtwo] <= 30; constraint trp_link_jitter[VNFtwo, VNFthree] <= 30; constraint trp_link_jitter[VNFthree, VNFfour] <= 30; % Calculate the cost for VNFs and cost for transport link and total cost var int: used_transport_cost =trp_link_price_list[VNFone, VNFtwo]+ trp_link_price_list[VNFtwo, VNFthree]+ trp_link_price_list[VNFthree, VNFfour]; var int: used_vim_cost =vim_price_list_one[VNFone]+ vim_price_list_two[VNFtwo]+ vim_price_list_three[VNFthree]+ vim_price_list_four[VNFfour]; var int: total_cost = used_transport_cost + used_vim_cost; solve minimize total_cost; """ expected_model_fragment_str_no_vld = """ %This is the NETWORK RESOURCE MODEL enum Vims = { vimaaaaaaaa_38f5_438d_b8ee_3f93b3531f87, vimbbbbbbbb_38f5_438d_b8ee_3f93b3531f87, vimcccccccc_ed84_4e49_b5df_a9d117bd731f, vimdddddddd_ed84_4e49_b5df_a9d117bd731f, vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87}; % The vim-accounts array[Vims, Vims] of int: trp_link_latency = [|0,50,100,150,200, |0,0,100,150,200, |0,0,0,150,200, |0,0,0,0,200, |0,0,0,0,0, |]; % Transport link latency between data centers array[Vims, Vims] of int: trp_link_jitter = [|0,5,10,15,20, |0,0,10,15,20, |0,0,0,15,20, |0,0,0,0,20, |0,0,0,0,0, |]; % Transport link jitter between data centers array[Vims, Vims] of int: trp_link_price_list = [|0,5,6,6,7, |0,0,6,6,7, |0,0,0,6,7, |0,0,0,0,7, |0,0,0,0,0, |]; % Transport link price list array[Vims] of int: vim_price_list_one = [50,51,52,53,54]; % This is the NETWORK BASIC LOAD MODEL (CONSUMED) % NOTE. This is not applicable in OSM Release 7 % This is the SERVICE CONSUMPTION MODEL % These are the variables, i.e. which DC to select for each VNF var Vims: VNFone; % These are the set of rules for selecting DCs to VNFs % Calculate the cost for VNFs and cost for transport link and total cost var int: used_transport_cost =0; var int: used_vim_cost =vim_price_list_one[VNFone]; var int: total_cost = used_transport_cost + used_vim_cost; solve minimize total_cost; """ class TestMznModelGenerator(TestCase): def test_create_model(self): mg = MznModelGenerator(logging.getLogger(__name__)) mzn_model = mg.create_model(test_ns_placement_data_str) # so asserting exact content is difficult due to the datetime.now(), therefore we ignore the first lines self.assertTrue( expected_model_fragment_str.replace("\n", "") in mzn_model.replace("\n", ""), "faulty model generated", ) def test_create_model_no_vld_constraints(self): """ instantiate w/o constraints in nsd or order params has a valid model :return: """ mg = MznModelGenerator(logging.getLogger(__name__)) mzn_model = mg.create_model(test_ns_placement_data_str_no_vld_constraints) # so asserting exact content is difficult due to the datetime.now(), therefore we ignore the first lines self.assertTrue( expected_model_fragment_str_no_vld_constraints.replace("\n", "") in mzn_model.replace("\n", ""), "faulty model generated", ) def test_create_model_w_pinning(self): mg = MznModelGenerator(logging.getLogger(__name__)) mzn_model = mg.create_model(test_ns_placement_data_w_pinning_str) # so asserting exact content is difficult due to the datetime.now(), therefore we ignore the first lines self.assertTrue( expected_model_fragment_w_pinning_str.replace("\n", "") in mzn_model.replace("\n", ""), "faulty model generated", ) def test_create_model_no_vld(self): mg = MznModelGenerator(logging.getLogger(__name__)) mzn_model = mg.create_model(test_ns_placement_data_str_no_vld) # so asserting exact content is difficult due to the datetime.now(), therefore we ignore the first lines self.assertTrue( expected_model_fragment_str_no_vld.replace("\n", "") in mzn_model.replace("\n", ""), "faulty model generated", ) def test__load_jinja_template(self): """ add other test to check exception if template not loaded (e.g. invalid template name, perhaps also valid name but invalid content (in case jinja2 detects such things)) """ mg = MznModelGenerator(logging.getLogger(__name__)) template = mg._load_jinja_template() # Note we use the default template self.assertTrue( isinstance(template, Template), "failed to load jinja2 template" ) def test_vim_account_replace(self): mg = MznModelGenerator(logging.getLogger(__name__)) nspd = test_ns_placement_data_str mzn_model = mg.create_model(nspd) expected = ( "%This is the NETWORK RESOURCE MODEL" + "\n" + "enum Vims = {" + "\n" ) for val in test_ns_placement_data_str["vim_accounts"]: expected = expected + val.replace("-", "_") + ",\n" expected = expected[:-2] + "}; % The vim-accounts" res = re.findall(expected, mzn_model) self.assertEqual(1, len(res), "vim accounts didnt replace from - to _") def test_trp_link_price_list(self): mg = MznModelGenerator(logging.getLogger(__name__)) mzn_model = mg.create_model(test_ns_placement_data_str) expected = "array\\[Vims, Vims\\] of int: trp_link_price_list = \\[" for price_list in test_ns_placement_data_str["trp_link_price_list"]: expected = ( expected + "\\|" + (str(price_list)[1:-1]).replace(" ", "") + ",\n" ) expected = expected + "\\|\\]; % Transport link price list" res = re.findall(expected, mzn_model) self.assertEqual(1, len(res), "price list is not correct") def test_link_latency(self): mg = MznModelGenerator(logging.getLogger(__name__)) mzn_model = mg.create_model(test_ns_placement_data_str) expected = "array\\[Vims, Vims\\] of int: trp_link_latency = \\[" for link_latency in test_ns_placement_data_str["trp_link_latency"]: expected = ( expected + "\\|" + (str(link_latency)[1:-1]).replace(" ", "") + ",\n" ) expected = expected + "\\|\\]; % Transport link latency between data centers" res = re.findall(expected, mzn_model) self.assertEqual(1, len(res), "trp_link_latency values is not correct") def test_link_jitter(self): mg = MznModelGenerator(logging.getLogger(__name__)) mzn_model = mg.create_model(test_ns_placement_data_str) expected = "array\\[Vims, Vims\\] of int: trp_link_jitter = \\[" for link_jitter in test_ns_placement_data_str["trp_link_jitter"]: expected = ( expected + "\\|" + (str(link_jitter)[1:-1]).replace(" ", "") + ",\n" ) expected = expected + "\\|\\]; % Transport link jitter between data centers" res = re.findall(expected, mzn_model) self.assertEqual(1, len(res), "trp_link_jitter values is not correct") def test_price_per_vim(self): mg = MznModelGenerator(logging.getLogger(__name__)) mzn_model = mg.create_model(test_ns_placement_data_w_pinning_str) expected = "" for price_list in test_ns_placement_data_w_pinning_str["ns_desc"]: expected += ( "array\\[Vims\\] of int: vim_price_list_" + price_list.get("vnf_id") + " = " ) temp = str(price_list.get("vnf_price_per_vim"))[1:-1].replace(" ", "") expected += "\\[" + temp + "\\];\n" res = re.findall(expected, mzn_model) self.assertEqual(1, len(res), "mzn_model contains pinning") def test_pinning(self): mg = MznModelGenerator(logging.getLogger(__name__)) mzn_model = mg.create_model(test_ns_placement_data_str) expected = "" for pin_list in test_ns_placement_data_str["ns_desc"]: if pin_list.get("vim_account"): expected += ( "Vims: VNF" + pin_list.get("vnf_id") + " = " + pin_list.get("vim_account") + ";\n" ) else: expected += "var Vims: VNF" + pin_list.get("vnf_id") + ";\n" res = re.findall(expected, mzn_model) self.assertEqual(1, len(res), "mzn_model has no pinning") def test__without_pinning(self): mg = MznModelGenerator(logging.getLogger(__name__)) mzn_model = mg.create_model(test_ns_placement_data_w_pinning_str) expected = "" for pin_list in test_ns_placement_data_w_pinning_str["ns_desc"]: if pin_list.get("vim_account"): expected += ( "Vims: VNF" + pin_list.get("vnf_id") + " = " + pin_list.get("vim_account") + ";\n" ) else: expected += "var Vims: VNF" + pin_list.get("vnf_id") + ";\n" res = re.findall(expected, mzn_model) self.assertEqual(1, len(res), "mzn_model contains pinning") def test__without_constraints_for_jitter_and_latency(self): mg = MznModelGenerator(logging.getLogger(__name__)) mzn_model = mg.create_model(test_ns_placement_data_str_no_vld_constraints) expected_latency = "constraint trp_link_latency" expected_jitter = "constraint trp_link_jitter" latency_or_jitter_was_found = 0 for l_o_j in test_ns_placement_data_str_no_vld_constraints["vld_desc"]: if l_o_j.get("latency") or l_o_j.get("jitter"): latency_or_jitter_was_found = 1 res_latency = re.findall(expected_latency, mzn_model) res_jitter = re.findall(expected_jitter, mzn_model) self.assertEqual( 0, latency_or_jitter_was_found, "Jitter or latency was found in the test input", ) self.assertEqual( 0, len(res_latency), "constraint trp_link_latency was found in mzn_model" ) self.assertEqual( 0, len(res_jitter), "constraint trp_link_latency was found in mzn_model" ) def test__constraints_for_jitter_and_latency(self): mg = MznModelGenerator(logging.getLogger(__name__)) mzn_model = mg.create_model(test_ns_placement_data_str) expected_latency = "" expected_jitter = "" latency_or_jitter_was_found = 0 for l_o_j in test_ns_placement_data_str["vld_desc"]: if not (l_o_j.get("latency") or l_o_j.get("jitter")): latency_or_jitter_was_found = 1 expected_latency += ( "constraint trp_link_latency" + "\\[VNF" + l_o_j.get("cp_refs")[0] + ", VNF" + l_o_j.get("cp_refs")[1] + "\\] \\<= " + str(l_o_j.get("latency")) + ";\n\n" ) expected_jitter += ( "constraint trp_link_jitter" + "\\[VNF" + l_o_j.get("cp_refs")[0] + ", VNF" + l_o_j.get("cp_refs")[1] + "\\] \\<= " + str(l_o_j.get("jitter")) + ";\n\n" ) res = re.findall(expected_latency + expected_jitter, mzn_model) self.assertEqual( 0, latency_or_jitter_was_found, "Jitter or latency was not found in the test input", ) self.assertEqual(1, len(res), "faulty model generated")