Bug 2175: K8s-Cluster Update is not implemented
[osm/LCM.git] / osm_lcm / ns.py
index 6aed304..d3ec1df 100644 (file)
@@ -102,6 +102,11 @@ from osm_common.fsbase import FsException
 
 from osm_lcm.data_utils.database.database import Database
 from osm_lcm.data_utils.filesystem.filesystem import Filesystem
+from osm_lcm.data_utils.wim import (
+    get_sdn_ports,
+    get_target_wim_attrs,
+    select_feasible_wim_account,
+)
 
 from n2vc.n2vc_juju_conn import N2VCJujuConnector
 from n2vc.exceptions import N2VCException, N2VCNotFound, K8sException
@@ -134,7 +139,7 @@ class NsLcm(LcmBase):
     )  # timeout for some progress in a primitive execution
     timeout_migrate = 1800  # default global timeout for migrating vnfs
     timeout_operate = 1800  # default global timeout for migrating vnfs
-    timeout_verticalscale = 1800   # default global timeout for Vertical Sclaing
+    timeout_verticalscale = 1800  # default global timeout for Vertical Sclaing
     SUBOPERATION_STATUS_NOT_FOUND = -1
     SUBOPERATION_STATUS_NEW = -2
     SUBOPERATION_STATUS_SKIP = -3
@@ -225,6 +230,8 @@ class NsLcm(LcmBase):
             "termination": self.RO.status,
             "migrate": self.RO.status,
             "healing": self.RO.recreate_status,
+            "verticalscale": self.RO.status,
+            "start_stop_rebuild": self.RO.status,
         }
 
     @staticmethod
@@ -250,7 +257,6 @@ class NsLcm(LcmBase):
         return None
 
     def _on_update_ro_db(self, nsrs_id, ro_descriptor):
-
         # self.logger.debug('_on_update_ro_db(nsrs_id={}'.format(nsrs_id))
 
         try:
@@ -268,7 +274,6 @@ class NsLcm(LcmBase):
             )
 
     async def _on_update_n2vc_db(self, table, filter, path, updated_data, vca_id=None):
-
         # remove last dot from path (if exists)
         if path.endswith("."):
             path = path[:-1]
@@ -276,7 +281,6 @@ class NsLcm(LcmBase):
         # self.logger.debug('_on_update_n2vc_db(table={}, filter={}, path={}, updated_data={}'
         #                   .format(table, filter, path, updated_data))
         try:
-
             nsr_id = filter.get("_id")
 
             # read ns record from database
@@ -422,7 +426,7 @@ class NsLcm(LcmBase):
     @staticmethod
     def _parse_cloud_init(cloud_init_text, additional_params, vnfd_id, vdu_id):
         try:
-            env = Environment(undefined=StrictUndefined)
+            env = Environment(undefined=StrictUndefined, autoescape=True)
             template = env.from_string(cloud_init_text)
             return template.render(additional_params or {})
         except UndefinedError as e:
@@ -544,7 +548,6 @@ class NsLcm(LcmBase):
             return wim_account
 
     def scale_vnfr(self, db_vnfr, vdu_create=None, vdu_delete=None, mark_delete=False):
-
         db_vdu_push_list = []
         template_vdur = []
         db_update = {"_admin.modified": time()}
@@ -832,7 +835,6 @@ class NsLcm(LcmBase):
         start_deploy,
         timeout_ns_deploy,
     ):
-
         db_vims = {}
 
         def get_vim_account(vim_account_id):
@@ -859,9 +861,30 @@ class NsLcm(LcmBase):
                     target_vld["vim_info"][target_sdn]["sdn-ports"] = vld_params[
                         "provider-network"
                     ]["sdn-ports"]
-            if vld_params.get("wimAccountId"):
-                target_wim = "wim:{}".format(vld_params["wimAccountId"])
-                target_vld["vim_info"][target_wim] = {}
+
+            # check if WIM is needed; if needed, choose a feasible WIM able to connect VIMs
+            # if wim_account_id is specified in vld_params, validate if it is feasible.
+            wim_account_id, db_wim = select_feasible_wim_account(
+                db_nsr, db_vnfrs, target_vld, vld_params, self.logger
+            )
+
+            if wim_account_id:
+                # WIM is needed and a feasible one was found, populate WIM target and SDN ports
+                self.logger.info("WIM selected: {:s}".format(str(wim_account_id)))
+                # update vld_params with correct WIM account Id
+                vld_params["wimAccountId"] = wim_account_id
+
+                target_wim = "wim:{}".format(wim_account_id)
+                target_wim_attrs = get_target_wim_attrs(nsr_id, target_vld, vld_params)
+                sdn_ports = get_sdn_ports(vld_params, db_wim)
+                if len(sdn_ports) > 0:
+                    target_vld["vim_info"][target_wim] = target_wim_attrs
+                    target_vld["vim_info"][target_wim]["sdn-ports"] = sdn_ports
+
+                self.logger.debug(
+                    "Target VLD with WIM data: {:s}".format(str(target_vld))
+                )
+
             for param in ("vim-network-name", "vim-network-id"):
                 if vld_params.get(param):
                     if isinstance(vld_params[param], dict):
@@ -893,6 +916,8 @@ class NsLcm(LcmBase):
                         None,
                     )
                     vdur = next((vdur for vdur in target_vnf.get("vdur", ())), None)
