Fix bug 1412: Generate kdu instance from LCM
[osm/LCM.git] / osm_lcm / ns.py
index c7e0184..75db8e5 100644 (file)
@@ -28,12 +28,12 @@ from osm_lcm import ROclient
 from osm_lcm.ng_ro import NgRoClient, NgRoException
 from osm_lcm.lcm_utils import LcmException, LcmExceptionNoMgmtIP, LcmBase, deep_get, get_iterable, populate_dict
 from osm_lcm.data_utils.nsd import get_vnf_profiles
-from osm_lcm.data_utils.vnfd import get_vnf_configuration, get_vdu_list, get_vdu_profile, \
+from osm_lcm.data_utils.vnfd import get_vdu_list, get_vdu_profile, \
     get_ee_sorted_initial_config_primitive_list, get_ee_sorted_terminate_config_primitive_list, \
-    get_kdu_list, get_virtual_link_profiles, get_vdu, get_vdu_configuration, get_kdu_configuration, \
-    get_vdu_index, get_scaling_aspect, get_number_of_instances
+    get_kdu_list, get_virtual_link_profiles, get_vdu, get_configuration, \
+    get_vdu_index, get_scaling_aspect, get_number_of_instances, get_juju_ee_ref
 from osm_lcm.data_utils.list_utils import find_in_list
-from osm_lcm.data_utils.vnfr import get_osm_params
+from osm_lcm.data_utils.vnfr import get_osm_params, get_vdur_index
 from osm_lcm.data_utils.dict_utils import parse_yaml_strings
 from osm_lcm.data_utils.database.vim_account import VimAccountDB
 from n2vc.k8s_helm_conn import K8sHelmConnector
@@ -338,7 +338,6 @@ class NsLcm(LcmBase):
         # remove unused by RO configuration, monitoring, scaling and internal keys
         vnfd_RO.pop("_id", None)
         vnfd_RO.pop("_admin", None)
-        vnfd_RO.pop("vnf-configuration", None)
         vnfd_RO.pop("monitoring-param", None)
         vnfd_RO.pop("scaling-group-descriptor", None)
         vnfd_RO.pop("kdu", None)
@@ -646,10 +645,13 @@ class NsLcm(LcmBase):
             }
             # check if this network needs SDN assist
             if vld.get("pci-interfaces"):
-                db_vim = VimAccountDB.get_vim_account_with_id(target_vld["vim_info"][0]["vim_account_id"])
+                db_vim = get_vim_account(ns_params["vimAccountId"])
                 sdnc_id = db_vim["config"].get("sdn-controller")
                 if sdnc_id:
