X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=NG-RO%2Fosm_ng_ro%2Fns.py;h=6ad5368fd6073012332b3a9838b8952f35b925a4;hb=45cb01768d4b1c77a6311b45c48c7bf2abc32d5b;hp=ee0463a4db662f802e9c21030e72c4ebd0fe2023;hpb=a9fc6189122a4f95e8efebb70e36eb46f3613de3;p=osm%2FRO.git diff --git a/NG-RO/osm_ng_ro/ns.py b/NG-RO/osm_ng_ro/ns.py index ee0463a4..6ad5368f 100644 --- a/NG-RO/osm_ng_ro/ns.py +++ b/NG-RO/osm_ng_ro/ns.py @@ -16,38 +16,39 @@ # limitations under the License. ## -# import yaml +from http import HTTPStatus import logging +from random import choice as random_choice +from threading import Lock +from time import time from traceback import format_exc as traceback_format_exc -from osm_ng_ro.ns_thread import NsWorker, NsWorkerException, deep_get -from osm_ng_ro.validation import validate_input, deploy_schema +from uuid import uuid4 + +from cryptography.hazmat.backends import default_backend as crypto_default_backend +from cryptography.hazmat.primitives import serialization as crypto_serialization +from cryptography.hazmat.primitives.asymmetric import rsa +from jinja2 import ( + Environment, + select_autoescape, + StrictUndefined, + TemplateError, + TemplateNotFound, + UndefinedError, +) from osm_common import ( - dbmongo, dbmemory, + dbmongo, fslocal, fsmongo, - msglocal, msgkafka, + msglocal, version as common_version, ) from osm_common.dbbase import DbException from osm_common.fsbase import FsException from osm_common.msgbase import MsgException -from http import HTTPStatus -from uuid import uuid4 -from threading import Lock -from random import choice as random_choice -from time import time -from jinja2 import ( - Environment, - TemplateError, - TemplateNotFound, - StrictUndefined, - UndefinedError, -) -from cryptography.hazmat.primitives import serialization as crypto_serialization -from cryptography.hazmat.primitives.asymmetric import rsa -from cryptography.hazmat.backends import default_backend as crypto_default_backend +from osm_ng_ro.ns_thread import deep_get, NsWorker, NsWorkerException +from osm_ng_ro.validation import deploy_schema, validate_input __author__ = "Alfonso Tierno " min_common_version = "0.1.16" @@ -74,8 +75,8 @@ def get_process_id(): if text_id: return text_id - except Exception: - pass + except Exception as error: + logging.exception(f"{error} occured while getting process id") # Return a random id return "".join(random_choice("0123456789abcdef") for _ in range(12)) @@ -328,7 +329,10 @@ class Ns(object): def _parse_jinja2(self, cloud_init_content, params, context): try: - env = Environment(undefined=StrictUndefined) + env = Environment( + undefined=StrictUndefined, + autoescape=select_autoescape(default_for_string=True, default=True), + ) template = env.from_string(cloud_init_content) return template.render(params or {}) @@ -539,6 +543,8 @@ class Ns(object): return quota + nonlocal indata + flavor_data = { "disk": int(target_flavor["storage-gb"]), "ram": int(target_flavor["memory-mb"]), @@ -547,6 +553,26 @@ class Ns(object): numa = {} extended = {} + target_vdur = None + for vnf in indata.get("vnf", []): + for vdur in vnf.get("vdur", []): + if vdur.get("ns-flavor-id") == target_flavor["id"]: + target_vdur = vdur + + for storage in target_vdur.get("virtual-storages", []): + if ( + storage.get("type-of-storage") + == "etsi-nfv-descriptors:ephemeral-storage" + ): + flavor_data["ephemeral"] = int( + storage.get("size-of-storage", 0) + ) + elif ( + storage.get("type-of-storage") + == "etsi-nfv-descriptors:swap-storage" + ): + flavor_data["swap"] = int(storage.get("size-of-storage", 0)) + if target_flavor.get("guest-epa"): extended = {} epa_vcpu_set = False @@ -671,6 +697,28 @@ class Ns(object): return extra_dict + def _process_affinity_group_params( + target_affinity_group, vim_info, target_record_id + ): + extra_dict = {} + + affinity_group_data = { + "name": target_affinity_group["name"], + "type": target_affinity_group["type"], + "scope": target_affinity_group["scope"], + } + + if target_affinity_group.get("vim-affinity-group-id"): + affinity_group_data[ + "vim-affinity-group-id" + ] = target_affinity_group["vim-affinity-group-id"] + + extra_dict["params"] = { + "affinity_group_data": affinity_group_data, + } + + return extra_dict + def _ip_profile_2_ro(ip_profile): if not ip_profile: return None @@ -768,6 +816,45 @@ class Ns(object): extra_dict = {"depends_on": [image_text, flavor_text]} net_list = [] + # If the position info is provided for all the interfaces, it will be sorted + # according to position number ascendingly. + if all( + i.get("position") + 1 + for i in target_vdu["interfaces"] + if i.get("position") is not None + ): + sorted_interfaces = sorted( + target_vdu["interfaces"], + key=lambda x: (x.get("position") is None, x.get("position")), + ) + target_vdu["interfaces"] = sorted_interfaces + + # If the position info is provided for some interfaces but not all of them, the interfaces + # which has specific position numbers will be placed and others' positions will not be taken care. + else: + if any( + i.get("position") + 1 + for i in target_vdu["interfaces"] + if i.get("position") is not None + ): + n = len(target_vdu["interfaces"]) + sorted_interfaces = [-1] * n + k, m = 0, 0 + while k < n: + if target_vdu["interfaces"][k].get("position"): + idx = target_vdu["interfaces"][k]["position"] + sorted_interfaces[idx - 1] = target_vdu["interfaces"][k] + k += 1 + while m < n: + if not target_vdu["interfaces"][m].get("position"): + idy = sorted_interfaces.index(-1) + sorted_interfaces[idy] = target_vdu["interfaces"][m] + m += 1 + + target_vdu["interfaces"] = sorted_interfaces + + # If the position info is not provided for the interfaces, interfaces will be attached + # according to the order in the VNFD. for iface_index, interface in enumerate(target_vdu["interfaces"]): if interface.get("ns-vld-id"): net_text = ns_preffix + ":vld." + interface["ns-vld-id"] @@ -877,14 +964,56 @@ class Ns(object): if ssh_keys: cloud_config["key-pairs"] = ssh_keys - disk_list = None + persistent_root_disk = {} + disk_list = [] + vnfd_id = vnfr["vnfd-id"] + vnfd = self.db.get_one("vnfds", {"_id": vnfd_id}) + for vdu in vnfd.get("vdu", ()): + if vdu["name"] == target_vdu["vdu-name"]: + for vsd in vnfd.get("virtual-storage-desc", ()): + if ( + vsd.get("id") + == vdu.get("virtual-storage-desc", [[]])[0] + ): + root_disk = vsd + if root_disk.get( + "type-of-storage" + ) == "persistent-storage:persistent-storage" and root_disk.get( + "size-of-storage" + ): + persistent_root_disk[vsd["id"]] = { + "image_id": vdu.get("sw-image-desc"), + "size": root_disk["size-of-storage"], + } + disk_list.append(persistent_root_disk[vsd["id"]]) + if target_vdu.get("virtual-storages"): - disk_list = [ - {"size": disk["size-of-storage"]} - for disk in target_vdu["virtual-storages"] - if disk.get("type-of-storage") - == "persistent-storage:persistent-storage" - ] + for disk in target_vdu["virtual-storages"]: + if ( + disk.get("type-of-storage") + == "persistent-storage:persistent-storage" + and disk["id"] not in persistent_root_disk.keys() + ): + disk_list.append({"size": disk["size-of-storage"]}) + + affinity_group_list = [] + + if target_vdu.get("affinity-or-anti-affinity-group-id"): + affinity_group = {} + for affinity_group_id in target_vdu[ + "affinity-or-anti-affinity-group-id" + ]: + affinity_group_text = ( + ns_preffix + + ":affinity-or-anti-affinity-group." + + affinity_group_id + ) + + extra_dict["depends_on"].append(affinity_group_text) + affinity_group["affinity_group_id"] = ( + "TASK-" + affinity_group_text + ) + affinity_group_list.append(affinity_group) extra_dict["params"] = { "name": "{}-{}-{}-{}".format( @@ -897,6 +1026,7 @@ class Ns(object): "start": True, "image_id": "TASK-" + image_text, "flavor_id": "TASK-" + flavor_text, + "affinity_group_list": affinity_group_list, "net_list": net_list, "cloud_config": cloud_config or None, "disk_list": disk_list, @@ -951,7 +1081,9 @@ class Ns(object): ) item_ = item - if target_vim.startswith("sdn"): + if target_vim.startswith("sdn") or target_vim.startswith( + "wim" + ): # item must be sdn-net instead of net if target_vim is a sdn item_ = "sdn_net" target_record_id += ".sdn" @@ -1001,7 +1133,7 @@ class Ns(object): target_record_id = "{}.{}".format(db_record, target_item["id"]) item_ = item - if target_vim.startswith("sdn"): + if target_vim.startswith("sdn") or target_vim.startswith("wim"): # item must be sdn-net instead of net if target_vim is a sdn item_ = "sdn_net" target_record_id += ".sdn" @@ -1134,6 +1266,20 @@ class Ns(object): process_params=_process_flavor_params, ) + step = "process NS Affinity Groups" + _process_items( + target_list=indata.get("affinity-or-anti-affinity-group") or [], + existing_list=db_nsr.get("affinity-or-anti-affinity-group") + or [], + db_record="nsrs:{}:affinity-or-anti-affinity-group".format( + nsr_id + ), + db_update=db_nsr_update, + db_path="affinity-or-anti-affinity-group", + item="affinity-or-anti-affinity-group", + process_params=_process_affinity_group_params, + ) + # VNF.vld for vnfr_id, vnfr in db_vnfrs.items(): # vnfr_id need to be set as global variable for among others nested method _process_vdu_params