+                    if not vdur:
+                        continue
                     for a_index, a_vld in enumerate(target["ns"]["vld"]):
                         target_vld = find_in_list(
                             get_iterable(vdur, "interfaces"),
@@ -904,7 +929,6 @@ class NsLcm(LcmBase):
                             lambda v_vld: v_vld["name"] in (a_vld["name"], a_vld["id"]),
                         )
                         if target_vld:
-
                             if vnf_params.get("vimAccountId") not in a_vld.get(
                                 "vim_info", {}
                             ):
@@ -1003,16 +1027,16 @@ class NsLcm(LcmBase):
             # check if this network needs SDN assist
             if vld.get("pci-interfaces"):
                 db_vim = get_vim_account(ns_params["vimAccountId"])
-                sdnc_id = db_vim["config"].get("sdn-controller")
-                if sdnc_id:
-                    sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
-                    target_sdn = "sdn:{}".format(sdnc_id)
-                    target_vld["vim_info"][target_sdn] = {
-                        "sdn": True,
-                        "target_vim": target_vim,
-                        "vlds": [sdn_vld],
-                        "type": vld.get("type"),
-                    }
+                if vim_config := db_vim.get("config"):
+                    if sdnc_id := vim_config.get("sdn-controller"):
+                        sdn_vld = "nsrs:{}:vld.{}".format(nsr_id, vld["id"])
+                        target_sdn = "sdn:{}".format(sdnc_id)
+                        target_vld["vim_info"][target_sdn] = {
+                            "sdn": True,
+                            "target_vim": target_vim,
+                            "vlds": [sdn_vld],
+                            "type": vld.get("type"),
+                        }
 
             nsd_vnf_profiles = get_vnf_profiles(nsd)
             for nsd_vnf_profile in nsd_vnf_profiles:
@@ -1290,8 +1314,13 @@ class NsLcm(LcmBase):
         self.logger.debug("RO return > {}".format(desc))
         action_id = desc["action_id"]
         await self._wait_ng_ro(
-            nsr_id, action_id, nslcmop_id, start_deploy, timeout_ns_deploy, stage,
-            operation="instantiation"
+            nsr_id,
+            action_id,
+            nslcmop_id,
+            start_deploy,
+            timeout_ns_deploy,
+            stage,
+            operation="instantiation",
         )
 
         # Updating NSR
@@ -1372,8 +1401,13 @@ class NsLcm(LcmBase):
             # wait until done
             delete_timeout = 20 * 60  # 20 minutes
             await self._wait_ng_ro(
-                nsr_id, action_id, nslcmop_id, start_deploy, delete_timeout, stage,
-                operation="termination"
+                nsr_id,
+                action_id,
+                nslcmop_id,
+                start_deploy,
+                delete_timeout,
+                stage,
+                operation="termination",
             )
 
             db_nsr_update["_admin.deployed.RO.nsr_delete_action_id"] = None
@@ -1550,7 +1584,6 @@ class NsLcm(LcmBase):
         ro_retries = 0
 
         while True:
-
             ro_retries += 1
             if ro_retries >= 360:  # 1 hour
                 raise LcmException(
@@ -1647,7 +1680,9 @@ class NsLcm(LcmBase):
                         }
                         desc = await self.RO.deploy(nsr_id, target)
                         action_id = desc["action_id"]
-                        await self._wait_ng_ro(nsr_id, action_id, timeout=600, operation="instantiation")
+                        await self._wait_ng_ro(
+                            nsr_id, action_id, timeout=600, operation="instantiation"
+                        )
                         break
                     else:
                         # wait until NS is deployed at RO
@@ -1782,7 +1817,6 @@ class NsLcm(LcmBase):
         }
         step = ""
         try:
-
             element_type = "NS"
             element_under_configuration = nsr_id
 
@@ -1866,7 +1900,6 @@ class NsLcm(LcmBase):
             vca_id = self.get_vca_id(db_vnfr, db_nsr)
             # create or register execution environment in VCA
             if vca_type in ("lxc_proxy_charm", "k8s_proxy_charm", "helm", "helm-v3"):
-
                 self._write_configuration_status(
                     nsr_id=nsr_id,
                     vca_index=vca_index,
@@ -2096,7 +2129,7 @@ class NsLcm(LcmBase):
                     # for a KNF and not for its KDUs, the previous verification gives False, and the code
                     # jumps to this block, meaning that there is the need to verify if the VNF is actually a VNF
                     # or it is a KNF)
-                    elif db_vnfr.get('vdur'):
+                    elif db_vnfr.get("vdur"):
                         rw_mgmt_ip = await self.wait_vm_up_insert_key_ro(
                             logging_text,
                             nsr_id,
@@ -2315,7 +2348,6 @@ class NsLcm(LcmBase):
         element_type: str = None,
         other_update: dict = None,
     ):
-
         # self.logger.debug('_write_configuration_status(): vca_index={}, status={}'
         #                   .format(vca_index, status))
 
@@ -2882,9 +2914,11 @@ class NsLcm(LcmBase):
             self.logger.debug(logging_text + "Exit")
             self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_instantiate")
 
-    def _get_vnfd(self, vnfd_id: str, cached_vnfds: Dict[str, Any]):
+    def _get_vnfd(self, vnfd_id: str, projects_read: str, cached_vnfds: Dict[str, Any]):
         if vnfd_id not in cached_vnfds:
-            cached_vnfds[vnfd_id] = self.db.get_one("vnfds", {"id": vnfd_id})
+            cached_vnfds[vnfd_id] = self.db.get_one(
+                "vnfds", {"id": vnfd_id, "_admin.projects_read": projects_read}
+            )
         return cached_vnfds[vnfd_id]
 
     def _get_vnfr(self, nsr_id: str, vnf_profile_id: str, cached_vnfrs: Dict[str, Any]):
@@ -2926,7 +2960,8 @@ class NsLcm(LcmBase):
         ]:
             vnf_profile = get_vnf_profile(nsd, ee_relation_data["vnf-profile-id"])
             vnfd_id = vnf_profile["vnfd-id"]