-                    target_vld["vim_info"].append({"sdnc_id": 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")}
 
             nsd_vnf_profiles = get_vnf_profiles(nsd)
             for nsd_vnf_profile in nsd_vnf_profiles:
@@ -742,8 +744,8 @@ class NsLcm(LcmBase):
                 self.logger.debug("NS > ssh_keys > {}".format(ssh_keys_all))
 
                 if ssh_keys_all:
-                    vdu_configuration = get_vdu_configuration(vnfd, vdur["vdu-id-ref"])
-                    vnf_configuration = get_vnf_configuration(vnfd)
+                    vdu_configuration = get_configuration(vnfd, vdur["vdu-id-ref"])
+                    vnf_configuration = get_configuration(vnfd, vnfd["id"])
                     if vdu_configuration and vdu_configuration.get("config-access") and \
                        vdu_configuration.get("config-access").get("ssh-access"):
                         vdur["ssh-keys"] = ssh_keys_all
@@ -783,8 +785,23 @@ class NsLcm(LcmBase):
                 ns_flavor = target["flavor"][int(vdur["ns-flavor-id"])]
                 if target_vim not in ns_flavor["vim_info"]:
                     ns_flavor["vim_info"][target_vim] = {}
-                # image
-                ns_image = target["image"][int(vdur["ns-image-id"])]
+
+                # deal with images
+                # in case alternative images are provided we must check if they should be applied
+                # for the vim_type, modify the vim_type taking into account
+                ns_image_id = int(vdur["ns-image-id"])
+                if vdur.get("alt-image-ids"):
+                    db_vim = get_vim_account(vnfr["vim-account-id"])
+                    vim_type = db_vim["vim_type"]
+                    for alt_image_id in vdur.get("alt-image-ids"):
+                        ns_alt_image = target["image"][int(alt_image_id)]
+                        if vim_type == ns_alt_image.get("vim-type"):
+                            # must use alternative image
+                            self.logger.debug("use alternative image id: {}".format(alt_image_id))
+                            ns_image_id = alt_image_id
+                            vdur["ns-image-id"] = ns_image_id
+                            break
+                ns_image = target["image"][int(ns_image_id)]
                 if target_vim not in ns_image["vim_info"]:
                     ns_image["vim_info"][target_vim] = {}
 
@@ -1146,14 +1163,14 @@ class NsLcm(LcmBase):
             if vnfr_id:
                 element_type = 'VNF'
                 element_under_configuration = vnfr_id
-                namespace += ".{}".format(vnfr_id)
+                namespace += ".{}-{}".format(vnfr_id, vdu_index or 0)
                 if vdu_id:
                     namespace += ".{}-{}".format(vdu_id, vdu_index or 0)
                     element_type = 'VDU'
                     element_under_configuration = "{}-{}".format(vdu_id, vdu_index or 0)
                     osm_config["osm"]["vdu_id"] = vdu_id
                 elif kdu_name:
-                    namespace += ".{}".format(kdu_name)
+                    namespace += ".{}.{}".format(kdu_name, vdu_index or 0)
                     element_type = 'KDU'
                     element_under_configuration = kdu_name
                     osm_config["osm"]["kdu_name"] = kdu_name
@@ -1215,7 +1232,7 @@ class NsLcm(LcmBase):
                         cloud_name=vca_k8s_cloud,
                         credential_name=vca_k8s_cloud_credential,
                     )
-                elif vca_type == "helm" or vca_type == "helm-v3":                    
+                elif vca_type == "helm" or vca_type == "helm-v3":     
                     ee_id, credentials = await self.vca_map[vca_type].create_execution_environment(
                         namespace=namespace,
                         reuse_ee_id=ee_id,
@@ -1780,7 +1797,7 @@ class NsLcm(LcmBase):
                 if db_vnfr.get("additionalParamsForVnf"):
                     deploy_params.update(parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy()))
 
-                descriptor_config = get_vnf_configuration(vnfd)
+                descriptor_config = get_configuration(vnfd, vnfd["id"])
                 if descriptor_config:
                     self._deploy_n2vc(
                         logging_text=logging_text + "member_vnf_index={} ".format(member_vnf_index),
@@ -1805,7 +1822,7 @@ class NsLcm(LcmBase):
                 # Deploy charms for each VDU that supports one.
                 for vdud in get_vdu_list(vnfd):
                     vdu_id = vdud["id"]
-                    descriptor_config = get_vdu_configuration(vnfd, vdu_id)
+                    descriptor_config = get_configuration(vnfd, vdu_id)
                     vdur = find_in_list(db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id)
 
                     if vdur.get("additionalParams"):
@@ -1844,7 +1861,7 @@ class NsLcm(LcmBase):
                             )
                 for kdud in get_kdu_list(vnfd):
                     kdu_name = kdud["name"]
-                    descriptor_config = get_kdu_configuration(vnfd, kdu_name)
+                    descriptor_config = get_configuration(vnfd, kdu_name)
                     if descriptor_config:
                         vdu_id = None
                         vdu_index = 0
@@ -1886,7 +1903,7 @@ class NsLcm(LcmBase):
                 vdu_name = None
 
                 # Get additional parameters
-                deploy_params = {"OSM": get_osm_params(db_vnfr)}
+                deploy_params = {"OSM": {"vim_account_id": ns_params["vimAccountId"]}}
                 if db_nsr.get("additionalParamsForNs"):
                     deploy_params.update(parse_yaml_strings(db_nsr["additionalParamsForNs"].copy()))
                 base_folder = nsd["_admin"]["storage"]
@@ -2035,7 +2052,7 @@ class NsLcm(LcmBase):
             if db_vnfd_list:
                 for vnfd in db_vnfd_list:
                     db_vnfd = self.db.get_one("vnfds", {"_id": vnfd})
-                    db_vnf_relations = deep_get(db_vnfd, ('vnf-configuration', 'relation'))
+                    db_vnf_relations = get_configuration(db_vnfd, db_vnfd["id"]).get("relation", [])
                     if db_vnf_relations:
                         for r in db_vnf_relations:
                             # check if this VCA is in the relation
@@ -2175,7 +2192,12 @@ class NsLcm(LcmBase):
                                "filter": {"_id": nsr_id},
                                "path": nsr_db_path}
 
