Enable black in tox.ini
[osm/PLA.git] / osm_pla / test / test_mznModelGenerator.py
1 # Copyright 2020 ArctosLabs Scandinavia AB
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12 # implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 import datetime
16 import logging
17
18 # import unittest
19 from unittest import TestCase
20
21 # import random
22 # from operator import itemgetter
23 import re
24
25 from jinja2 import Template
26
27 from osm_pla.placement.mznplacement import MznModelGenerator
28
29 test_ns_placement_data_str = {
30 "vim_accounts": [
31 "vim" + vim_account.replace("-", "_")
32 for vim_account in [
33 "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87",
34 "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87",
35 "cccccccc-ed84-4e49-b5df-a9d117bd731f",
36 "dddddddd-ed84-4e49-b5df-a9d117bd731f",
37 "eeeeeeee-38f5-438d-b8ee-3f93b3531f87",
38 ]
39 ],
40 "trp_link_latency": [
41 [0, 50, 100, 150, 200],
42 [0, 0, 100, 150, 200],
43 [0, 0, 0, 150, 200],
44 [0, 0, 0, 0, 200],
45 [0, 0, 0, 0, 0],
46 ],
47 "trp_link_jitter": [
48 [0, 5, 10, 15, 20],
49 [0, 0, 10, 15, 20],
50 [0, 0, 0, 15, 20],
51 [0, 0, 0, 0, 20],
52 [0, 0, 0, 0, 0],
53 ],
54 "trp_link_price_list": [
55 [0, 5, 6, 6, 7],
56 [0, 0, 6, 6, 7],
57 [0, 0, 0, 6, 7],
58 [0, 0, 0, 0, 7],
59 [0, 0, 0, 0, 0],
60 ],
61 "ns_desc": [
62 {"vnf_id": "one", "vnf_price_per_vim": [50, 51, 52, 53, 54]},
63 {"vnf_id": "two", "vnf_price_per_vim": [20, 21, 22, 23, 24]},
64 {"vnf_id": "three", "vnf_price_per_vim": [70, 71, 72, 73, 74]},
65 {"vnf_id": "four", "vnf_price_per_vim": [40, 41, 42, 43, 44]},
66 ],
67 "vld_desc": [
68 {"cp_refs": ["one", "two"], "latency": 150, "jitter": 30},
69 {"cp_refs": ["two", "three"], "latency": 140, "jitter": 30},
70 {"cp_refs": ["three", "four"], "latency": 130, "jitter": 30},
71 ],
72 "generator_data": {"file": __file__, "time": datetime.datetime.now()},
73 }
74
75 test_ns_placement_data_str_no_vld_constraints = {
76 "vim_accounts": [
77 "vim" + vim_account.replace("-", "_")
78 for vim_account in [
79 "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87",
80 "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87",
81 "cccccccc-ed84-4e49-b5df-a9d117bd731f",
82 "dddddddd-ed84-4e49-b5df-a9d117bd731f",
83 "eeeeeeee-38f5-438d-b8ee-3f93b3531f87",
84 ]
85 ],
86 "trp_link_latency": [
87 [0, 50, 100, 150, 200],
88 [0, 0, 100, 150, 200],
89 [0, 0, 0, 150, 200],
90 [0, 0, 0, 0, 200],
91 [0, 0, 0, 0, 0],
92 ],
93 "trp_link_jitter": [
94 [0, 5, 10, 15, 20],
95 [0, 0, 10, 15, 20],
96 [0, 0, 0, 15, 20],
97 [0, 0, 0, 0, 20],
98 [0, 0, 0, 0, 0],
99 ],
100 "trp_link_price_list": [
101 [0, 5, 6, 6, 7],
102 [0, 0, 6, 6, 7],
103 [0, 0, 0, 6, 7],
104 [0, 0, 0, 0, 7],
105 [0, 0, 0, 0, 0],
106 ],
107 "ns_desc": [
108 {"vnf_id": "one", "vnf_price_per_vim": [50, 51, 52, 53, 54]},
109 {"vnf_id": "two", "vnf_price_per_vim": [20, 21, 22, 23, 24]},
110 {"vnf_id": "three", "vnf_price_per_vim": [70, 71, 72, 73, 74]},
111 {"vnf_id": "four", "vnf_price_per_vim": [40, 41, 42, 43, 44]},
112 ],
113 "vld_desc": [
114 {"cp_refs": ["one", "two"]},
115 {"cp_refs": ["two", "three"]},
116 {"cp_refs": ["three", "four"]},
117 ],
118 "generator_data": {"file": __file__, "time": datetime.datetime.now()},
119 }
120
121 test_ns_placement_data = {
122 "vim_accounts": [
123 "vim" + vim_account.replace("-", "_")
124 for vim_account in [
125 "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87",
126 "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87",
127 "cccccccc-ed84-4e49-b5df-a9d117bd731f",
128 "dddddddd-ed84-4e49-b5df-a9d117bd731f",
129 "eeeeeeee-38f5-438d-b8ee-3f93b3531f87",
130 ]
131 ],
132 "trp_link_latency": [
133 [0, 50, 100, 150, 200],
134 [0, 0, 100, 150, 200],
135 [0, 0, 0, 150, 200],
136 [0, 0, 0, 0, 200],
137 [0, 0, 0, 0, 0],
138 ],
139 "trp_link_jitter": [
140 [0, 5, 10, 15, 20],
141 [0, 0, 10, 15, 20],
142 [0, 0, 0, 15, 20],
143 [0, 0, 0, 0, 20],
144 [0, 0, 0, 0, 0],
145 ],
146 "trp_link_price_list": [
147 [0, 5, 6, 6, 7],
148 [0, 0, 6, 6, 7],
149 [0, 0, 0, 6, 7],
150 [0, 0, 0, 0, 7],
151 [0, 0, 0, 0, 0],
152 ],
153 "ns_desc": [
154 {"vnf_id": "1", "vnf_price_per_vim": [50, 51, 52, 53, 54]},
155 {"vnf_id": "2", "vnf_price_per_vim": [20, 21, 22, 23, 24]},
156 {"vnf_id": "3", "vnf_price_per_vim": [70, 71, 72, 73, 74]},
157 {"vnf_id": "4", "vnf_price_per_vim": [40, 41, 42, 43, 44]},
158 ],
159 "vld_desc": [
160 {"cp_refs": ["1", "2"], "latency": 150, "jitter": 30},
161 {"cp_refs": ["2", "3"], "latency": 140, "jitter": 30},
162 {"cp_refs": ["3", "4"], "latency": 130, "jitter": 30},
163 ],
164 "generator_data": {"file": __file__, "time": datetime.datetime.now()},
165 }
166
167 test_ns_placement_data_w_pinning = {
168 "vim_accounts": [
169 "vim" + vim_account.replace("-", "_")
170 for vim_account in [
171 "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87",
172 "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87",
173 "cccccccc-ed84-4e49-b5df-a9d117bd731f",
174 "dddddddd-ed84-4e49-b5df-a9d117bd731f",
175 "eeeeeeee-38f5-438d-b8ee-3f93b3531f87",
176 ]
177 ],
178 "trp_link_latency": [
179 [0, 50, 100, 150, 200],
180 [0, 0, 100, 150, 200],
181 [0, 0, 0, 150, 200],
182 [0, 0, 0, 0, 200],
183 [0, 0, 0, 0, 0],
184 ],
185 "trp_link_jitter": [
186 [0, 5, 10, 15, 20],
187 [0, 0, 10, 15, 20],
188 [0, 0, 0, 15, 20],
189 [0, 0, 0, 0, 20],
190 [0, 0, 0, 0, 0],
191 ],
192 "trp_link_price_list": [
193 [0, 5, 6, 6, 7],
194 [0, 0, 6, 6, 7],
195 [0, 0, 0, 6, 7],
196 [0, 0, 0, 0, 7],
197 [0, 0, 0, 0, 0],
198 ],
199 "ns_desc": [
200 {"vnf_id": "1", "vnf_price_per_vim": [50, 51, 52, 53, 54]},
201 {
202 "vnf_id": "2",
203 "vnf_price_per_vim": [20, 21, 22, 23, 24],
204 "vim_account": "vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87",
205 },
206 {"vnf_id": "3", "vnf_price_per_vim": [70, 71, 72, 73, 74]},
207 {
208 "vnf_id": "4",
209 "vnf_price_per_vim": [40, 41, 42, 43, 44],
210 "vim_account": "vimcccccccc_ed84_4e49_b5df_a9d117bd731f",
211 },
212 ],
213 "vld_desc": [
214 {"cp_refs": ["1", "2"], "latency": 150, "jitter": 30},
215 {"cp_refs": ["2", "3"], "latency": 140, "jitter": 30},
216 {"cp_refs": ["3", "4"], "latency": 130, "jitter": 30},
217 ],
218 "generator_data": {"file": __file__, "time": datetime.datetime.now()},
219 }
220
221 test_ns_placement_data_w_pinning_str = {
222 "vim_accounts": [
223 "vim" + vim_account.replace("-", "_")
224 for vim_account in [
225 "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87",
226 "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87",
227 "cccccccc-ed84-4e49-b5df-a9d117bd731f",
228 "dddddddd-ed84-4e49-b5df-a9d117bd731f",
229 "eeeeeeee-38f5-438d-b8ee-3f93b3531f87",
230 ]
231 ],
232 "trp_link_latency": [
233 [0, 50, 100, 150, 200],
234 [0, 0, 100, 150, 200],
235 [0, 0, 0, 150, 200],
236 [0, 0, 0, 0, 200],
237 [0, 0, 0, 0, 0],
238 ],
239 "trp_link_jitter": [
240 [0, 5, 10, 15, 20],
241 [0, 0, 10, 15, 20],
242 [0, 0, 0, 15, 20],
243 [0, 0, 0, 0, 20],
244 [0, 0, 0, 0, 0],
245 ],
246 "trp_link_price_list": [
247 [0, 5, 6, 6, 7],
248 [0, 0, 6, 6, 7],
249 [0, 0, 0, 6, 7],
250 [0, 0, 0, 0, 7],
251 [0, 0, 0, 0, 0],
252 ],
253 "ns_desc": [
254 {"vnf_id": "one", "vnf_price_per_vim": [50, 51, 52, 53, 54]},
255 {
256 "vnf_id": "two",
257 "vnf_price_per_vim": [20, 21, 22, 23, 24],
258 "vim_account": "vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87",
259 },
260 {"vnf_id": "three", "vnf_price_per_vim": [70, 71, 72, 73, 74]},
261 {
262 "vnf_id": "four",
263 "vnf_price_per_vim": [40, 41, 42, 43, 44],
264 "vim_account": "vimcccccccc_ed84_4e49_b5df_a9d117bd731f",
265 },
266 ],
267 "vld_desc": [
268 {"cp_refs": ["one", "two"], "latency": 150, "jitter": 30},
269 {"cp_refs": ["two", "three"], "latency": 140, "jitter": 30},
270 {"cp_refs": ["three", "four"], "latency": 130, "jitter": 30},
271 ],
272 "generator_data": {"file": __file__, "time": datetime.datetime.now()},
273 }
274
275 test_ns_placement_data_str_no_vld = {
276 "vim_accounts": [
277 "vim" + vim_account.replace("-", "_")
278 for vim_account in [
279 "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87",
280 "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87",
281 "cccccccc-ed84-4e49-b5df-a9d117bd731f",
282 "dddddddd-ed84-4e49-b5df-a9d117bd731f",
283 "eeeeeeee-38f5-438d-b8ee-3f93b3531f87",
284 ]
285 ],
286 "trp_link_latency": [
287 [0, 50, 100, 150, 200],
288 [0, 0, 100, 150, 200],
289 [0, 0, 0, 150, 200],
290 [0, 0, 0, 0, 200],
291 [0, 0, 0, 0, 0],
292 ],
293 "trp_link_jitter": [
294 [0, 5, 10, 15, 20],
295 [0, 0, 10, 15, 20],
296 [0, 0, 0, 15, 20],
297 [0, 0, 0, 0, 20],
298 [0, 0, 0, 0, 0],
299 ],
300 "trp_link_price_list": [
301 [0, 5, 6, 6, 7],
302 [0, 0, 6, 6, 7],
303 [0, 0, 0, 6, 7],
304 [0, 0, 0, 0, 7],
305 [0, 0, 0, 0, 0],
306 ],
307 "ns_desc": [{"vnf_id": "one", "vnf_price_per_vim": [50, 51, 52, 53, 54]}],
308 "vld_desc": [],
309 "generator_data": {"file": __file__, "time": datetime.datetime.now()},
310 }
311
312 expected_model_fragment = """
313 %This is the NETWORK RESOURCE MODEL
314 enum Vims = {
315 vimaaaaaaaa_38f5_438d_b8ee_3f93b3531f87,
316 vimbbbbbbbb_38f5_438d_b8ee_3f93b3531f87,
317 vimcccccccc_ed84_4e49_b5df_a9d117bd731f,
318 vimdddddddd_ed84_4e49_b5df_a9d117bd731f,
319 vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87}; % The vim-accounts
320 array[Vims, Vims] of int: trp_link_latency = [|0,50,100,150,200,
321 |0,0,100,150,200,
322 |0,0,0,150,200,
323 |0,0,0,0,200,
324 |0,0,0,0,0,
325 |]; % Transport link latency between data centers
326 array[Vims, Vims] of int: trp_link_jitter = [|0,5,10,15,20,
327 |0,0,10,15,20,
328 |0,0,0,15,20,
329 |0,0,0,0,20,
330 |0,0,0,0,0,
331 |]; % Transport link jitter between data centers
332 array[Vims, Vims] of int: trp_link_price_list = [|0,5,6,6,7,
333 |0,0,6,6,7,
334 |0,0,0,6,7,
335 |0,0,0,0,7,
336 |0,0,0,0,0,
337 |]; % Transport link price list
338 array[Vims] of int: vim_price_list_1 = [50,51,52,53,54];
339 array[Vims] of int: vim_price_list_2 = [20,21,22,23,24];
340 array[Vims] of int: vim_price_list_3 = [70,71,72,73,74];
341 array[Vims] of int: vim_price_list_4 = [40,41,42,43,44];
342
343
344 % This is the NETWORK BASIC LOAD MODEL (CONSUMED)
345 % NOTE. This is not applicable in OSM Release 7
346
347 % This is the SERVICE CONSUMPTION MODEL
348 % These are the variables, i.e. which DC to select for each VNF
349 var Vims: VNF1;
350 var Vims: VNF2;
351 var Vims: VNF3;
352 var Vims: VNF4;
353
354
355 % These are the set of rules for selecting DCs to VNFs
356 constraint trp_link_latency[VNF1, VNF2] <= 150;
357 constraint trp_link_latency[VNF2, VNF3] <= 140;
358 constraint trp_link_latency[VNF3, VNF4] <= 130;
359 constraint trp_link_jitter[VNF1, VNF2] <= 30;
360 constraint trp_link_jitter[VNF2, VNF3] <= 30;
361 constraint trp_link_jitter[VNF3, VNF4] <= 30;
362
363 % Calculate the cost for VNFs and cost for transport link and total cost
364 var int: used_transport_cost =trp_link_price_list[VNF1, VNF2]+
365 trp_link_price_list[VNF2, VNF3]+
366 trp_link_price_list[VNF3, VNF4];
367
368 var int: used_vim_cost =vim_price_list_1[VNF1]+
369 vim_price_list_2[VNF2]+
370 vim_price_list_3[VNF3]+
371 vim_price_list_4[VNF4];
372
373 var int: total_cost = used_transport_cost + used_vim_cost;
374
375 solve minimize total_cost;
376 """
377 expected_model_fragment_str = """
378 %This is the NETWORK RESOURCE MODEL
379 enum Vims = {
380 vimaaaaaaaa_38f5_438d_b8ee_3f93b3531f87,
381 vimbbbbbbbb_38f5_438d_b8ee_3f93b3531f87,
382 vimcccccccc_ed84_4e49_b5df_a9d117bd731f,
383 vimdddddddd_ed84_4e49_b5df_a9d117bd731f,
384 vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87}; % The vim-accounts
385 array[Vims, Vims] of int: trp_link_latency = [|0,50,100,150,200,
386 |0,0,100,150,200,
387 |0,0,0,150,200,
388 |0,0,0,0,200,
389 |0,0,0,0,0,
390 |]; % Transport link latency between data centers
391 array[Vims, Vims] of int: trp_link_jitter = [|0,5,10,15,20,
392 |0,0,10,15,20,
393 |0,0,0,15,20,
394 |0,0,0,0,20,
395 |0,0,0,0,0,
396 |]; % Transport link jitter between data centers
397 array[Vims, Vims] of int: trp_link_price_list = [|0,5,6,6,7,
398 |0,0,6,6,7,
399 |0,0,0,6,7,
400 |0,0,0,0,7,
401 |0,0,0,0,0,
402 |]; % Transport link price list
403 array[Vims] of int: vim_price_list_one = [50,51,52,53,54];
404 array[Vims] of int: vim_price_list_two = [20,21,22,23,24];
405 array[Vims] of int: vim_price_list_three = [70,71,72,73,74];
406 array[Vims] of int: vim_price_list_four = [40,41,42,43,44];
407
408
409 % This is the NETWORK BASIC LOAD MODEL (CONSUMED)
410 % NOTE. This is not applicable in OSM Release 7
411
412 % This is the SERVICE CONSUMPTION MODEL
413 % These are the variables, i.e. which DC to select for each VNF
414 var Vims: VNFone;
415 var Vims: VNFtwo;
416 var Vims: VNFthree;
417 var Vims: VNFfour;
418
419
420 % These are the set of rules for selecting DCs to VNFs
421 constraint trp_link_latency[VNFone, VNFtwo] <= 150;
422 constraint trp_link_latency[VNFtwo, VNFthree] <= 140;
423 constraint trp_link_latency[VNFthree, VNFfour] <= 130;
424 constraint trp_link_jitter[VNFone, VNFtwo] <= 30;
425 constraint trp_link_jitter[VNFtwo, VNFthree] <= 30;
426 constraint trp_link_jitter[VNFthree, VNFfour] <= 30;
427
428 % Calculate the cost for VNFs and cost for transport link and total cost
429 var int: used_transport_cost =trp_link_price_list[VNFone, VNFtwo]+
430 trp_link_price_list[VNFtwo, VNFthree]+
431 trp_link_price_list[VNFthree, VNFfour];
432
433 var int: used_vim_cost =vim_price_list_one[VNFone]+
434 vim_price_list_two[VNFtwo]+
435 vim_price_list_three[VNFthree]+
436 vim_price_list_four[VNFfour];
437
438 var int: total_cost = used_transport_cost + used_vim_cost;
439
440 solve minimize total_cost;
441 """
442
443 expected_model_fragment_str_no_vld_constraints = """
444 %This is the NETWORK RESOURCE MODEL
445 enum Vims = {
446 vimaaaaaaaa_38f5_438d_b8ee_3f93b3531f87,
447 vimbbbbbbbb_38f5_438d_b8ee_3f93b3531f87,
448 vimcccccccc_ed84_4e49_b5df_a9d117bd731f,
449 vimdddddddd_ed84_4e49_b5df_a9d117bd731f,
450 vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87}; % The vim-accounts
451 array[Vims, Vims] of int: trp_link_latency = [|0,50,100,150,200,
452 |0,0,100,150,200,
453 |0,0,0,150,200,
454 |0,0,0,0,200,
455 |0,0,0,0,0,
456 |]; % Transport link latency between data centers
457 array[Vims, Vims] of int: trp_link_jitter = [|0,5,10,15,20,
458 |0,0,10,15,20,
459 |0,0,0,15,20,
460 |0,0,0,0,20,
461 |0,0,0,0,0,
462 |]; % Transport link jitter between data centers
463 array[Vims, Vims] of int: trp_link_price_list = [|0,5,6,6,7,
464 |0,0,6,6,7,
465 |0,0,0,6,7,
466 |0,0,0,0,7,
467 |0,0,0,0,0,
468 |]; % Transport link price list
469 array[Vims] of int: vim_price_list_one = [50,51,52,53,54];
470 array[Vims] of int: vim_price_list_two = [20,21,22,23,24];
471 array[Vims] of int: vim_price_list_three = [70,71,72,73,74];
472 array[Vims] of int: vim_price_list_four = [40,41,42,43,44];
473
474
475 % This is the NETWORK BASIC LOAD MODEL (CONSUMED)
476 % NOTE. This is not applicable in OSM Release 7
477
478 % This is the SERVICE CONSUMPTION MODEL
479 % These are the variables, i.e. which DC to select for each VNF
480 var Vims: VNFone;
481 var Vims: VNFtwo;
482 var Vims: VNFthree;
483 var Vims: VNFfour;
484
485
486 % These are the set of rules for selecting DCs to VNFs
487
488 % Calculate the cost for VNFs and cost for transport link and total cost
489 var int: used_transport_cost =trp_link_price_list[VNFone, VNFtwo]+
490 trp_link_price_list[VNFtwo, VNFthree]+
491 trp_link_price_list[VNFthree, VNFfour];
492
493 var int: used_vim_cost =vim_price_list_one[VNFone]+
494 vim_price_list_two[VNFtwo]+
495 vim_price_list_three[VNFthree]+
496 vim_price_list_four[VNFfour];
497
498 var int: total_cost = used_transport_cost + used_vim_cost;
499
500 solve minimize total_cost;
501 """
502
503 expected_model_fragment_w_pinning = """
504 %This is the NETWORK RESOURCE MODEL
505 enum Vims = {
506 vimaaaaaaaa_38f5_438d_b8ee_3f93b3531f87,
507 vimbbbbbbbb_38f5_438d_b8ee_3f93b3531f87,
508 vimcccccccc_ed84_4e49_b5df_a9d117bd731f,
509 vimdddddddd_ed84_4e49_b5df_a9d117bd731f,
510 vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87}; % The vim-accounts
511 array[Vims, Vims] of int: trp_link_latency = [|0,50,100,150,200,
512 |0,0,100,150,200,
513 |0,0,0,150,200,
514 |0,0,0,0,200,
515 |0,0,0,0,0,
516 |]; % Transport link latency between data centers
517 array[Vims, Vims] of int: trp_link_jitter = [|0,5,10,15,20,
518 |0,0,10,15,20,
519 |0,0,0,15,20,
520 |0,0,0,0,20,
521 |0,0,0,0,0,
522 |]; % Transport link jitter between data centers
523 array[Vims, Vims] of int: trp_link_price_list = [|0,5,6,6,7,
524 |0,0,6,6,7,
525 |0,0,0,6,7,
526 |0,0,0,0,7,
527 |0,0,0,0,0,
528 |]; % Transport link price list
529 array[Vims] of int: vim_price_list_1 = [50,51,52,53,54];
530 array[Vims] of int: vim_price_list_2 = [20,21,22,23,24];
531 array[Vims] of int: vim_price_list_3 = [70,71,72,73,74];
532 array[Vims] of int: vim_price_list_4 = [40,41,42,43,44];
533
534
535 % This is the NETWORK BASIC LOAD MODEL (CONSUMED)
536 % NOTE. This is not applicable in OSM Release 7
537
538 % This is the SERVICE CONSUMPTION MODEL
539 % These are the variables, i.e. which DC to select for each VNF
540 var Vims: VNF1;
541 Vims: VNF2 = vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87;
542 var Vims: VNF3;
543 Vims: VNF4 = vimcccccccc_ed84_4e49_b5df_a9d117bd731f;
544
545
546 % These are the set of rules for selecting DCs to VNFs
547 constraint trp_link_latency[VNF1, VNF2] <= 150;
548 constraint trp_link_latency[VNF2, VNF3] <= 140;
549 constraint trp_link_latency[VNF3, VNF4] <= 130;
550 constraint trp_link_jitter[VNF1, VNF2] <= 30;
551 constraint trp_link_jitter[VNF2, VNF3] <= 30;
552 constraint trp_link_jitter[VNF3, VNF4] <= 30;
553
554 % Calculate the cost for VNFs and cost for transport link and total cost
555 var int: used_transport_cost =trp_link_price_list[VNF1, VNF2]+
556 trp_link_price_list[VNF2, VNF3]+
557 trp_link_price_list[VNF3, VNF4];
558
559 var int: used_vim_cost =vim_price_list_1[VNF1]+
560 vim_price_list_2[VNF2]+
561 vim_price_list_3[VNF3]+
562 vim_price_list_4[VNF4];
563
564 var int: total_cost = used_transport_cost + used_vim_cost;
565
566 solve minimize total_cost;
567 """
568
569 expected_model_fragment_w_pinning_str = """
570 %This is the NETWORK RESOURCE MODEL
571 enum Vims = {
572 vimaaaaaaaa_38f5_438d_b8ee_3f93b3531f87,
573 vimbbbbbbbb_38f5_438d_b8ee_3f93b3531f87,
574 vimcccccccc_ed84_4e49_b5df_a9d117bd731f,
575 vimdddddddd_ed84_4e49_b5df_a9d117bd731f,
576 vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87}; % The vim-accounts
577 array[Vims, Vims] of int: trp_link_latency = [|0,50,100,150,200,
578 |0,0,100,150,200,
579 |0,0,0,150,200,
580 |0,0,0,0,200,
581 |0,0,0,0,0,
582 |]; % Transport link latency between data centers
583 array[Vims, Vims] of int: trp_link_jitter = [|0,5,10,15,20,
584 |0,0,10,15,20,
585 |0,0,0,15,20,
586 |0,0,0,0,20,
587 |0,0,0,0,0,
588 |]; % Transport link jitter between data centers
589 array[Vims, Vims] of int: trp_link_price_list = [|0,5,6,6,7,
590 |0,0,6,6,7,
591 |0,0,0,6,7,
592 |0,0,0,0,7,
593 |0,0,0,0,0,
594 |]; % Transport link price list
595 array[Vims] of int: vim_price_list_one = [50,51,52,53,54];
596 array[Vims] of int: vim_price_list_two = [20,21,22,23,24];
597 array[Vims] of int: vim_price_list_three = [70,71,72,73,74];
598 array[Vims] of int: vim_price_list_four = [40,41,42,43,44];
599
600
601 % This is the NETWORK BASIC LOAD MODEL (CONSUMED)
602 % NOTE. This is not applicable in OSM Release 7
603
604 % This is the SERVICE CONSUMPTION MODEL
605 % These are the variables, i.e. which DC to select for each VNF
606 var Vims: VNFone;
607 Vims: VNFtwo = vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87;
608 var Vims: VNFthree;
609 Vims: VNFfour = vimcccccccc_ed84_4e49_b5df_a9d117bd731f;
610
611
612 % These are the set of rules for selecting DCs to VNFs
613 constraint trp_link_latency[VNFone, VNFtwo] <= 150;
614 constraint trp_link_latency[VNFtwo, VNFthree] <= 140;
615 constraint trp_link_latency[VNFthree, VNFfour] <= 130;
616 constraint trp_link_jitter[VNFone, VNFtwo] <= 30;
617 constraint trp_link_jitter[VNFtwo, VNFthree] <= 30;
618 constraint trp_link_jitter[VNFthree, VNFfour] <= 30;
619
620 % Calculate the cost for VNFs and cost for transport link and total cost
621 var int: used_transport_cost =trp_link_price_list[VNFone, VNFtwo]+
622 trp_link_price_list[VNFtwo, VNFthree]+
623 trp_link_price_list[VNFthree, VNFfour];
624
625 var int: used_vim_cost =vim_price_list_one[VNFone]+
626 vim_price_list_two[VNFtwo]+
627 vim_price_list_three[VNFthree]+
628 vim_price_list_four[VNFfour];
629
630 var int: total_cost = used_transport_cost + used_vim_cost;
631
632 solve minimize total_cost;
633 """
634
635 expected_model_fragment_str_no_vld = """
636 %This is the NETWORK RESOURCE MODEL
637 enum Vims = {
638 vimaaaaaaaa_38f5_438d_b8ee_3f93b3531f87,
639 vimbbbbbbbb_38f5_438d_b8ee_3f93b3531f87,
640 vimcccccccc_ed84_4e49_b5df_a9d117bd731f,
641 vimdddddddd_ed84_4e49_b5df_a9d117bd731f,
642 vimeeeeeeee_38f5_438d_b8ee_3f93b3531f87}; % The vim-accounts
643 array[Vims, Vims] of int: trp_link_latency = [|0,50,100,150,200,
644 |0,0,100,150,200,
645 |0,0,0,150,200,
646 |0,0,0,0,200,
647 |0,0,0,0,0,
648 |]; % Transport link latency between data centers
649 array[Vims, Vims] of int: trp_link_jitter = [|0,5,10,15,20,
650 |0,0,10,15,20,
651 |0,0,0,15,20,
652 |0,0,0,0,20,
653 |0,0,0,0,0,
654 |]; % Transport link jitter between data centers
655 array[Vims, Vims] of int: trp_link_price_list = [|0,5,6,6,7,
656 |0,0,6,6,7,
657 |0,0,0,6,7,
658 |0,0,0,0,7,
659 |0,0,0,0,0,
660 |]; % Transport link price list
661 array[Vims] of int: vim_price_list_one = [50,51,52,53,54];
662
663
664 % This is the NETWORK BASIC LOAD MODEL (CONSUMED)
665 % NOTE. This is not applicable in OSM Release 7
666
667 % This is the SERVICE CONSUMPTION MODEL
668 % These are the variables, i.e. which DC to select for each VNF
669
670 var Vims: VNFone;
671
672 % These are the set of rules for selecting DCs to VNFs
673
674 % Calculate the cost for VNFs and cost for transport link and total cost
675 var int: used_transport_cost =0;
676
677 var int: used_vim_cost =vim_price_list_one[VNFone];
678
679 var int: total_cost = used_transport_cost + used_vim_cost;
680
681 solve minimize total_cost;
682 """
683
684
685 class TestMznModelGenerator(TestCase):
686 def test_create_model(self):
687 mg = MznModelGenerator(logging.getLogger(__name__))
688 mzn_model = mg.create_model(test_ns_placement_data_str)
689
690 # so asserting exact content is difficult due to the datetime.now(), therefore we ignore the first lines
691 self.assertTrue(
692 expected_model_fragment_str.replace("\n", "")
693 in mzn_model.replace("\n", ""),
694 "faulty model generated",
695 )
696
697 def test_create_model_no_vld_constraints(self):
698 """
699 instantiate w/o constraints in nsd or order params has a valid model
700 :return:
701 """
702 mg = MznModelGenerator(logging.getLogger(__name__))
703 mzn_model = mg.create_model(test_ns_placement_data_str_no_vld_constraints)
704
705 # so asserting exact content is difficult due to the datetime.now(), therefore we ignore the first lines
706 self.assertTrue(
707 expected_model_fragment_str_no_vld_constraints.replace("\n", "")
708 in mzn_model.replace("\n", ""),
709 "faulty model generated",
710 )
711
712 def test_create_model_w_pinning(self):
713 mg = MznModelGenerator(logging.getLogger(__name__))
714 mzn_model = mg.create_model(test_ns_placement_data_w_pinning_str)
715
716 # so asserting exact content is difficult due to the datetime.now(), therefore we ignore the first lines
717 self.assertTrue(
718 expected_model_fragment_w_pinning_str.replace("\n", "")
719 in mzn_model.replace("\n", ""),
720 "faulty model generated",
721 )
722
723 def test_create_model_no_vld(self):
724 mg = MznModelGenerator(logging.getLogger(__name__))
725 mzn_model = mg.create_model(test_ns_placement_data_str_no_vld)
726
727 # so asserting exact content is difficult due to the datetime.now(), therefore we ignore the first lines
728 self.assertTrue(
729 expected_model_fragment_str_no_vld.replace("\n", "")
730 in mzn_model.replace("\n", ""),
731 "faulty model generated",
732 )
733
734 def test__load_jinja_template(self):
735 """
736
737 add other test to check exception if template not loaded (e.g. invalid template name,
738 perhaps also valid name but invalid content (in case jinja2 detects such things))
739 """
740 mg = MznModelGenerator(logging.getLogger(__name__))
741 template = mg._load_jinja_template() # Note we use the default template
742 self.assertTrue(
743 isinstance(template, Template), "failed to load jinja2 template"
744 )
745
746 def test_vim_account_replace(self):
747 mg = MznModelGenerator(logging.getLogger(__name__))
748 nspd = test_ns_placement_data_str
749 mzn_model = mg.create_model(nspd)
750
751 expected = (
752 "%This is the NETWORK RESOURCE MODEL" + "\n" + "enum Vims = {" + "\n"
753 )
754 for val in test_ns_placement_data_str["vim_accounts"]:
755 expected = expected + val.replace("-", "_") + ",\n"
756 expected = expected[:-2] + "}; % The vim-accounts"
757 res = re.findall(expected, mzn_model)
758 self.assertEqual(1, len(res), "vim accounts didnt replace from - to _")
759
760 def test_trp_link_price_list(self):
761 mg = MznModelGenerator(logging.getLogger(__name__))
762 mzn_model = mg.create_model(test_ns_placement_data_str)
763
764 expected = "array\\[Vims, Vims\\] of int: trp_link_price_list = \\["
765 for price_list in test_ns_placement_data_str["trp_link_price_list"]:
766 expected = (
767 expected + "\\|" + (str(price_list)[1:-1]).replace(" ", "") + ",\n"
768 )
769 expected = expected + "\\|\\]; % Transport link price list"
770 res = re.findall(expected, mzn_model)
771 self.assertEqual(1, len(res), "price list is not correct")
772
773 def test_link_latency(self):
774 mg = MznModelGenerator(logging.getLogger(__name__))
775 mzn_model = mg.create_model(test_ns_placement_data_str)
776
777 expected = "array\\[Vims, Vims\\] of int: trp_link_latency = \\["
778 for link_latency in test_ns_placement_data_str["trp_link_latency"]:
779 expected = (
780 expected + "\\|" + (str(link_latency)[1:-1]).replace(" ", "") + ",\n"
781 )
782 expected = expected + "\\|\\]; % Transport link latency between data centers"
783 res = re.findall(expected, mzn_model)
784 self.assertEqual(1, len(res), "trp_link_latency values is not correct")
785
786 def test_link_jitter(self):
787 mg = MznModelGenerator(logging.getLogger(__name__))
788 mzn_model = mg.create_model(test_ns_placement_data_str)
789
790 expected = "array\\[Vims, Vims\\] of int: trp_link_jitter = \\["
791 for link_jitter in test_ns_placement_data_str["trp_link_jitter"]:
792 expected = (
793 expected + "\\|" + (str(link_jitter)[1:-1]).replace(" ", "") + ",\n"
794 )
795 expected = expected + "\\|\\]; % Transport link jitter between data centers"
796
797 res = re.findall(expected, mzn_model)
798
799 self.assertEqual(1, len(res), "trp_link_jitter values is not correct")
800
801 def test_price_per_vim(self):
802 mg = MznModelGenerator(logging.getLogger(__name__))
803 mzn_model = mg.create_model(test_ns_placement_data_w_pinning_str)
804
805 expected = ""
806 for price_list in test_ns_placement_data_w_pinning_str["ns_desc"]:
807 expected += (
808 "array\\[Vims\\] of int: vim_price_list_"
809 + price_list.get("vnf_id")
810 + " = "
811 )
812 temp = str(price_list.get("vnf_price_per_vim"))[1:-1].replace(" ", "")
813 expected += "\\[" + temp + "\\];\n"
814
815 res = re.findall(expected, mzn_model)
816 self.assertEqual(1, len(res), "mzn_model contains pinning")
817
818 def test_pinning(self):
819 mg = MznModelGenerator(logging.getLogger(__name__))
820 mzn_model = mg.create_model(test_ns_placement_data_str)
821
822 expected = ""
823 for pin_list in test_ns_placement_data_str["ns_desc"]:
824 if pin_list.get("vim_account"):
825 expected += (
826 "Vims: VNF"
827 + pin_list.get("vnf_id")
828 + " = "
829 + pin_list.get("vim_account")
830 + ";\n"
831 )
832 else:
833 expected += "var Vims: VNF" + pin_list.get("vnf_id") + ";\n"
834
835 res = re.findall(expected, mzn_model)
836 self.assertEqual(1, len(res), "mzn_model has no pinning")
837
838 def test__without_pinning(self):
839 mg = MznModelGenerator(logging.getLogger(__name__))
840 mzn_model = mg.create_model(test_ns_placement_data_w_pinning_str)
841
842 expected = ""
843 for pin_list in test_ns_placement_data_w_pinning_str["ns_desc"]:
844 if pin_list.get("vim_account"):
845 expected += (
846 "Vims: VNF"
847 + pin_list.get("vnf_id")
848 + " = "
849 + pin_list.get("vim_account")
850 + ";\n"
851 )
852 else:
853 expected += "var Vims: VNF" + pin_list.get("vnf_id") + ";\n"
854
855 res = re.findall(expected, mzn_model)
856 self.assertEqual(1, len(res), "mzn_model contains pinning")
857
858 def test__without_constraints_for_jitter_and_latency(self):
859 mg = MznModelGenerator(logging.getLogger(__name__))
860 mzn_model = mg.create_model(test_ns_placement_data_str_no_vld_constraints)
861
862 expected_latency = "constraint trp_link_latency"
863 expected_jitter = "constraint trp_link_jitter"
864 latency_or_jitter_was_found = 0
865 for l_o_j in test_ns_placement_data_str_no_vld_constraints["vld_desc"]:
866 if l_o_j.get("latency") or l_o_j.get("jitter"):
867 latency_or_jitter_was_found = 1
868
869 res_latency = re.findall(expected_latency, mzn_model)
870 res_jitter = re.findall(expected_jitter, mzn_model)
871 self.assertEqual(
872 0,
873 latency_or_jitter_was_found,
874 "Jitter or latency was found in the test input",
875 )
876 self.assertEqual(
877 0, len(res_latency), "constraint trp_link_latency was found in mzn_model"
878 )
879 self.assertEqual(
880 0, len(res_jitter), "constraint trp_link_latency was found in mzn_model"
881 )
882
883 def test__constraints_for_jitter_and_latency(self):
884 mg = MznModelGenerator(logging.getLogger(__name__))
885 mzn_model = mg.create_model(test_ns_placement_data_str)
886
887 expected_latency = ""
888 expected_jitter = ""
889 latency_or_jitter_was_found = 0
890 for l_o_j in test_ns_placement_data_str["vld_desc"]:
891 if not (l_o_j.get("latency") or l_o_j.get("jitter")):
892 latency_or_jitter_was_found = 1
893 expected_latency += (
894 "constraint trp_link_latency"
895 + "\\[VNF"
896 + l_o_j.get("cp_refs")[0]
897 + ", VNF"
898 + l_o_j.get("cp_refs")[1]
899 + "\\] \\<= "
900 + str(l_o_j.get("latency"))
901 + ";\n\n"
902 )
903
904 expected_jitter += (
905 "constraint trp_link_jitter"
906 + "\\[VNF"
907 + l_o_j.get("cp_refs")[0]
908 + ", VNF"
909 + l_o_j.get("cp_refs")[1]
910 + "\\] \\<= "
911 + str(l_o_j.get("jitter"))
912 + ";\n\n"
913 )
914
915 res = re.findall(expected_latency + expected_jitter, mzn_model)
916 self.assertEqual(
917 0,
918 latency_or_jitter_was_found,
919 "Jitter or latency was not found in the test input",
920 )
921 self.assertEqual(1, len(res), "faulty model generated")