-            db_vnfd = self._get_vnfd(vnfd_id, cached_vnfds)
+            project = nsd["_admin"]["projects_read"][0]
+            db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
             entity_id = (
                 vnfd_id
                 if ee_relation_level == EELevel.VNF
@@ -2999,7 +3034,8 @@ class NsLcm(LcmBase):
         vnf_profile = get_vnf_profile(nsd, vca.vnf_profile_id)
         vnf_profile_id = vnf_profile["id"]
         vnfd_id = vnf_profile["vnfd-id"]
-        db_vnfd = self._get_vnfd(vnfd_id, cached_vnfds)
+        project = nsd["_admin"]["projects_read"][0]
+        db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
         db_vnf_relations = get_relation_list(db_vnfd, vnfd_id)
         for r in db_vnf_relations:
             provider_dict = None
@@ -3054,7 +3090,8 @@ class NsLcm(LcmBase):
             vnf_profiles,
             lambda vnf_profile: vnf_profile["id"] == ee_relation.vnf_profile_id,
         )["vnfd-id"]
-        db_vnfd = self._get_vnfd(vnfd_id, cached_vnfds)
+        project = nsd["_admin"]["projects_read"][0]
+        db_vnfd = self._get_vnfd(vnfd_id, project, cached_vnfds)
         kdu_resource_profile = get_kdu_resource_profile(
             db_vnfd, ee_relation.kdu_resource_profile_id
         )
@@ -3176,7 +3213,6 @@ class NsLcm(LcmBase):
         vca_index: int,
         timeout: int = 3600,
     ) -> bool:
-
         # steps:
         # 1. find all relations for this VCA
         # 2. wait for other peers related
@@ -3254,7 +3290,6 @@ class NsLcm(LcmBase):
         timeout: int = 600,
         vca_id: str = None,
     ):
-
         try:
             k8sclustertype = k8s_instance_info["k8scluster-type"]
             # Instantiate kdu
@@ -5231,15 +5266,23 @@ class NsLcm(LcmBase):
                         del desc_params["kdu_model"]
                     else:
                         kdu_model = kdu.get("kdu-model")
-                        parts = kdu_model.split(sep=":")
-                        if len(parts) == 2:
-                            kdu_model = parts[0]
+                        if kdu_model.count("/") < 2:
+                            parts = kdu_model.split(sep=":")
+                            if len(parts) == 2:
+                                kdu_model = parts[0]
+                    if desc_params.get("kdu_atomic_upgrade"):
+                        atomic_upgrade = desc_params.get(
+                            "kdu_atomic_upgrade"
+                        ).lower() in ("yes", "true", "1")
+                        del desc_params["kdu_atomic_upgrade"]
+                    else:
+                        atomic_upgrade = True
 
                     detailed_status = await asyncio.wait_for(
                         self.k8scluster_map[kdu["k8scluster-type"]].upgrade(
                             cluster_uuid=kdu.get("k8scluster-uuid"),
                             kdu_instance=kdu.get("kdu-instance"),
-                            atomic=True,
+                            atomic=atomic_upgrade,
                             kdu_model=kdu_model,
                             params=desc_params,
                             db_dict=db_dict,
@@ -5431,33 +5474,39 @@ class NsLcm(LcmBase):
                     "member-vnf-index": member_vnf_index,
                     "type": "delete",
                     "vdu_index": count_index,
-                    })
+                }
+            )
             scaling_info["vdu-delete"][vdu["vdu-id-ref"]] = count_index
             scaling_info["vdu"].append(
                 {
                     "name": vdu.get("name") or vdu.get("vdu-name"),
                     "vdu_id": vdu["vdu-id-ref"],
                     "interface": [],
-                    })
+                }
+            )
             for interface in vdu["interfaces"]:
                 scaling_info["vdu"][index]["interface"].append(
                     {
                         "name": interface["name"],
                         "ip_address": interface["ip-address"],
                         "mac_address": interface.get("mac-address"),
-                        })
+                    }
+                )
             self.logger.info("NS update scaling info{}".format(scaling_info))
             stage[2] = "Terminating VDUs"
             if scaling_info.get("vdu-delete"):
                 # scale_process = "RO"
                 if self.ro_config.get("ng"):
                     await self._scale_ng_ro(
-                        logging_text, db_nsr, update_db_nslcmops, db_vnfr, scaling_info, stage
+                        logging_text,
+                        db_nsr,
+                        update_db_nslcmops,
+                        db_vnfr,
+                        scaling_info,
+                        stage,
                     )
 
-    async def remove_vnf(
-        self, nsr_id, nslcmop_id, vnf_instance_id
-    ):
+    async def remove_vnf(self, nsr_id, nslcmop_id, vnf_instance_id):
         """This method is to Remove VNF instances from NS.
 
         Args:
@@ -5476,7 +5525,9 @@ class NsLcm(LcmBase):
             if check_vnfr_count > 1:
                 stage = ["", "", ""]
                 step = "Getting nslcmop from database"
-                self.logger.debug(step + " after having waited for previous tasks to be completed")
+                self.logger.debug(
+                    step + " after having waited for previous tasks to be completed"
+                )
                 # db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
                 db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
                 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
@@ -5485,19 +5536,31 @@ class NsLcm(LcmBase):
                     "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}) """
 
                 update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