-            kdu_instance = await self.k8scluster_map[k8sclustertype].install(
+            kdu_instance = self.k8scluster_map[k8sclustertype].generate_kdu_instance_name(
+                db_dict=db_dict_install,
+                kdu_model=k8s_instance_info["kdu-model"],
+            )
+            self.update_db_2("nsrs", nsr_id, {nsr_db_path + ".kdu-instance": kdu_instance})
+            await self.k8scluster_map[k8sclustertype].install(
                 cluster_uuid=k8s_instance_info["k8scluster-uuid"],
                 kdu_model=k8s_instance_info["kdu-model"],
                 atomic=True,
@@ -2183,7 +2205,9 @@ class NsLcm(LcmBase):
                 db_dict=db_dict_install,
                 timeout=timeout,
                 kdu_name=k8s_instance_info["kdu-name"],
-                namespace=k8s_instance_info["namespace"])
+                namespace=k8s_instance_info["namespace"],
+                kdu_instance=kdu_instance,
+            )
             self.update_db_2("nsrs", nsr_id, {nsr_db_path + ".kdu-instance": kdu_instance})
 
             # Obtain services to obtain management service ip
@@ -2220,8 +2244,9 @@ class NsLcm(LcmBase):
             vnfr_update_dict["kdur.{}.status".format(kdu_index)] = "READY"
             self.update_db_2("vnfrs", vnfr_data.get("_id"), vnfr_update_dict)
 
-            kdu_config = kdud.get("kdu-configuration")
-            if kdu_config and kdu_config.get("initial-config-primitive") and kdu_config.get("juju") is None:
+            kdu_config = get_configuration(vnfd, k8s_instance_info["kdu-name"])
+            if kdu_config and kdu_config.get("initial-config-primitive") and \
+               get_juju_ee_ref(vnfd, k8s_instance_info["kdu-name"]) is None:
                 initial_config_primitive_list = kdu_config.get("initial-config-primitive")
                 initial_config_primitive_list.sort(key=lambda val: int(val["seq"]))
 
@@ -2313,14 +2338,14 @@ class NsLcm(LcmBase):
                     kdud = next(kdud for kdud in vnfd_with_id["kdu"] if kdud["name"] == kdur["kdu-name"])
                     namespace = kdur.get("k8s-namespace")
                     if kdur.get("helm-chart"):
-                        kdumodel = kdur["helm-chart"]["kdu-model-locator"]
+                        kdumodel = kdur["helm-chart"]
                         # Default version: helm3, if helm-version is v2 assign v2
                         k8sclustertype = "helm-chart-v3"
                         self.logger.debug("kdur: {}".format(kdur))
                         if kdur.get("helm-version") and kdur.get("helm-version") == "v2":
                             k8sclustertype = "helm-chart"
                     elif kdur.get("juju-bundle"):
