Feature 10509 manual scaling for native k8s charm
[osm/LCM.git] / osm_lcm / ns.py
index 8b2be1e..ddd827e 100644 (file)
@@ -31,6 +31,7 @@ from jinja2 import (
 )
 
 from osm_lcm import ROclient
+from osm_lcm.data_utils.nsr import get_deployed_kdu
 from osm_lcm.ng_ro import NgRoClient, NgRoException
 from osm_lcm.lcm_utils import (
     LcmException,
@@ -54,9 +55,10 @@ from osm_lcm.data_utils.vnfd import (
     get_scaling_aspect,
     get_number_of_instances,
     get_juju_ee_ref,
+    get_kdu_profile,
 )
 from osm_lcm.data_utils.list_utils import find_in_list
-from osm_lcm.data_utils.vnfr import get_osm_params, get_vdur_index
+from osm_lcm.data_utils.vnfr import get_osm_params, get_vdur_index, get_kdur
 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
@@ -4947,14 +4949,6 @@ class NsLcm(LcmBase):
             self.update_db_2("nsrs", nsr_id, db_nsr_update)
             nsr_deployed = db_nsr["_admin"].get("deployed")
 
-            #######
-            nsr_deployed = db_nsr["_admin"].get("deployed")
-            vnf_index = db_nslcmop["operationParams"].get("member_vnf_index")
-            # vdu_id = db_nslcmop["operationParams"].get("vdu_id")
-            # vdu_count_index = db_nslcmop["operationParams"].get("vdu_count_index")
-            # vdu_name = db_nslcmop["operationParams"].get("vdu_name")
-            #######
-
             vnf_index = db_nslcmop["operationParams"]["scaleVnfData"][
                 "scaleByStepData"
             ]["member-vnf-index"]
@@ -5017,9 +5011,9 @@ class NsLcm(LcmBase):
                     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": []}
+
+            vca_scaling_info = []
+            scaling_info = {"scaling_group_name": scaling_group, "vdu": [], "kdu": []}
             if scaling_type == "SCALE_OUT":
                 if "aspect-delta-details" not in scaling_descriptor:
                     raise LcmException(
@@ -5030,12 +5024,14 @@ class NsLcm(LcmBase):
                 # count if max-instance-count is reached
                 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
 
-                vdu_scaling_info["scaling_direction"] = "OUT"
-                vdu_scaling_info["vdu-create"] = {}
+                scaling_info["scaling_direction"] = "OUT"
+                scaling_info["vdu-create"] = {}
+                scaling_info["kdu-create"] = {}
                 for delta in deltas:
-                    for vdu_delta in delta["vdu-delta"]:
+                    for vdu_delta in delta.get("vdu-delta", {}):
                         vdud = get_vdu(db_vnfd, vdu_delta["id"])
-                        vdu_index = get_vdur_index(db_vnfr, vdu_delta)
+                        # vdu_index also provides the number of instance of the targeted vdu
+                        vdu_count = vdu_index = get_vdur_index(db_vnfr, vdu_delta)
                         cloud_init_text = self._get_vdu_cloud_init_content(
                             vdud, db_vnfd
                         )
@@ -5056,10 +5052,18 @@ class NsLcm(LcmBase):
                         default_instance_num = get_number_of_instances(
                             db_vnfd, vdud["id"]
                         )
+                        instances_number = vdu_delta.get("number-of-instances", 1)
+                        nb_scale_op += instances_number
+
+                        new_instance_count = nb_scale_op + default_instance_num
+                        # Control if new count is over max and vdu count is less than max.
+                        # Then assign new instance count
+                        if new_instance_count > max_instance_count > vdu_count:
+                            instances_number = new_instance_count - max_instance_count
+                        else:
+                            instances_number = instances_number
 
-                        nb_scale_op += vdu_delta.get("number-of-instances", 1)
-
-                        if nb_scale_op + default_instance_num > max_instance_count:
+                        if new_instance_count > max_instance_count:
                             raise LcmException(
                                 "reached the limit of {} (max-instance-count) "
                                 "scaling-out operations for the "
@@ -5081,7 +5085,7 @@ class NsLcm(LcmBase):
                                         vdud["id"],
                                     )
                                 )
-                                VCA_scaling_info.append(
+                                vca_scaling_info.append(
                                     {
                                         "osm_vdu_id": vdu_delta["id"],
                                         "member-vnf-index": vnf_index,
@@ -5089,33 +5093,102 @@ class NsLcm(LcmBase):
                                         "vdu_index": vdu_index + x,
                                     }
                                 )
-                        RO_scaling_info.append(
+                        scaling_info["vdu-create"][vdu_delta["id"]] = instances_number
+                    for kdu_delta in delta.get("kdu-resource-delta", {}):
+                        kdu_profile = get_kdu_profile(db_vnfd, kdu_delta["id"])
+                        kdu_name = kdu_profile["kdu-name"]
+                        resource_name = kdu_profile["resource-name"]
+
+                        # Might have different kdus in the same delta
+                        # Should have list for each kdu
+                        if not scaling_info["kdu-create"].get(kdu_name, None):
+                            scaling_info["kdu-create"][kdu_name] = []
+
+                        kdur = get_kdur(db_vnfr, kdu_name)
+                        if kdur.get("helm-chart"):
+                            k8s_cluster_type = "helm-chart-v3"
+                            self.logger.debug("kdur: {}".format(kdur))
+                            if (
+                                kdur.get("helm-version")
+                                and kdur.get("helm-version") == "v2"
+                            ):
+                                k8s_cluster_type = "helm-chart"
+                            raise NotImplementedError
+                        elif kdur.get("juju-bundle"):
+                            k8s_cluster_type = "juju-bundle"
+                        else:
+                            raise LcmException(
+                                "kdu type for kdu='{}.{}' is neither helm-chart nor "
+                                "juju-bundle. Maybe an old NBI version is running".format(
+                                    db_vnfr["member-vnf-index-ref"], kdu_name
+                                )
+                            )
+
+                        max_instance_count = 10
+                        if kdu_profile and "max-number-of-instances" in kdu_profile:
+                            max_instance_count = kdu_profile.get(
+                                "max-number-of-instances", 10
+                            )
+
+                        nb_scale_op += kdu_delta.get("number-of-instances", 1)
+                        deployed_kdu, _ = get_deployed_kdu(
+                            nsr_deployed, kdu_name, vnf_index
+                        )
+                        if deployed_kdu is None:
+                            raise LcmException(
+                                "KDU '{}' for vnf '{}' not deployed".format(
+                                    kdu_name, vnf_index
+                                )
+                            )
+                        kdu_instance = deployed_kdu.get("kdu-instance")
+                        instance_num = await self.k8scluster_map[
+                            k8s_cluster_type
+                        ].get_scale_count(resource_name, kdu_instance, vca_id=vca_id)
+                        kdu_replica_count = instance_num + kdu_delta.get(
+                            "number-of-instances", 1
+                        )
+
+                        # Control if new count is over max and instance_num is less than max.
+                        # Then assign max instance number to kdu replica count
+                        if kdu_replica_count > max_instance_count > instance_num:
+                            kdu_replica_count = max_instance_count
+                        if kdu_replica_count > max_instance_count:
+                            raise LcmException(
+                                "reached the limit of {} (max-instance-count) "
+                                "scaling-out operations for the "
+                                "scaling-group-descriptor '{}'".format(
+                                    instance_num, scaling_group
+                                )
+                            )
+
+                        for x in range(kdu_delta.get("number-of-instances", 1)):
+                            vca_scaling_info.append(
+                                {
+                                    "osm_kdu_id": kdu_name,
+                                    "member-vnf-index": vnf_index,
+                                    "type": "create",
+                                    "kdu_index": instance_num + x - 1,
+                                }
+                            )
+                        scaling_info["kdu-create"][kdu_name].append(
                             {
-                                "osm_vdu_id": vdu_delta["id"],
                                 "member-vnf-index": vnf_index,
                                 "type": "create",
-                                "count": vdu_delta.get("number-of-instances", 1),
+                                "k8s-cluster-type": k8s_cluster_type,
+                                "resource-name": resource_name,
+                                "scale": kdu_replica_count,
                             }
                         )
-                        if cloud_init_list:
-                            RO_scaling_info[-1]["cloud_init"] = cloud_init_list
-                        vdu_scaling_info["vdu-create"][vdu_delta["id"]] = vdu_delta.get(
-                            "number-of-instances", 1
-                        )
-
             elif scaling_type == "SCALE_IN":
-                if (
-                    "min-instance-count" in scaling_descriptor
-                    and scaling_descriptor["min-instance-count"] is not None
-                ):
-                    min_instance_count = int(scaling_descriptor["min-instance-count"])
-
-                vdu_scaling_info["scaling_direction"] = "IN"
-                vdu_scaling_info["vdu-delete"] = {}
                 deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
+
+                scaling_info["scaling_direction"] = "IN"
+                scaling_info["vdu-delete"] = {}
+                scaling_info["kdu-delete"] = {}
+
                 for delta in deltas:
-                    for vdu_delta in delta["vdu-delta"]:
-                        vdu_index = get_vdur_index(db_vnfr, vdu_delta)
+                    for vdu_delta in delta.get("vdu-delta", {}):
+                        vdu_count = 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:
@@ -5124,26 +5197,25 @@ class NsLcm(LcmBase):
                         default_instance_num = get_number_of_instances(
                             db_vnfd, vdu_delta["id"]
                         )
+                        instance_num = vdu_delta.get("number-of-instances", 1)
+                        nb_scale_op -= instance_num
 
-                        nb_scale_op -= vdu_delta.get("number-of-instances", 1)
-                        if nb_scale_op + default_instance_num < min_instance_count:
+                        new_instance_count = nb_scale_op + default_instance_num
+
+                        if new_instance_count < min_instance_count < vdu_count:
+                            instances_number = min_instance_count - new_instance_count
+                        else:
+                            instances_number = instance_num
+
+                        if new_instance_count < 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),
-                                "vdu_index": vdu_index - 1,
-                            }
-                        )
                         for x in range(vdu_delta.get("number-of-instances", 1)):