-                await self.terminate_vdus(db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text)
+                await self.terminate_vdus(
+                    db_vnfr,
+                    member_vnf_index,
+                    db_nsr,
+                    update_db_nslcmops,
+                    stage,
+                    logging_text,
+                )
 
                 constituent_vnfr = db_nsr.get("constituent-vnfr-ref")
                 constituent_vnfr.remove(db_vnfr.get("_id"))
-                db_nsr_update["constituent-vnfr-ref"] = db_nsr.get("constituent-vnfr-ref")
+                db_nsr_update["constituent-vnfr-ref"] = db_nsr.get(
+                    "constituent-vnfr-ref"
+                )
                 self.update_db_2("nsrs", nsr_id, db_nsr_update)
                 self.db.del_one("vnfrs", {"_id": db_vnfr.get("_id")})
                 self.update_db_2("nsrs", nsr_id, db_nsr_update)
                 return "COMPLETED", "Done"
             else:
                 step = "Terminate VNF Failed with"
-                raise LcmException("{} Cannot terminate the last VNF in this NS.".format(
-                    vnf_instance_id))
+                raise LcmException(
+                    "{} Cannot terminate the last VNF in this NS.".format(
+                        vnf_instance_id
+                    )
+                )
         except (LcmException, asyncio.CancelledError):
             raise
         except Exception as e:
@@ -5505,7 +5568,12 @@ class NsLcm(LcmBase):
             return "FAILED", "Error removing VNF {}".format(e)
 
     async def _ns_redeploy_vnf(
-        self, nsr_id, nslcmop_id, db_vnfd, db_vnfr, db_nsr,
+        self,
+        nsr_id,
+        nslcmop_id,
+        db_vnfd,
+        db_vnfr,
+        db_nsr,
     ):
         """This method updates and redeploys VNF instances
 
@@ -5528,7 +5596,14 @@ class NsLcm(LcmBase):
 
             # Terminate old VNF resources
             update_db_nslcmops = self.db.get_one("nslcmops", {"_id": nslcmop_id})
-            await self.terminate_vdus(db_vnfr, member_vnf_index, db_nsr, update_db_nslcmops, stage, logging_text)
+            await self.terminate_vdus(
+                db_vnfr,
+                member_vnf_index,
+                db_nsr,
+                update_db_nslcmops,
+                stage,
+                logging_text,
+            )
 
             # old_vnfd_id = db_vnfr["vnfd-id"]
             # new_db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
@@ -5549,10 +5624,16 @@ class NsLcm(LcmBase):
             new_vdur = update_db_nslcmops["operationParams"]["newVdur"]
             # new_vdur = self._create_vdur_descriptor_from_vnfd(db_nsd, db_vnfd, old_db_vnfd, vnfd_id, db_nsr, member_vnf_index)
             # new_vnfr_update = {"vnfd-ref": new_vnfd_ref, "vnfd-id": new_vnfd_id, "connection-point": new_vnfr_cp, "vdur": new_vdur, "ip-address": ""}
-            new_vnfr_update = {"revision": latest_vnfd_revision, "connection-point": new_vnfr_cp, "vdur": new_vdur, "ip-address": ""}
+            new_vnfr_update = {
+                "revision": latest_vnfd_revision,
+                "connection-point": new_vnfr_cp,
+                "vdur": new_vdur,
+                "ip-address": "",
+            }
             self.update_db_2("vnfrs", db_vnfr["_id"], new_vnfr_update)
             updated_db_vnfr = self.db.get_one(
-                "vnfrs", {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id}
+                "vnfrs",
+                {"member-vnf-index-ref": member_vnf_index, "nsr-id-ref": nsr_id},
             )
 
             # Instantiate new VNF resources
@@ -5564,9 +5645,7 @@ class NsLcm(LcmBase):
             scaling_info["kdu-create"] = {}
             vdud_instantiate_list = db_vnfd["vdu"]
             for index, vdud in enumerate(vdud_instantiate_list):
-                cloud_init_text = self._get_vdu_cloud_init_content(
-                    vdud, db_vnfd
-                )
+                cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
                 if cloud_init_text:
                     additional_params = (
                         self._get_vdu_additional_params(updated_db_vnfr, vdud["id"])
@@ -5597,9 +5676,15 @@ class NsLcm(LcmBase):
                 scaling_info["vdu-create"][vdud["id"]] = count_index
             if self.ro_config.get("ng"):
                 self.logger.debug(
-                    "New Resources to be deployed: {}".format(scaling_info))
+                    "New Resources to be deployed: {}".format(scaling_info)
+                )
                 await self._scale_ng_ro(
-                    logging_text, db_nsr, update_db_nslcmops, updated_db_vnfr, scaling_info, stage
+                    logging_text,
+                    db_nsr,
+                    update_db_nslcmops,
+                    updated_db_vnfr,
+                    scaling_info,
+                    stage,
                 )
                 return "COMPLETED", "Done"
         except (LcmException, asyncio.CancelledError):
@@ -5645,7 +5730,6 @@ class NsLcm(LcmBase):
             raise
 
         except Exception as e:
-
             self.logger.debug("Error upgrading charm {}".format(path))
 
             return "FAILED", "Error upgrading charm {}: {}".format(path, e)
@@ -5708,7 +5792,6 @@ class NsLcm(LcmBase):
             nsr_deployed = db_nsr["_admin"].get("deployed")
 
             if update_type == "CHANGE_VNFPKG":
-
                 # Get the input parameters given through update request
                 vnf_instance_id = db_nslcmop["operationParams"][
                     "changeVnfPackageData"
@@ -5747,7 +5830,6 @@ class NsLcm(LcmBase):
 
                 step = "Checking if revision has changed in VNFD"
                 if current_vnf_revision != latest_vnfd_revision:
-
                     change_type = "policy_updated"
 
                     # There is new revision of VNFD, update operation is required
@@ -5795,7 +5877,6 @@ class NsLcm(LcmBase):
                             # There could be several charm used in the same VNF
                             for ee_item in ee_list:
                                 if ee_item.get("juju"):
-
                                     step = "Getting charm name"
                                     charm_name = ee_item["juju"].get("charm")
 
@@ -5825,7 +5906,6 @@ class NsLcm(LcmBase):
                     if find_software_version(current_vnfd) != find_software_version(
                         latest_vnfd
                     ):
-
                         step = "Checking if existing VNF has charm"
                         for current_charm_path, target_charm_path in list(
                             charm_artifact_paths
@@ -5841,15 +5921,8 @@ class NsLcm(LcmBase):
                         # based on new descriptor
                         step = "Redeploying VNF"
                         member_vnf_index = db_vnfr["member-vnf-index-ref"]
-                        (
-                            result,
-                            detailed_status
-                        ) = await self._ns_redeploy_vnf(
-                            nsr_id,
-                            nslcmop_id,
-                            latest_vnfd,
-                            db_vnfr,
-                            db_nsr
+                        (result, detailed_status) = await self._ns_redeploy_vnf(
+                            nsr_id, nslcmop_id, latest_vnfd, db_vnfr, db_nsr
                         )
                         if result == "FAILED":
                             nslcmop_operation_state = result
@@ -5874,10 +5947,8 @@ class NsLcm(LcmBase):
                                     current_charm_path, target_charm_path
                                 )
                             ):
-
                                 step = "Checking whether VNF uses juju bundle"
                                 if check_juju_bundle_existence(current_vnfd):
-
                                     raise LcmException(
                                         "Charm upgrade is not supported for the instance which"
                                         " uses juju-bundle: {}".format(
@@ -5936,7 +6007,9 @@ class NsLcm(LcmBase):
                 db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_instance_id})
                 member_vnf_index = db_vnfr["member-vnf-index-ref"]
                 step = "Removing VNF"
-                (result, detailed_status) = await self.remove_vnf(nsr_id, nslcmop_id, vnf_instance_id)
+                (result, detailed_status) = await self.remove_vnf(
+                    nsr_id, nslcmop_id, vnf_instance_id
+                )
                 if result == "FAILED":
                     nslcmop_operation_state = result
                     error_description_nslcmop = detailed_status
@@ -5952,12 +6025,18 @@ class NsLcm(LcmBase):
                 )
 
             elif update_type == "OPERATE_VNF":
-                vnf_id = db_nslcmop["operationParams"]["operateVnfData"]["vnfInstanceId"]
-                operation_type = db_nslcmop["operationParams"]["operateVnfData"]["changeStateTo"]
-                additional_param = db_nslcmop["operationParams"]["operateVnfData"]["additionalParam"]
+                vnf_id = db_nslcmop["operationParams"]["operateVnfData"][
+                    "vnfInstanceId"
+                ]
+                operation_type = db_nslcmop["operationParams"]["operateVnfData"][
+                    "changeStateTo"
+                ]
+                additional_param = db_nslcmop["operationParams"]["operateVnfData"][
+                    "additionalParam"
+                ]
                 (result, detailed_status) = await self.rebuild_start_stop(
                     nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
-                    )
+                )
                 if result == "FAILED":
                     nslcmop_operation_state = result
                     error_description_nslcmop = detailed_status
@@ -7260,7 +7339,9 @@ class NsLcm(LcmBase):
             job["vnfr_id"] = vnfr_id
         return job_list
 
-    async def rebuild_start_stop(self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type):
+    async def rebuild_start_stop(
+        self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
+    ):
         logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
         self.logger.info(logging_text + "Enter")
         stage = ["Preparing the environment", ""]
@@ -7274,18 +7355,22 @@ class NsLcm(LcmBase):
             db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
             vim_account_id = db_vnfr.get("vim-account-id")
             vim_info_key = "vim:" + vim_account_id
+            vdu_id = additional_param["vdu_id"]
+            vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
             vdur = find_in_list(
-                db_vnfr["vdur"], lambda vdu: vdu["count-index"] == additional_param["count-index"]
-                )
+                vdurs, lambda vdu: vdu["count-index"] == additional_param["count-index"]
+            )
             if vdur:
                 vdu_vim_name = vdur["name"]
                 vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
                 target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
+            else:
+                raise LcmException("Target vdu is not found")
             self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
             # wait for any previous tasks in process
             stage[1] = "Waiting for previous operations to terminate"
             self.logger.info(stage[1])
-            await self.lcm_tasks.waitfor_related_HA('ns', 'nslcmops', nslcmop_id)
+            await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
 
             stage[1] = "Reading from database."
             self.logger.info(stage[1])
@@ -7293,7 +7378,7 @@ class NsLcm(LcmBase):
                 nsr_id=nsr_id,
                 ns_state=None,
                 current_operation=operation_type.upper(),
-                current_operation_id=nslcmop_id
+                current_operation_id=nslcmop_id,
             )
             self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
 
@@ -7309,7 +7394,7 @@ class NsLcm(LcmBase):
                     "vdu_index": additional_param["count-index"],
                     "vdu_id": vdur["id"],
                     "target_vim": target_vim,
-                    "vim_account_id": vim_account_id
+                    "vim_account_id": vim_account_id,
                 }
             }
             stage[1] = "Sending rebuild request to RO... {}".format(desc)
@@ -7319,7 +7404,13 @@ class NsLcm(LcmBase):
             self.logger.info("response from RO: {}".format(result_dict))
             action_id = result_dict["action_id"]
             await self._wait_ng_ro(
-                nsr_id, action_id, nslcmop_id, start_deploy, self.timeout_operate
+                nsr_id,
+                action_id,
+                nslcmop_id,
+                start_deploy,
+                self.timeout_operate,
+                None,
+                "start_stop_rebuild",
             )
             return "COMPLETED", "Done"
         except (ROclient.ROClientException, DbException, LcmException) as e:
@@ -7330,7 +7421,9 @@ class NsLcm(LcmBase):
             exc = "Operation was cancelled"
         except Exception as e:
             exc = traceback.format_exc()
-            self.logger.critical("Exit Exception {} {}".format(type(e).__name__, e), exc_info=True)
+            self.logger.critical(
+                "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
+            )
             return "FAILED", "Error in operate VNF {}".format(exc)
 
     def get_vca_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
@@ -7403,8 +7496,12 @@ class NsLcm(LcmBase):
             self.logger.debug("RO return > {}".format(desc))
             action_id = desc["action_id"]
             await self._wait_ng_ro(
-                nsr_id, action_id, nslcmop_id, start_deploy, self.timeout_migrate,
-                operation="migrate"
+                nsr_id,
+                action_id,
+                nslcmop_id,
+                start_deploy,
+                self.timeout_migrate,
+                operation="migrate",
             )
         except (ROclient.ROClientException, DbException, LcmException) as e:
             self.logger.error("Exit Exception {}".format(e))
@@ -7454,7 +7551,6 @@ class NsLcm(LcmBase):
             self.logger.debug(logging_text + "Exit")
             self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_migrate")
 
-
     async def heal(self, nsr_id, nslcmop_id):
         """
         Heal NS