-                        kdumodel = kdur["juju-bundle"]["kdu-model-locator"]
+                        kdumodel = kdur["juju-bundle"]
                         k8sclustertype = "juju-bundle"
                     else:
                         raise LcmException("kdu type for kdu='{}.{}' is neither helm-chart nor "
@@ -2410,10 +2435,8 @@ class NsLcm(LcmBase):
         # fill db_nsr._admin.deployed.VCA.<index>
 
         self.logger.debug(logging_text + "_deploy_n2vc vnfd_id={}, vdu_id={}".format(vnfd_id, vdu_id))
-        if descriptor_config.get("juju"):   # There is one execution envioronment of type juju
-            ee_list = [descriptor_config]
-        elif descriptor_config.get("execution-environment-list"):
-            ee_list = descriptor_config.get("execution-environment-list")
+        if "execution-environment-list" in descriptor_config:
+            ee_list = descriptor_config.get("execution-environment-list", [])
         else:  # other types as script are not supported
             ee_list = []
 
@@ -2718,7 +2741,7 @@ class NsLcm(LcmBase):
                 return vca["ee_id"]
 
     async def destroy_N2VC(self, logging_text, db_nslcmop, vca_deployed, config_descriptor,
-                           vca_index, destroy_ee=True, exec_primitives=True):
+                           vca_index, destroy_ee=True, exec_primitives=True, scaling_in=False):
         """
         Execute the terminate primitives and destroy the execution environment (if destroy_ee=False
         :param logging_text:
@@ -2729,6 +2752,7 @@ class NsLcm(LcmBase):
         :param destroy_ee: False to do not destroy, because it will be destroyed all of then at once
         :param exec_primitives: False to do not execute terminate primitives, because the config is not completed or has
                             not executed properly
+        :param scaling_in: True destroys the application, False destroys the model
         :return: None or exception
         """
 
@@ -2786,7 +2810,7 @@ class NsLcm(LcmBase):
             await self.prometheus.update(remove_jobs=vca_deployed["prometheus_jobs"])
 
         if destroy_ee:
-            await self.vca_map[vca_type].delete_execution_environment(vca_deployed["ee_id"])
+            await self.vca_map[vca_type].delete_execution_environment(vca_deployed["ee_id"], scaling_in=scaling_in)
 
     async def _delete_all_N2VC(self, db_nsr: dict):
         self._write_all_config_status(db_nsr=db_nsr, status='TERMINATING')
@@ -3021,16 +3045,13 @@ class NsLcm(LcmBase):
                     config_descriptor = db_nsr.get("ns-configuration")
                 elif vca.get("vdu_id"):
                     db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
-                    vdud = next((vdu for vdu in db_vnfd.get("vdu", ()) if vdu["id"] == vca.get("vdu_id")), None)
-                    if vdud:
-                        config_descriptor = vdud.get("vdu-configuration")
+                    config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
                 elif vca.get("kdu_name"):
                     db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
-                    kdud = next((kdu for kdu in db_vnfd.get("kdu", ()) if kdu["name"] == vca.get("kdu_name")), None)
-                    if kdud:
-                        config_descriptor = kdud.get("kdu-configuration")
+                    config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
                 else:
-                    config_descriptor = db_vnfds_from_member_index[vca["member-vnf-index"]].get("vnf-configuration")
+                    db_vnfd = db_vnfds_from_member_index[vca["member-vnf-index"]]
+                    config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
                 vca_type = vca.get("type")
                 exec_terminate_primitives = (not operation_params.get("skip_terminate_primitives") and
                                              vca.get("needed_terminate"))
@@ -3409,11 +3430,11 @@ class NsLcm(LcmBase):
             # look for primitive
             config_primitive_desc = descriptor_configuration = None
             if vdu_id:
-                descriptor_configuration = get_vdu_configuration(db_vnfd, vdu_id)
+                descriptor_configuration = get_configuration(db_vnfd, vdu_id)
             elif kdu_name:
-                descriptor_configuration = get_kdu_configuration(db_vnfd, kdu_name)
+                descriptor_configuration = get_configuration(db_vnfd, kdu_name)
             elif vnf_index:
-                descriptor_configuration = get_vnf_configuration(db_vnfd)
+                descriptor_configuration = get_configuration(db_vnfd, db_vnfd["id"])
             else:
                 descriptor_configuration = db_nsd.get("ns-configuration")
 
@@ -3444,12 +3465,12 @@ class NsLcm(LcmBase):
                     desc_params = parse_yaml_strings(db_vnfr.get("additionalParamsForVnf"))
             else:
                 desc_params = parse_yaml_strings(db_nsr.get("additionalParamsForNs"))