-                            VCA_scaling_info.append(
+                            vca_scaling_info.append(
                                 {
                                     "osm_vdu_id": vdu_delta["id"],
                                     "member-vnf-index": vnf_index,
@@ -5151,17 +5223,93 @@ class NsLcm(LcmBase):
                                     "vdu_index": vdu_index - 1 - x,
                                 }
                             )
-                        vdu_scaling_info["vdu-delete"][vdu_delta["id"]] = vdu_delta.get(
+                        scaling_info["vdu-delete"][vdu_delta["id"]] = instances_number
+                    for kdu_delta in delta.get("kdu-resource-delta", {}):
+                        kdu_profile = get_kdu_profile(db_vnfd, kdu_delta["id"])
+                        kdu_name = kdu_profile["kdu-name"]
+                        resource_name = kdu_profile["resource-name"]
+
+                        if not scaling_info["kdu-delete"].get(kdu_name, None):
+                            scaling_info["kdu-delete"][kdu_name] = []
+
+                        kdur = get_kdur(db_vnfr, kdu_name)
+                        if kdur.get("helm-chart"):
+                            k8s_cluster_type = "helm-chart-v3"
+                            self.logger.debug("kdur: {}".format(kdur))
+                            if (
+                                kdur.get("helm-version")
+                                and kdur.get("helm-version") == "v2"
+                            ):
+                                k8s_cluster_type = "helm-chart"
+                            raise NotImplementedError
+                        elif kdur.get("juju-bundle"):
+                            k8s_cluster_type = "juju-bundle"
+                        else:
+                            raise LcmException(
+                                "kdu type for kdu='{}.{}' is neither helm-chart nor "
+                                "juju-bundle. Maybe an old NBI version is running".format(
+                                    db_vnfr["member-vnf-index-ref"], kdur["kdu-name"]
+                                )
+                            )
+
+                        min_instance_count = 0
+                        if kdu_profile and "min-number-of-instances" in kdu_profile:
+                            min_instance_count = kdu_profile["min-number-of-instances"]
+
+                        nb_scale_op -= kdu_delta.get("number-of-instances", 1)
+                        deployed_kdu, _ = get_deployed_kdu(
+                            nsr_deployed, kdu_name, vnf_index
+                        )
+                        if deployed_kdu is None:
+                            raise LcmException(
+                                "KDU '{}' for vnf '{}' not deployed".format(
+                                    kdu_name, vnf_index
+                                )
+                            )
+                        kdu_instance = deployed_kdu.get("kdu-instance")
+                        instance_num = await self.k8scluster_map[
+                            k8s_cluster_type
+                        ].get_scale_count(resource_name, kdu_instance, vca_id=vca_id)
+                        kdu_replica_count = instance_num - kdu_delta.get(
                             "number-of-instances", 1
                         )
 
+                        if kdu_replica_count < min_instance_count < instance_num:
+                            kdu_replica_count = min_instance_count
+                        if kdu_replica_count < min_instance_count:
+                            raise LcmException(
+                                "reached the limit of {} (min-instance-count) scaling-in operations for the "
+                                "scaling-group-descriptor '{}'".format(
+                                    instance_num, scaling_group
+                                )
+                            )
+
+                        for x in range(kdu_delta.get("number-of-instances", 1)):
+                            vca_scaling_info.append(
+                                {
+                                    "osm_kdu_id": kdu_name,
+                                    "member-vnf-index": vnf_index,
+                                    "type": "delete",
+                                    "kdu_index": instance_num - x - 1,
+                                }
+                            )
+                        scaling_info["kdu-delete"][kdu_name].append(
+                            {
+                                "member-vnf-index": vnf_index,
+                                "type": "delete",
+                                "k8s-cluster-type": k8s_cluster_type,
+                                "resource-name": resource_name,
+                                "scale": kdu_replica_count,
+                            }
+                        )
+
             # update VDU_SCALING_INFO with the VDUs to delete ip_addresses
-            vdu_delete = copy(vdu_scaling_info.get("vdu-delete"))
-            if vdu_scaling_info["scaling_direction"] == "IN":
+            vdu_delete = copy(scaling_info.get("vdu-delete"))
+            if scaling_info["scaling_direction"] == "IN":
                 for vdur in reversed(db_vnfr["vdur"]):
                     if vdu_delete.get(vdur["vdu-id-ref"]):
                         vdu_delete[vdur["vdu-id-ref"]] -= 1
-                        vdu_scaling_info["vdu"].append(
+                        scaling_info["vdu"].append(
                             {
                                 "name": vdur.get("name") or vdur.get("vdu-name"),
                                 "vdu_id": vdur["vdu-id-ref"],
@@ -5169,7 +5317,7 @@ class NsLcm(LcmBase):
                             }
                         )
                         for interface in vdur["interfaces"]:
-                            vdu_scaling_info["vdu"][-1]["interface"].append(
+                            scaling_info["vdu"][-1]["interface"].append(
                                 {
                                     "name": interface["name"],
                                     "ip_address": interface["ip-address"],
@@ -5213,7 +5361,7 @@ class NsLcm(LcmBase):
                                 "primitive".format(scaling_group, vnf_config_primitive)
                             )
 
-                        vnfr_params = {"VDU_SCALE_INFO": vdu_scaling_info}
+                        vnfr_params = {"VDU_SCALE_INFO": scaling_info}
                         if db_vnfr.get("additionalParamsForVnf"):
                             vnfr_params.update(db_vnfr["additionalParamsForVnf"])
 
@@ -5315,24 +5463,33 @@ class NsLcm(LcmBase):
             ] = time()
 
             # SCALE-IN VCA - BEGIN
-            if VCA_scaling_info:
+            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"])
+                for vca_info in vca_scaling_info:
+                    if vca_info["type"] == "delete":
+                        member_vnf_index = str(vca_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
+                            logging_text + "vdu info: {}".format(vca_info)
                         )
+                        if vca_info.get("osm_vdu_id"):
+                            vdu_id = vca_info["osm_vdu_id"]
+                            vdu_index = int(vca_info["vdu_index"])
+                            stage[
+                                1
+                            ] = "Scaling member_vnf_index={}, vdu_id={}, vdu_index={} ".format(
+                                member_vnf_index, vdu_id, vdu_index
+                            )
+                        else:
+                            vdu_index = 0
+                            kdu_id = vca_info["osm_kdu_id"]
+                            stage[
+                                1
+                            ] = "Scaling member_vnf_index={}, kdu_id={}, vdu_index={} ".format(
+                                member_vnf_index, kdu_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"]
@@ -5414,117 +5571,165 @@ class NsLcm(LcmBase):
             # SCALE-IN VCA - END
 
             # SCALE RO - BEGIN
-            if RO_scaling_info:
+            if scaling_info.get("vdu-create") or scaling_info.get("vdu-delete"):
                 scale_process = "RO"
                 if self.ro_config.get("ng"):
                     await self._scale_ng_ro(
-                        logging_text,
-                        db_nsr,
-                        db_nslcmop,
-                        db_vnfr,
-                        vdu_scaling_info,
-                        stage,
+                        logging_text, db_nsr, db_nslcmop, db_vnfr, scaling_info, stage
                     )
-            vdu_scaling_info.pop("vdu-create", None)
-            vdu_scaling_info.pop("vdu-delete", None)
+            scaling_info.pop("vdu-create", None)
+            scaling_info.pop("vdu-delete", None)
 
             scale_process = None
+            # SCALE RO - END
+
+            # SCALE KDU - BEGIN
+            if scaling_info.get("kdu-create") or scaling_info.get("kdu-delete"):
+                scale_process = "KDU"
+                await self._scale_kdu(
+                    logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
+                )
+            scaling_info.pop("kdu-create", None)
+            scaling_info.pop("kdu-delete", None)
+
+            scale_process = None
+            # SCALE KDU - END
+
             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:
+            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"])
+                for vca_info in vca_scaling_info:
+                    if vca_info["type"] == "create":
+                        member_vnf_index = str(vca_info["member-vnf-index"])
                         self.logger.debug(
-                            logging_text + "vdu info: {}".format(vdu_info)
+                            logging_text + "vdu info: {}".format(vca_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()
+                        if vca_info.get("osm_vdu_id"):
+                            vdu_index = int(vca_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"]
                             )
-                        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"]
+                            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 = vca_info["osm_vdu_id"]
+                            vdur = find_in_list(
+                                db_vnfr["vdur"], lambda vdu: vdu["vdu-id-ref"] == vdu_id
                             )
-                        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
+                            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
                             )
-                            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(
+                            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
-                                ),
-                                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,
-                            )
+                                )
+                                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,
+                                )
+                        else:
+                            kdu_name = vca_info["osm_kdu_id"]
+                            descriptor_config = get_configuration(db_vnfd, kdu_name)
+                            if descriptor_config:
+                                vdu_id = None
+                                kdu_index = int(vca_info["kdu_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=kdu_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
 
@@ -5551,7 +5756,7 @@ class NsLcm(LcmBase):
                             vnf_config_primitive
                         )
 
-                        vnfr_params = {"VDU_SCALE_INFO": vdu_scaling_info}
+                        vnfr_params = {"VDU_SCALE_INFO": scaling_info}
                         if db_vnfr.get("additionalParamsForVnf"):
                             vnfr_params.update(db_vnfr["additionalParamsForVnf"])
 
@@ -5761,6 +5966,107 @@ class NsLcm(LcmBase):
             self.logger.debug(logging_text + "Exit")
             self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_scale")
 
+    async def _scale_kdu(
+        self, logging_text, nsr_id, nsr_deployed, db_vnfd, vca_id, scaling_info
+    ):
+        _scaling_info = scaling_info.get("kdu-create") or scaling_info.get("kdu-delete")
+        for kdu_name in _scaling_info:
+            for kdu_scaling_info in _scaling_info[kdu_name]:
+                deployed_kdu, index = get_deployed_kdu(
+                    nsr_deployed, kdu_name, kdu_scaling_info["member-vnf-index"]
+                )
+                cluster_uuid = deployed_kdu["k8scluster-uuid"]
+                kdu_instance = deployed_kdu["kdu-instance"]
+                scale = int(kdu_scaling_info["scale"])
+                k8s_cluster_type = kdu_scaling_info["k8s-cluster-type"]
+
+                db_dict = {
+                    "collection": "nsrs",
+                    "filter": {"_id": nsr_id},
+                    "path": "_admin.deployed.K8s.{}".format(index),
+                }
+
+                step = "scaling application {}".format(
+                    kdu_scaling_info["resource-name"]
+                )
+                self.logger.debug(logging_text + step)
+
+                if kdu_scaling_info["type"] == "delete":
+                    kdu_config = get_configuration(db_vnfd, kdu_name)
+                    if (
+                        kdu_config
+                        and kdu_config.get("terminate-config-primitive")
+                        and get_juju_ee_ref(db_vnfd, kdu_name) is None
+                    ):
+                        terminate_config_primitive_list = kdu_config.get(
+                            "terminate-config-primitive"
+                        )
+                        terminate_config_primitive_list.sort(
+                            key=lambda val: int(val["seq"])
+                        )
+
+                        for (
+                            terminate_config_primitive
+                        ) in terminate_config_primitive_list:
+                            primitive_params_ = self._map_primitive_params(
+                                terminate_config_primitive, {}, {}
+                            )
+                            step = "execute terminate config primitive"
+                            self.logger.debug(logging_text + step)
+                            await asyncio.wait_for(
+                                self.k8scluster_map[k8s_cluster_type].exec_primitive(
+                                    cluster_uuid=cluster_uuid,
+                                    kdu_instance=kdu_instance,
+                                    primitive_name=terminate_config_primitive["name"],
+                                    params=primitive_params_,
+                                    db_dict=db_dict,
+                                    vca_id=vca_id,
+                                ),
+                                timeout=600,
+                            )
+
+                await asyncio.wait_for(
+                    self.k8scluster_map[k8s_cluster_type].scale(
+                        kdu_instance,
+                        scale,
+                        kdu_scaling_info["resource-name"],
+                        vca_id=vca_id,
+                    ),
+                    timeout=self.timeout_vca_on_error,
+                )
+
+                if kdu_scaling_info["type"] == "create":
+                    kdu_config = get_configuration(db_vnfd, kdu_name)
+                    if (
+                        kdu_config
+                        and kdu_config.get("initial-config-primitive")
+                        and get_juju_ee_ref(db_vnfd, 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"])
+                        )
+
+                        for initial_config_primitive in initial_config_primitive_list:
+                            primitive_params_ = self._map_primitive_params(
+                                initial_config_primitive, {}, {}
+                            )
+                            step = "execute initial config primitive"
+                            self.logger.debug(logging_text + step)
+                            await asyncio.wait_for(
+                                self.k8scluster_map[k8s_cluster_type].exec_primitive(
+                                    cluster_uuid=cluster_uuid,
+                                    kdu_instance=kdu_instance,
+                                    primitive_name=initial_config_primitive["name"],
+                                    params=primitive_params_,
+                                    db_dict=db_dict,
+                                    vca_id=vca_id,
+                                ),
+                                timeout=600,
+                            )
+
     async def _scale_ng_ro(
         self, logging_text, db_nsr, db_nslcmop, db_vnfr, vdu_scaling_info, stage
     ):