@@ -7511,17 +7607,22 @@ class NsLcm(LcmBase):
             self.update_db_2("nsrs", nsr_id, db_nsr_update)
 
             step = "Sending heal order to VIM"
-            task_ro = asyncio.ensure_future(
-                self.heal_RO(
-                    logging_text=logging_text,
-                    nsr_id=nsr_id,
-                    db_nslcmop=db_nslcmop,
-                    stage=stage,
-                )
+            # task_ro = asyncio.ensure_future(
+            #    self.heal_RO(
+            #        logging_text=logging_text,
+            #        nsr_id=nsr_id,
+            #        db_nslcmop=db_nslcmop,
+            #        stage=stage,
+            #    )
+            # )
+            # self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "heal_RO", task_ro)
+            # tasks_dict_info[task_ro] = "Healing at VIM"
+            await self.heal_RO(
+                logging_text=logging_text,
+                nsr_id=nsr_id,
+                db_nslcmop=db_nslcmop,
+                stage=stage,
             )
-            self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "heal_RO", task_ro)
-            tasks_dict_info[task_ro] = "Healing at VIM"
-
             # VCA tasks
             # read from db: nsd
             stage[1] = "Getting nsd={} from db.".format(db_nsr["nsd-id"])
@@ -7555,17 +7656,39 @@ class NsLcm(LcmBase):
                     member_vnf_index = db_vnfr.get("member-vnf-index-ref")
 
                     # Check each target VDU and deploy N2VC
-                    for target_vdu in target_vnf["additionalParams"].get("vdu", None):
+                    target_vdu_list = target_vnf.get("additionalParams", {}).get(
+                        "vdu", []
+                    )
+                    if not target_vdu_list:
+                        # Codigo nuevo para crear diccionario
+                        target_vdu_list = []
+                        for existing_vdu in db_vnfr.get("vdur"):
+                            vdu_name = existing_vdu.get("vdu-name", None)
+                            vdu_index = existing_vdu.get("count-index", 0)
+                            vdu_run_day1 = target_vnf.get("additionalParams", {}).get(
+                                "run-day1", False
+                            )
+                            vdu_to_be_healed = {
+                                "vdu-id": vdu_name,
+                                "count-index": vdu_index,
+                                "run-day1": vdu_run_day1,
+                            }
+                            target_vdu_list.append(vdu_to_be_healed)
+                    for target_vdu in target_vdu_list:
                         deploy_params_vdu = target_vdu
                         # Set run-day1 vnf level value if not vdu level value exists
-                        if not deploy_params_vdu.get("run-day1") and target_vnf["additionalParams"].get("run-day1"):
-                            deploy_params_vdu["run-day1"] = target_vnf["additionalParams"].get("run-day1")
+                        if not deploy_params_vdu.get("run-day1") and target_vnf[
+                            "additionalParams"
+                        ].get("run-day1"):
+                            deploy_params_vdu["run-day1"] = target_vnf[
+                                "additionalParams"
+                            ].get("run-day1")
                         vdu_name = target_vdu.get("vdu-id", None)
                         # TODO: Get vdu_id from vdud.
                         vdu_id = vdu_name
                         # For multi instance VDU count-index is mandatory
                         # For single session VDU count-indes is 0