-            if kdu_name and get_kdu_configuration(db_vnfd, kdu_name):
-                kdu_configuration = get_kdu_configuration(db_vnfd, kdu_name)
+            if kdu_name and get_configuration(db_vnfd, kdu_name):
+                kdu_configuration = get_configuration(db_vnfd, kdu_name)
                 actions = set()
-                for primitive in kdu_configuration["initial-config-primitive"]:
+                for primitive in kdu_configuration.get("initial-config-primitive", []):
                     actions.add(primitive["name"])
-                for primitive in kdu_configuration["config-primitive"]:
+                for primitive in kdu_configuration.get("config-primitive", []):
                     actions.add(primitive["name"])
                 kdu_action = True if primitive_name in actions else False
 
@@ -3595,6 +3616,7 @@ class NsLcm(LcmBase):
 
         logging_text = "Task ns={} scale={} ".format(nsr_id, nslcmop_id)
         stage = ['', '', '']
+        tasks_dict_info = {}
         # ^ stage, step, VIM progress
         self.logger.debug(logging_text + "Enter")
         # get all needed from database
@@ -3606,6 +3628,7 @@ class NsLcm(LcmBase):
         scale_process = None
         old_operational_status = ""
         old_config_status = ""
+        nsi_id = None
         try:
             # wait for any previous tasks in process
             step = "Waiting for previous operations to terminate"
@@ -3650,6 +3673,8 @@ class NsLcm(LcmBase):
             step = "Getting vnfd from database"
             db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
 
