| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 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 platform |
| 17 | import itertools |
| 18 | |
| 19 | import pymzn |
| 20 | from jinja2 import Environment |
| magnussonl | de4f782 | 2020-07-09 16:30:41 +0200 | [diff] [blame] | 21 | from jinja2.loaders import FileSystemLoader, PackageLoader, ChoiceLoader |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 22 | |
| 23 | |
| 24 | class MznPlacementConductor(object): |
| 25 | """ |
| 26 | Knows how to process placement req using minizinc |
| 27 | """ |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 28 | |
| 29 | if platform.system() == "Windows": |
| 30 | default_mzn_path = "C:\\Program Files\\MiniZinc IDE (bundled)\\minizinc.exe" |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 31 | else: |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 32 | default_mzn_path = "/minizinc/bin/minizinc" |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 33 | |
| 34 | def __init__(self, log, mzn_path=default_mzn_path): |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 35 | pymzn.config["minizinc"] = mzn_path |
| 36 | self.log = ( |
| 37 | log # FIXME what to log (besides forwarding it to MznModelGenerator) here? |
| 38 | ) |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 39 | |
| 40 | def _run_placement_model(self, mzn_model, ns_desc, mzn_model_data={}): |
| 41 | """ |
| 42 | Runs the minizinc placement model and post process the result |
| 43 | Note: in this revision we use the 'item' output mode from pymzn.minizinc since it ease |
| 44 | post processing of the solutions when we use enumerations in mzn_model |
| 45 | Note: minizinc does not support '-' in identifiers and therefore we convert back from use of '_' when we |
| 46 | process the result |
| 47 | Note: minizinc does not support identifiers starting with numbers and therefore we skip the leading 'vim_' |
| 48 | when we process the result |
| 49 | |
| 50 | :param mzn_model: a minizinc model as str (note: may also be path to .mzn file) |
| 51 | :param ns_desc: network service descriptor, carries information about pinned VNFs so those can be included in |
| 52 | the result |
| 53 | :param mzn_model_data: minizinc model data dictionary (typically not used with our models) |
| 54 | :return: list of dicts formatted as {'vimAccountId': '<account id>', 'member-vnf-index': <'index'>} |
| 55 | or formatted as [{}] if unsatisfiable model |
| 56 | """ |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 57 | solns = pymzn.minizinc(mzn_model, data=mzn_model_data, output_mode="item") |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 58 | |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 59 | if "UNSATISFIABLE" in str(solns): |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 60 | return [{}] |
| 61 | |
| 62 | solns_as_str = str(solns[0]) |
| 63 | |
| 64 | # make it easier to extract the desired information by cleaning from newline, whitespace etc. |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 65 | solns_as_str = solns_as_str.replace("\n", "").replace(" ", "").rstrip(";") |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 66 | |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 67 | vnf_vim_mapping = (e.split("=") for e in solns_as_str.split(";")) |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 68 | |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 69 | res = [ |
| 70 | {"vimAccountId": e[1][3:].replace("_", "-"), "member-vnf-index": e[0][3:]} |
| 71 | for e in vnf_vim_mapping |
| 72 | ] |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 73 | # add any pinned VNFs |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 74 | pinned = [ |
| 75 | { |
| 76 | "vimAccountId": e["vim_account"][3:].replace("_", "-"), |
| 77 | "member-vnf-index": e["vnf_id"], |
| 78 | } |
| 79 | for e in ns_desc |
| 80 | if "vim_account" in e.keys() |
| 81 | ] |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 82 | |
| 83 | return res + pinned |
| 84 | |
| 85 | def do_placement_computation(self, nspd): |
| 86 | """ |
| 87 | Orchestrates the placement computation |
| 88 | |
| 89 | :param nspd: placement data |
| 90 | :return: see _run_placement_model |
| 91 | """ |
| 92 | mzn_model = MznModelGenerator(self.log).create_model(nspd) |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 93 | return self._run_placement_model(mzn_model, nspd["ns_desc"]) |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 94 | |
| 95 | |
| 96 | class MznModelGenerator(object): |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 97 | """ |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 98 | Has the capability to generate minizinc models from information contained in |
| 99 | NsPlacementData objects. Uses jinja2 as templating language for the model |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 100 | """ |
| 101 | |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 102 | default_j2_template = "osm_pla_dynamic_template.j2" |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 103 | template_search_path = [ |
| 104 | "osm_pla/placement", |
| 105 | "../placement", |
| 106 | "/pla/osm_pla/placement", |
| 107 | "./", |
| 108 | "/usr/lib/python3/dist-packages/osm_pla/placement", |
| 109 | ] |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 110 | |
| 111 | def __init__(self, log): |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 112 | """ |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 113 | Constructor |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 114 | """ |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 115 | self.log = log # FIXME we do not log anything so far |
| 116 | |
| 117 | def create_model(self, ns_placement_data): |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 118 | """ |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 119 | Creates a minizinc model according to the content of nspd |
| 120 | nspd - NSPlacementData |
| 121 | return MZNModel |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 122 | """ |
| 123 | self.log.info("ns_desc: {}".format(ns_placement_data["ns_desc"])) |
| 124 | self.log.info("vld_desc: {}".format(ns_placement_data["vld_desc"])) |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 125 | mzn_model_template = self._load_jinja_template() |
| 126 | mzn_model = mzn_model_template.render(ns_placement_data) |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 127 | self.log.info("Minizinc model: {}".format(mzn_model)) |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 128 | return mzn_model |
| 129 | |
| 130 | def _load_jinja_template(self, template_name=default_j2_template): |
| 131 | """loads the jinja template used for model generation""" |
| magnussonl | de4f782 | 2020-07-09 16:30:41 +0200 | [diff] [blame] | 132 | loader1 = FileSystemLoader(MznModelGenerator.template_search_path) |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 133 | loader2 = PackageLoader("osm_pla", ".") |
| Dario Faccin | 0d0e80f | 2023-05-24 16:58:47 +0200 | [diff] [blame] | 134 | env = Environment(loader=ChoiceLoader([loader1, loader2]), autoescape=True) |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 135 | return env.get_template(template_name) |
| 136 | |
| 137 | |
| 138 | class NsPlacementDataFactory(object): |
| 139 | """ |
| 140 | process information an network service and applicable network infrastructure resources in order to produce |
| 141 | information tailored for the minizinc model code generator |
| 142 | """ |
| 143 | |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 144 | def __init__( |
| 145 | self, |
| 146 | vim_accounts_info, |
| 147 | vnf_prices, |
| 148 | nsd, |
| 149 | pil_info, |
| 150 | pinning=None, |
| 151 | order_constraints=None, |
| 152 | ): |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 153 | """ |
| 154 | :param vim_accounts_info: a dictionary with vim url as key and id as value, we add a unique index to it for use |
| 155 | in the mzn array constructs and adjust the value of the id to minizinc acceptable identifier syntax |
| 156 | :param vnf_prices: a dictionary with 'vnfd-id-ref' as key and a dictionary with vim_urls: cost as value |
| 157 | :param nsd: the network service descriptor |
| 158 | :param pil_info: price list and metrics for PoP interconnection links |
| 159 | :param pinning: list of {'member-vnf-index': '<idx>', 'vim_account': '<vim-account>'} |
| 160 | :param order_constraints: any constraints provided at instantiation time |
| 161 | """ |
| 162 | next_idx = itertools.count() |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 163 | self._vim_accounts_info = { |
| 164 | k: {"id": "vim" + v.replace("-", "_"), "idx": next(next_idx)} |
| 165 | for k, v in vim_accounts_info.items() |
| 166 | } |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 167 | self._vnf_prices = vnf_prices |
| 168 | self._nsd = nsd |
| 169 | self._pil_info = pil_info |
| 170 | self._pinning = pinning |
| 171 | self._order_constraints = order_constraints |
| 172 | |
| 173 | def _produce_trp_link_characteristics_data(self, characteristics): |
| 174 | """ |
| 175 | :param characteristics: one of {pil_latency, pil_price, pil_jitter} |
| 176 | :return: 2d array of requested trp_link characteristics data |
| 177 | """ |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 178 | if characteristics not in {"pil_latency", "pil_price", "pil_jitter"}: |
| 179 | raise Exception("characteristic '{}' not supported".format(characteristics)) |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 180 | num_vims = len(self._vim_accounts_info) |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 181 | trp_link_characteristics = [ |
| 182 | [0 if col == row else 0x7FFF for col in range(num_vims)] |
| 183 | for row in range(num_vims) |
| 184 | ] |
| 185 | for pil in self._pil_info["pil"]: |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 186 | if characteristics in pil.keys(): |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 187 | ep1 = pil["pil_endpoints"][0] |
| 188 | ep2 = pil["pil_endpoints"][1] |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 189 | # only consider links between applicable vims |
| magnussonl | d8c1b39 | 2020-06-30 16:48:08 +0200 | [diff] [blame] | 190 | if ep1 in self._vim_accounts_info and ep2 in self._vim_accounts_info: |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 191 | idx1 = self._vim_accounts_info[ep1]["idx"] |
| 192 | idx2 = self._vim_accounts_info[ep2]["idx"] |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 193 | trp_link_characteristics[idx1][idx2] = pil[characteristics] |
| 194 | trp_link_characteristics[idx2][idx1] = pil[characteristics] |
| 195 | |
| 196 | return trp_link_characteristics |
| 197 | |
| garciaale | b2b0a44 | 2021-01-08 14:59:23 -0300 | [diff] [blame] | 198 | # TODO: Review if we should adapt this method with SOL006 /nsd/vnfd/int-virtual-link-desc/df/qos fields. |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 199 | def _produce_vld_desc(self): |
| 200 | """ |
| 201 | Creates the expected vlds from the nsd. Includes constraints if part of nsd. |
| 202 | Overrides constraints with any syntactically correct instantiation parameters |
| 203 | :return: |
| 204 | """ |
| garciaale | b2b0a44 | 2021-01-08 14:59:23 -0300 | [diff] [blame] | 205 | |
| 206 | all_vld_member_vnf_index_refs = {} |
| 207 | # TODO: Change for multiple DF support |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 208 | ns_df = self._nsd.get("df", [{}])[0] |
| 209 | for vnf_profile in ns_df.get("vnf-profile", []): |
| 210 | for vlc in vnf_profile.get("virtual-link-connectivity", []): |
| 211 | vld_id = vlc.get("virtual-link-profile-id") |
| 212 | vld_member_vnf_index_ref = vnf_profile.get("id") |
| garciaale | b2b0a44 | 2021-01-08 14:59:23 -0300 | [diff] [blame] | 213 | if vld_id in all_vld_member_vnf_index_refs: |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 214 | all_vld_member_vnf_index_refs[vld_id].append( |
| 215 | vld_member_vnf_index_ref |
| 216 | ) |
| garciaale | b2b0a44 | 2021-01-08 14:59:23 -0300 | [diff] [blame] | 217 | else: |
| 218 | all_vld_member_vnf_index_refs[vld_id] = [vld_member_vnf_index_ref] |
| 219 | |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 220 | vld_desc = [] |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 221 | for vld in self._nsd.get("virtual-link-desc", ()): |
| 222 | if vld.get("mgmt-network", False) is True: |
| garciaale | b2b0a44 | 2021-01-08 14:59:23 -0300 | [diff] [blame] | 223 | continue |
| 224 | vld_desc_entry = {} |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 225 | cp_refs = all_vld_member_vnf_index_refs[vld.get("id")] |
| garciaale | b2b0a44 | 2021-01-08 14:59:23 -0300 | [diff] [blame] | 226 | if len(cp_refs) == 2: |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 227 | vld_desc_entry["cp_refs"] = cp_refs |
| garciaale | b2b0a44 | 2021-01-08 14:59:23 -0300 | [diff] [blame] | 228 | # TODO: Change for multiple DF support |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 229 | vld_df = vld.get("df", [{}])[0] |
| 230 | for constraint in vld_df.get("qos", {}): |
| 231 | if constraint == "latency": |
| 232 | vld_desc_entry["latency"] = vld_df["qos"][constraint] |
| 233 | elif constraint == "packet-delay-variation": |
| 234 | vld_desc_entry["jitter"] = vld_df["qos"][constraint] |
| garciaale | b2b0a44 | 2021-01-08 14:59:23 -0300 | [diff] [blame] | 235 | vld_desc.append(vld_desc_entry) |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 236 | |
| 237 | # create candidates from instantiate params |
| 238 | if self._order_constraints is not None: |
| 239 | candidate_vld_desc = [] |
| 240 | # use id to find the endpoints in the nsd |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 241 | for entry in self._order_constraints.get("vld-constraints"): |
| 242 | for vld in self._nsd.get("virtual-link-desc", ()): |
| 243 | if entry["id"] == vld.get("id"): |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 244 | vld_desc_instantiate_entry = {} |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 245 | cp_refs = all_vld_member_vnf_index_refs[vld.get("id")] |
| 246 | vld_desc_instantiate_entry["cp_refs"] = cp_refs |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 247 | # add whatever constraints that are provided to the vld_desc_entry |
| 248 | # misspelled 'link-constraints' => empty dict |
| 249 | # lack (or misspelling) of one or both supported constraints => entry not appended |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 250 | for constraint, value in entry.get( |
| 251 | "link-constraints", {} |
| 252 | ).items(): |
| 253 | if constraint == "latency": |
| 254 | vld_desc_instantiate_entry["latency"] = value |
| 255 | elif constraint == "jitter": |
| 256 | vld_desc_instantiate_entry["jitter"] = value |
| 257 | if {"latency", "jitter"}.intersection( |
| 258 | vld_desc_instantiate_entry.keys() |
| 259 | ): |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 260 | candidate_vld_desc.append(vld_desc_instantiate_entry) |
| 261 | # merge with nsd originated, FIXME log any deviations? |
| 262 | for vld_d in vld_desc: |
| 263 | for vld_d_i in candidate_vld_desc: |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 264 | if set(vld_d["cp_refs"]) == set(vld_d_i["cp_refs"]): |
| 265 | if vld_d_i.get("jitter"): |
| 266 | vld_d["jitter"] = vld_d_i["jitter"] |
| 267 | if vld_d_i.get("latency"): |
| 268 | vld_d["latency"] = vld_d_i["latency"] |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 269 | |
| 270 | return vld_desc |
| 271 | |
| 272 | def _produce_ns_desc(self): |
| 273 | """ |
| 274 | collect information for the ns_desc part of the placement data |
| 275 | for the vim_accounts that are applicable, collect the vnf_price |
| 276 | """ |
| 277 | ns_desc = [] |
| garciaale | b2b0a44 | 2021-01-08 14:59:23 -0300 | [diff] [blame] | 278 | # TODO: Change for multiple DF support |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 279 | ns_df = self._nsd.get("df", [{}])[0] |
| 280 | for vnf_profile in ns_df.get("vnf-profile", []): |
| 281 | vnf_info = {"vnf_id": vnf_profile["id"]} |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 282 | # prices |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 283 | prices_for_vnfd = self._vnf_prices[vnf_profile["vnfd-id"]] |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 284 | # the list of prices must be ordered according to the indexing of the vim_accounts |
| 285 | price_list = [_ for _ in range(len(self._vim_accounts_info))] |
| 286 | for k in prices_for_vnfd.keys(): |
| 287 | if k in self._vim_accounts_info.keys(): |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 288 | price_list[self._vim_accounts_info[k]["idx"]] = prices_for_vnfd[k] |
| 289 | vnf_info["vnf_price_per_vim"] = price_list |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 290 | |
| 291 | # pinning to dc |
| 292 | if self._pinning is not None: |
| 293 | for pinned_vnf in self._pinning: |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 294 | if vnf_profile["id"] == pinned_vnf["member-vnf-index"]: |
| 295 | vnf_info["vim_account"] = "vim" + pinned_vnf[ |
| 296 | "vimAccountId" |
| 297 | ].replace("-", "_") |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 298 | |
| 299 | ns_desc.append(vnf_info) |
| 300 | return ns_desc |
| 301 | |
| 302 | def create_ns_placement_data(self): |
| garciadeblas | 20fc3b7 | 2022-11-14 00:48:32 +0100 | [diff] [blame] | 303 | """populate NsPlacmentData object""" |
| 304 | ns_placement_data = { |
| 305 | "vim_accounts": [ |
| 306 | vim_data["id"] |
| 307 | for _, vim_data in sorted( |
| 308 | self._vim_accounts_info.items(), key=lambda item: item[1]["idx"] |
| 309 | ) |
| 310 | ], |
| 311 | "trp_link_latency": self._produce_trp_link_characteristics_data( |
| 312 | "pil_latency" |
| 313 | ), |
| 314 | "trp_link_jitter": self._produce_trp_link_characteristics_data( |
| 315 | "pil_jitter" |
| 316 | ), |
| 317 | "trp_link_price_list": self._produce_trp_link_characteristics_data( |
| 318 | "pil_price" |
| 319 | ), |
| 320 | "ns_desc": self._produce_ns_desc(), |
| 321 | "vld_desc": self._produce_vld_desc(), |
| 322 | "generator_data": {"file": __file__, "time": datetime.datetime.now()}, |
| 323 | } |
| magnussonl | 2b0e2d7 | 2020-02-04 10:52:46 +0100 | [diff] [blame] | 324 | |
| 325 | return ns_placement_data |