-                        vdu_index = target_vdu.get("count-index",0)
+                        vdu_index = target_vdu.get("count-index", 0)
 
                         # n2vc_redesign STEP 3 to 6 Deploy N2VC
                         stage[1] = "Deploying Execution Environments."
@@ -7579,32 +7702,35 @@ class NsLcm(LcmBase):
                             vnf_ip_address = db_vnfr.get("ip-address")
                             target_instance = None
                             for instance in db_vnfr.get("vdur", None):
-                                if ( instance["vdu-name"] == vdu_name and instance["count-index"] == vdu_index ):
+                                if (
+                                    instance["vdu-name"] == vdu_name
+                                    and instance["count-index"] == vdu_index
+                                ):
                                     target_instance = instance
                                     break
                             if vnf_ip_address == target_instance.get("ip-address"):
                                 self._heal_n2vc(
-                                logging_text=logging_text
-                                + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
-                                    member_vnf_index, vdu_name, vdu_index
-                                ),
-                                db_nsr=db_nsr,
-                                db_vnfr=db_vnfr,
-                                nslcmop_id=nslcmop_id,
-                                nsr_id=nsr_id,
-                                nsi_id=nsi_id,
-                                vnfd_id=vnfd_ref,
-                                vdu_id=None,
-                                kdu_name=None,
-                                member_vnf_index=member_vnf_index,
-                                vdu_index=0,
-                                vdu_name=None,
-                                deploy_params=deploy_params_vdu,
-                                descriptor_config=descriptor_config,
-                                base_folder=base_folder,
-                                task_instantiation_info=tasks_dict_info,
-                                stage=stage,
-                            )
+                                    logging_text=logging_text
+                                    + "member_vnf_index={}, vdu_name={}, vdu_index={} ".format(
+                                        member_vnf_index, vdu_name, vdu_index
+                                    ),
+                                    db_nsr=db_nsr,
+                                    db_vnfr=db_vnfr,
+                                    nslcmop_id=nslcmop_id,
+                                    nsr_id=nsr_id,
+                                    nsi_id=nsi_id,
+                                    vnfd_id=vnfd_ref,
+                                    vdu_id=None,
+                                    kdu_name=None,
+                                    member_vnf_index=member_vnf_index,
+                                    vdu_index=0,
+                                    vdu_name=None,
+                                    deploy_params=deploy_params_vdu,
+                                    descriptor_config=descriptor_config,
+                                    base_folder=base_folder,
+                                    task_instantiation_info=tasks_dict_info,
+                                    stage=stage,
+                                )
 
                         # VDU Level charm. Normal case with native charms.
                         descriptor_config = get_configuration(vnfd, vdu_name)
@@ -7673,9 +7799,7 @@ class NsLcm(LcmBase):
                     db_nsr_update["config-status"] = old_config_status
                     db_nsr_update[
                         "detailed-status"
-                    ] = "FAILED healing nslcmop={} {}: {}".format(
-                        nslcmop_id, step, exc
-                    )
+                    ] = "FAILED healing nslcmop={} {}: {}".format(nslcmop_id, step, exc)
                     for task, task_name in tasks_dict_info.items():
                         if not task.done() or task.cancelled() or task.exception():
                             if task_name.startswith(self.task_name_deploy_vca):