+            base_folder = db_vnfd["_admin"]["storage"]
+
             step = "Getting scaling-group-descriptor"
             scaling_descriptor = find_in_list(
                 get_scaling_aspect(
@@ -3676,6 +3701,7 @@ class NsLcm(LcmBase):
                     admin_scale_index += 1
                     db_nsr_update["_admin.scaling-group.{}.name".format(admin_scale_index)] = scaling_group
             RO_scaling_info = []
+            VCA_scaling_info = []
             vdu_scaling_info = {"scaling_group_name": scaling_group, "vdu": []}
             if scaling_type == "SCALE_OUT":
                 if "aspect-delta-details" not in scaling_descriptor:
@@ -3692,7 +3718,7 @@ class NsLcm(LcmBase):
                 for delta in deltas:
                     for vdu_delta in delta["vdu-delta"]:
                         vdud = get_vdu(db_vnfd, vdu_delta["id"])
-                        vdu_index = get_vdu_index(db_vnfr, vdu_delta["id"])
+                        vdu_index = get_vdur_index(db_vnfr, vdu_delta)
                         cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
                         if cloud_init_text:
                             additional_params = self._get_vdu_additional_params(db_vnfr, vdud["id"]) or {}
@@ -3703,11 +3729,11 @@ class NsLcm(LcmBase):
                         if vdu_profile and "max-number-of-instances" in vdu_profile:
                             max_instance_count = vdu_profile.get("max-number-of-instances", 10)
                         
-                        deafult_instance_num = get_number_of_instances(db_vnfd, vdud["id"])
+                        default_instance_num = get_number_of_instances(db_vnfd, vdud["id"])
 
                         nb_scale_op += vdu_delta.get("number-of-instances", 1)
 
-                        if nb_scale_op + deafult_instance_num > max_instance_count:
+                        if nb_scale_op + default_instance_num > max_instance_count:
                             raise LcmException(
                                 "reached the limit of {} (max-instance-count) "
                                 "scaling-out operations for the "
@@ -3729,6 +3755,14 @@ class NsLcm(LcmBase):
                                         vdud["id"]
                                     )
                                 )
+                                VCA_scaling_info.append(
+                                    {
+                                        "osm_vdu_id": vdu_delta["id"],
+                                        "member-vnf-index": vnf_index,
+                                        "type": "create",
+                                        "vdu_index": vdu_index + x
+                                    }
+                                )
                         RO_scaling_info.append(
                             {
                                 "osm_vdu_id": vdu_delta["id"],
@@ -3750,21 +3784,32 @@ class NsLcm(LcmBase):
                 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
                 for delta in deltas:
                     for vdu_delta in delta["vdu-delta"]:
+                        vdu_index = get_vdur_index(db_vnfr, vdu_delta)
                         min_instance_count = 0
                         vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
                         if vdu_profile and "min-number-of-instances" in vdu_profile:
                             min_instance_count = vdu_profile["min-number-of-instances"]
 
-                        deafult_instance_num = get_number_of_instances(db_vnfd, vdu_delta["id"])
+                        default_instance_num = get_number_of_instances(db_vnfd, vdu_delta["id"])
 
                         nb_scale_op -= vdu_delta.get("number-of-instances", 1)
-                        if nb_scale_op + deafult_instance_num < min_instance_count:
+                        if nb_scale_op + default_instance_num < min_instance_count:
                             raise LcmException(
                                 "reached the limit of {} (min-instance-count) scaling-in operations for the "
                                 "scaling-group-descriptor '{}'".format(nb_scale_op, scaling_group)
                             )
                         RO_scaling_info.append({"osm_vdu_id": vdu_delta["id"], "member-vnf-index": vnf_index,
-                                                "type": "delete", "count": vdu_delta.get("number-of-instances", 1)})
+                                                "type": "delete", "count": vdu_delta.get("number-of-instances", 1),
+                                                "vdu_index": vdu_index - 1})
+                        for x in range(vdu_delta.get("number-of-instances", 1)):
+                            VCA_scaling_info.append(
+                                {
+                                    "osm_vdu_id": vdu_delta["id"],
+                                    "member-vnf-index": vnf_index,
+                                    "type": "delete",
+                                    "vdu_index": vdu_index - 1 - x
+                                }
+                            )
                         vdu_scaling_info["vdu-delete"][vdu_delta["id"]] = vdu_delta.get("number-of-instances", 1)
 
             # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
@@ -3797,7 +3842,9 @@ class NsLcm(LcmBase):
                             "executing pre-scale scaling-config-action '{}'".format(vnf_config_primitive)
 
                         # look for primitive
-                        for config_primitive in db_vnfd.get("vnf-configuration", {}).get("config-primitive", ()):
+                        for config_primitive in (get_configuration(
+                            db_vnfd, db_vnfd["id"]
+                        ) or {}).get("config-primitive", ()):
                             if config_primitive["name"] == vnf_config_primitive:
                                 break
                         else:
@@ -3864,6 +3911,68 @@ class NsLcm(LcmBase):
             db_nsr_update["_admin.scaling-group.{}.nb-scale-op".format(admin_scale_index)] = nb_scale_op
             db_nsr_update["_admin.scaling-group.{}.time".format(admin_scale_index)] = time()
 
+            # SCALE-IN VCA - BEGIN
+            if VCA_scaling_info:
+                step = db_nslcmop_update["detailed-status"] = \
+                    "Deleting the execution environments"
+                scale_process = "VCA"
+                for vdu_info in VCA_scaling_info:
+                    if vdu_info["type"] == "delete":
+                        member_vnf_index = str(vdu_info["member-vnf-index"])
+                        self.logger.debug(logging_text + "vdu info: {}".format(vdu_info))
+                        vdu_id = vdu_info["osm_vdu_id"]
+                        vdu_index = int(vdu_info["vdu_index"])
+                        stage[1] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
+                            member_vnf_index, vdu_id, vdu_index)
+                        stage[2] = step = "Scaling in VCA"
+                        self._write_op_status(
+                            op_id=nslcmop_id,
+                            stage=stage
+                        )
+                        vca_update = db_nsr["_admin"]["deployed"]["VCA"]
+                        config_update = db_nsr["configurationStatus"]
+                        for vca_index, vca in enumerate(vca_update):
+                            if (vca or vca.get("ee_id")) and vca["member-vnf-index"] == member_vnf_index and \
+                                    vca["vdu_count_index"] == vdu_index:
+                                if vca.get("vdu_id"):
+                                    config_descriptor = get_configuration(db_vnfd, vca.get("vdu_id"))
+                                elif vca.get("kdu_name"):
+                                    config_descriptor = get_configuration(db_vnfd, vca.get("kdu_name"))
+                                else:
+                                    config_descriptor = get_configuration(db_vnfd, db_vnfd["id"])
+                                operation_params = db_nslcmop.get("operationParams") or {}
+                                exec_terminate_primitives = (not operation_params.get("skip_terminate_primitives") and
+                                                             vca.get("needed_terminate"))
+                                task = asyncio.ensure_future(asyncio.wait_for(
+                                    self.destroy_N2VC(logging_text, db_nslcmop, vca, config_descriptor,
+                                                      vca_index, destroy_ee=True,
+                                                      exec_primitives=exec_terminate_primitives,
+                                                      scaling_in=True), timeout=self.timeout_charm_delete))
+                                # wait before next removal
+                                await asyncio.sleep(30)
+                                tasks_dict_info[task] = "Terminating VCA {}".format(vca.get("ee_id"))
+                                del vca_update[vca_index]
+                                del config_update[vca_index]
+                        # wait for pending tasks of terminate primitives
+                        if tasks_dict_info:
+                            self.logger.debug(logging_text +
+                                              'Waiting for tasks {}'.format(list(tasks_dict_info.keys())))
+                            error_list = await self._wait_for_tasks(logging_text, tasks_dict_info,
+                                                                    min(self.timeout_charm_delete,
+                                                                        self.timeout_ns_terminate),
+                                                                    stage, nslcmop_id)
+                            tasks_dict_info.clear()
+                            if error_list:
+                                raise LcmException("; ".join(error_list))
+
+                        db_vca_and_config_update = {
+                            "_admin.deployed.VCA": vca_update,
+                            "configurationStatus": config_update
+                        }
+                        self.update_db_2("nsrs", db_nsr["_id"], db_vca_and_config_update)
+            scale_process = None
+            # SCALE-IN VCA - END
+
             # SCALE RO - BEGIN
             if RO_scaling_info:
                 scale_process = "RO"
@@ -3875,6 +3984,117 @@ class NsLcm(LcmBase):
             scale_process = None
             if db_nsr_update:
                 self.update_db_2("nsrs", nsr_id, db_nsr_update)
+            # SCALE RO - END
+
+            # SCALE-UP VCA - BEGIN
+            if VCA_scaling_info:
+                step = db_nslcmop_update["detailed-status"] = \
+                    "Creating new execution environments"
+                scale_process = "VCA"
+                for vdu_info in VCA_scaling_info:
+                    if vdu_info["type"] == "create":
+                        member_vnf_index = str(vdu_info["member-vnf-index"])
+                        self.logger.debug(logging_text + "vdu info: {}".format(vdu_info))
+                        vnfd_id = db_vnfr["vnfd-ref"]
+                        vdu_index = int(vdu_info["vdu_index"])
+                        deploy_params = {"OSM": get_osm_params(db_vnfr)}
+                        if db_vnfr.get("additionalParamsForVnf"):
+                            deploy_params.update(parse_yaml_strings(db_vnfr["additionalParamsForVnf"].copy()))
+                        descriptor_config = get_configuration(db_vnfd, db_vnfd["id"])
+                        if descriptor_config:
+                            vdu_id = None
+                            vdu_name = None
+                            kdu_name = None
+                            self._deploy_n2vc(
+                                logging_text=logging_text + "member_vnf_index={} ".format(member_vnf_index),
+                                db_nsr=db_nsr,
+                                db_vnfr=db_vnfr,
+                                nslcmop_id=nslcmop_id,
+                                nsr_id=nsr_id,
+                                nsi_id=nsi_id,
+                                vnfd_id=vnfd_id,
+                                vdu_id=vdu_id,
+                                kdu_name=kdu_name,
+                                member_vnf_index=member_vnf_index,
+                                vdu_index=vdu_index,
+                                vdu_name=vdu_name,
+                                deploy_params=deploy_params,
+                                descriptor_config=descriptor_config,
+                                base_folder=base_folder,
+                                task_instantiation_info=tasks_dict_info,
+                                stage=stage
+                            )
+                        vdu_id = vdu_info["osm_vdu_id"]
+                        vdur = find_in_list(db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id)
+                        descriptor_config = get_configuration(db_vnfd, vdu_id)
+                        if vdur.get("additionalParams"):
+                            deploy_params_vdu = parse_yaml_strings(vdur["additionalParams"])
+                        else:
+                            deploy_params_vdu = deploy_params
+                        deploy_params_vdu["OSM"] = get_osm_params(db_vnfr, vdu_id, vdu_count_index=vdu_index)
+                        if descriptor_config:
+                            vdu_name = None
+                            kdu_name = None
+                            stage[1] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
+                                member_vnf_index, vdu_id, vdu_index)
+                            stage[2] = step = "Scaling out VCA"
+                            self._write_op_status(
+                                op_id=nslcmop_id,
+                                stage=stage
+                            )
+                            self._deploy_n2vc(
+                                logging_text=logging_text + "member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
+                                    member_vnf_index, vdu_id, 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_id,
+                                vdu_id=vdu_id,
+                                kdu_name=kdu_name,
+                                member_vnf_index=member_vnf_index,
+                                vdu_index=vdu_index,
+                                vdu_name=vdu_name,
+                                deploy_params=deploy_params_vdu,
+                                descriptor_config=descriptor_config,
+                                base_folder=base_folder,
+                                task_instantiation_info=tasks_dict_info,
+                                stage=stage
+                            )
+                        # TODO: scaling for kdu is not implemented yet.
+                        kdu_name = vdu_info["osm_vdu_id"]
+                        descriptor_config = get_configuration(db_vnfd, kdu_name)
+                        if descriptor_config:
+                            vdu_id = None
+                            vdu_index = vdu_index
+                            vdu_name = None
+                            kdur = next(x for x in db_vnfr["kdur"] if x["kdu-name"] == kdu_name)
+                            deploy_params_kdu = {"OSM": get_osm_params(db_vnfr)}
+                            if kdur.get("additionalParams"):
+                                deploy_params_kdu = parse_yaml_strings(kdur["additionalParams"])
+
+                            self._deploy_n2vc(
+                                logging_text=logging_text,
+                                db_nsr=db_nsr,
+                                db_vnfr=db_vnfr,
+                                nslcmop_id=nslcmop_id,
+                                nsr_id=nsr_id,
+                                nsi_id=nsi_id,
+                                vnfd_id=vnfd_id,
+                                vdu_id=vdu_id,
+                                kdu_name=kdu_name,
+                                member_vnf_index=member_vnf_index,
+                                vdu_index=vdu_index,
+                                vdu_name=vdu_name,
+                                deploy_params=deploy_params_kdu,
+                                descriptor_config=descriptor_config,
+                                base_folder=base_folder,
+                                task_instantiation_info=tasks_dict_info,
+                                stage=stage
+                            )
+            # SCALE-UP VCA - END
+            scale_process = None
 
             # POST-SCALE BEGIN
             # execute primitive service POST-SCALING