@@ -7738,6 +7862,7 @@ class NsLcm(LcmBase):
         :param stage: list with 3 items: [general stage, tasks, vim_specific]. This task will write over vim_specific
         :return: None or exception
         """
+
         def get_vim_account(vim_account_id):
             nonlocal db_vims
             if vim_account_id in db_vims:
@@ -7752,9 +7877,7 @@ class NsLcm(LcmBase):
             if ns_params and ns_params.get("timeout_ns_heal"):
                 timeout_ns_heal = ns_params["timeout_ns_heal"]
             else:
-                timeout_ns_heal = self.timeout.get(
-                    "ns_heal", self.timeout_ns_heal
-                )
+                timeout_ns_heal = self.timeout.get("ns_heal", self.timeout_ns_heal)
 
             db_vims = {}
 
@@ -7762,7 +7885,11 @@ class NsLcm(LcmBase):
             target = {
                 "action_id": nslcmop_id,
             }
-            self.logger.warning("db_nslcmop={} and timeout_ns_heal={}".format(db_nslcmop,timeout_ns_heal))
+            self.logger.warning(
+                "db_nslcmop={} and timeout_ns_heal={}".format(
+                    db_nslcmop, timeout_ns_heal
+                )
+            )
             target.update(db_nslcmop.get("operationParams", {}))
 
             self.logger.debug("Send to RO > nsr_id={} target={}".format(nsr_id, target))
@@ -7771,8 +7898,13 @@ class NsLcm(LcmBase):
             action_id = desc["action_id"]
             # waits for RO to complete because Reinjecting juju key at ro can find VM in state Deleted
             await self._wait_ng_ro(
-                nsr_id, action_id, nslcmop_id, start_heal, timeout_ns_heal, stage,
-                operation="healing"
+                nsr_id,
+                action_id,
+                nslcmop_id,
+                start_heal,
+                timeout_ns_heal,
+                stage,
+                operation="healing",
             )
 
             # Updating NSR
@@ -7788,7 +7920,7 @@ class NsLcm(LcmBase):
 
         except Exception as e:
             stage[2] = "ERROR healing at VIM"
-            #self.set_vnfr_at_error(db_vnfrs, str(e))
+            # self.set_vnfr_at_error(db_vnfrs, str(e))
             self.logger.error(
                 "Error healing at VIM {}".format(e),
                 exc_info=not isinstance(
@@ -7987,7 +8119,6 @@ class NsLcm(LcmBase):
         }
         step = ""
         try:
-
             element_type = "NS"
             element_under_configuration = nsr_id
 
@@ -8150,7 +8281,7 @@ class NsLcm(LcmBase):
                 status="INSTALLING SW",
                 element_under_configuration=element_under_configuration,
                 element_type=element_type,
-                #other_update=db_nsr_update,
+                # other_update=db_nsr_update,
                 other_update=None,
             )
 
@@ -8223,7 +8354,7 @@ class NsLcm(LcmBase):
                 # n2vc_redesign STEP 5.1
                 # wait for RO (ip-address) Insert pub_key into VM
                 # IMPORTANT: We need do wait for RO to complete healing operation.
-                await self._wait_heal_ro(nsr_id,self.timeout_ns_heal)
+                await self._wait_heal_ro(nsr_id, self.timeout_ns_heal)
                 if vnfr_id:
                     if kdu_name:
                         rw_mgmt_ip = await self.wait_kdu_up(
@@ -8249,15 +8380,19 @@ class NsLcm(LcmBase):
 
             # Day1 operations.
             # get run-day1 operation parameter
-            runDay1 =  deploy_params.get("run-day1",False)
-            self.logger.debug(" Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id,vdu_id,runDay1))
+            runDay1 = deploy_params.get("run-day1", False)
+            self.logger.debug(
+                " Healing vnf={}, vdu={}, runDay1 ={}".format(vnfr_id, vdu_id, runDay1)
+            )
             if runDay1:
                 # n2vc_redesign STEP 6  Execute initial config primitive
                 step = "execute initial config primitive"
 
                 # wait for dependent primitives execution (NS -> VNF -> VDU)
                 if initial_config_primitive_list:
-                    await self._wait_dependent_n2vc(nsr_id, vca_deployed_list, vca_index)
+                    await self._wait_dependent_n2vc(
+                        nsr_id, vca_deployed_list, vca_index
+                    )
 
                 # stage, in function of element type: vdu, kdu, vnf or ns
                 my_vca = vca_deployed_list[vca_index]
@@ -8305,7 +8440,9 @@ class NsLcm(LcmBase):
                     if check_if_terminated_needed:
                         if config_descriptor.get("terminate-config-primitive"):
                             self.update_db_2(
-                                "nsrs", nsr_id, {db_update_entry + "needed_terminate": True}
+                                "nsrs",
+                                nsr_id,
+                                {db_update_entry + "needed_terminate": True},
                             )
                         check_if_terminated_needed = False
 
@@ -8368,7 +8505,9 @@ class NsLcm(LcmBase):
         start_time = time()
         while time() <= start_time + timeout:
             db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
-            operational_status_ro = db_nsr["_admin"]["deployed"]["RO"]["operational-status"]
+            operational_status_ro = db_nsr["_admin"]["deployed"]["RO"][
+                "operational-status"
+            ]
             self.logger.debug("Wait Heal RO > {}".format(operational_status_ro))
             if operational_status_ro != "healing":
                 break
@@ -8403,16 +8542,18 @@ class NsLcm(LcmBase):
         try:
             # wait for any previous tasks in process
             step = "Waiting for previous operations to terminate"
-            await self.lcm_tasks.waitfor_related_HA('ns', 'nslcmops', nslcmop_id)
+            await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
 
             self._write_ns_status(
                 nsr_id=nsr_id,
                 ns_state=None,
                 current_operation="VerticalScale",
-                current_operation_id=nslcmop_id
+                current_operation_id=nslcmop_id,
             )
             step = "Getting nslcmop from database"
-            self.logger.debug(step + " after having waited for previous tasks to be completed")
+            self.logger.debug(
+                step + " after having waited for previous tasks to be completed"
+            )
             db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
             operationParams = db_nslcmop.get("operationParams")
             target = {}
@@ -8421,7 +8562,12 @@ class NsLcm(LcmBase):
             self.logger.debug("RO return > {}".format(desc))
             action_id = desc["action_id"]
             await self._wait_ng_ro(
-                nsr_id, action_id, nslcmop_id, start_deploy, self.timeout_verticalscale
+                nsr_id,
+                action_id,
+                nslcmop_id,
+                start_deploy,
+                self.timeout_verticalscale,
+                operation="verticalscale",
             )
         except (ROclient.ROClientException, DbException, LcmException) as e:
             self.logger.error("Exit Exception {}".format(e))
@@ -8431,7 +8577,9 @@ class NsLcm(LcmBase):
             exc = "Operation was cancelled"
         except Exception as e:
             exc = traceback.format_exc()
-            self.logger.critical("Exit Exception {} {}".format(type(e).__name__, e), exc_info=True)
+            self.logger.critical(
+                "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
+            )
         finally:
             self._write_ns_status(
                 nsr_id=nsr_id,
@@ -8440,9 +8588,7 @@ class NsLcm(LcmBase):
                 current_operation_id=None,
             )
             if exc:
-                db_nslcmop_update[
-                    "detailed-status"
-                ] = "FAILED {}: {}".format(step, exc)
+                db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
                 nslcmop_operation_state = "FAILED"
             else:
                 nslcmop_operation_state = "COMPLETED"