@@ -3892,7 +4112,9 @@ class NsLcm(LcmBase):
                             vnfr_params.update(db_vnfr["additionalParamsForVnf"])
 
                         # look for primitive
-                        for config_primitive in db_vnfd.get("vnf-configuration", {}).get("config-primitive", ()):
+                        for config_primitive in (
+                            get_configuration(db_vnfd, db_vnfd["id"]) or {}
+                        ).get("config-primitive", ()):
                             if config_primitive["name"] == vnf_config_primitive:
                                 break
                         else:
@@ -3967,6 +4189,11 @@ class NsLcm(LcmBase):
             self.logger.critical(logging_text + "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True)
         finally:
             self._write_ns_status(nsr_id=nsr_id, ns_state=None, current_operation="IDLE", current_operation_id=None)
+            if tasks_dict_info:
+                stage[1] = "Waiting for instantiate pending tasks."
+                self.logger.debug(logging_text + stage[1])
+                exc = await self._wait_for_tasks(logging_text, tasks_dict_info, self.timeout_ns_deploy,
+                                                 stage, nslcmop_id, nsr_id=nsr_id)
             if exc:
                 db_nslcmop_update["detailed-status"] = error_description_nslcmop = "FAILED {}: {}".format(step, exc)
                 nslcmop_operation_state = "FAILED"