From 5f75f10f2308aa6a8cf36cfdeeb20dc95316c5ce Mon Sep 17 00:00:00 2001 From: aktas Date: Mon, 15 Mar 2021 11:26:10 +0300 Subject: [PATCH] Feature 10509 manual scaling for native k8s charm Also includes improvements for scale function Change-Id: I23f51b8c1b219681841d0b1f7f4db3a0d9ed4c7b Signed-off-by: aktas --- osm_lcm/data_utils/nsr.py | 14 + osm_lcm/data_utils/vnfd.py | 7 + osm_lcm/data_utils/vnfr.py | 8 + osm_lcm/ns.py | 624 ++++++++++++++++++++------- osm_lcm/tests/test_db_descriptors.py | 257 +++++++++++ osm_lcm/tests/test_ns.py | 36 +- 6 files changed, 786 insertions(+), 160 deletions(-) diff --git a/osm_lcm/data_utils/nsr.py b/osm_lcm/data_utils/nsr.py index f62b0b4..006713c 100644 --- a/osm_lcm/data_utils/nsr.py +++ b/osm_lcm/data_utils/nsr.py @@ -22,6 +22,20 @@ # contact: fbravo@whitestack.com ## +from osm_lcm.lcm_utils import get_iterable + def get_vlds(nsr): return nsr.get("vld", ()) + + +def get_deployed_kdu(nsr_deployed, kdu_name, member_vnf_index): + deployed_kdu = None + index = None + for index, deployed_kdu in enumerate(get_iterable(nsr_deployed, "K8s")): + if ( + kdu_name == deployed_kdu["kdu-name"] + and deployed_kdu["member-vnf-index"] == member_vnf_index + ): + break + return deployed_kdu, index diff --git a/osm_lcm/data_utils/vnfd.py b/osm_lcm/data_utils/vnfd.py index 5351c41..17a98a9 100644 --- a/osm_lcm/data_utils/vnfd.py +++ b/osm_lcm/data_utils/vnfd.py @@ -101,6 +101,13 @@ def get_vdu_profile(vnfd, vdu_profile_id): ) +def get_kdu_profile(vnfd, kdu_profile_id): + return list_utils.find_in_list( + vnfd.get("df", ())[0]["kdu-resource-profile"], + lambda kdu_profile: kdu_profile["id"] == kdu_profile_id, + ) + + def get_configuration(vnfd, entity_id): lcm_ops_config = vnfd.get("df")[0].get("lcm-operations-configuration") if not lcm_ops_config: diff --git a/osm_lcm/data_utils/vnfr.py b/osm_lcm/data_utils/vnfr.py index 7e4d164..fe98102 100644 --- a/osm_lcm/data_utils/vnfr.py +++ b/osm_lcm/data_utils/vnfr.py @@ -69,3 +69,11 @@ def get_vdur_index(db_vnfr, vdu_delta): return len([x for x in vdur_list if x.get("vdu-id-ref") == vdu_delta["id"]]) else: return 0 + + +def get_kdur(db_vnfr, kdu_name): + kdur_list = get_iterable(db_vnfr, "kdur") + if kdur_list: + return next(x for x in kdur_list if x.get("kdu-name") == kdu_name) + else: + return None diff --git a/osm_lcm/ns.py b/osm_lcm/ns.py index 8b2be1e..ddd827e 100644 --- a/osm_lcm/ns.py +++ b/osm_lcm/ns.py @@ -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 ): diff --git a/osm_lcm/tests/test_db_descriptors.py b/osm_lcm/tests/test_db_descriptors.py index a42449b..cc4f828 100644 --- a/osm_lcm/tests/test_db_descriptors.py +++ b/osm_lcm/tests/test_db_descriptors.py @@ -224,6 +224,66 @@ db_nslcmops_text = """ operationState: COMPLETED startTime: 1575034637.0445576 statusEnteredTime: 1575034663.8484545 + +- _admin: + created: 1575034637.044651 + modified: 1575034637.044651 + projects_read: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + projects_write: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + _id: 52770491-a765-40ce-97a1-c6e200bba7b3 + detailed-status: done + id: 52770491-a765-40ce-97a1-c6e200bba7b3 + isAutomaticInvocation: false + isCancelPending: false + lcmOperationType: instantiate + links: + nsInstance: /osm/nslcm/v1/ns_instances/c54b14cb-69a8-45bc-b011-d6bea187dc0a + self: /osm/nslcm/v1/ns_lcm_op_occs/52770491-a765-40ce-97a1-c6e200bba7b3 + nsInstanceId: 0bcb701c-ee4d-41ab-8ee6-f4156f7f114d + operationParams: + lcmOperationType: scale + nsInstanceId: c54b14cb-69a8-45bc-b011-d6bea187dc0a + scaleVnfData: + scaleByStepData: + member-vnf-index: native-kdu + scaling-group-descriptor: kdu_scaling_group + scaleVnfType: SCALE_OUT + scaleType: SCALE_VNF + operationState: COMPLETED + startTime: 1575034637.0445576 + statusEnteredTime: 1575034663.8484545 + +- _admin: + created: 1575034637.044651 + modified: 1575034637.044651 + projects_read: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + projects_write: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + _id: 4013bbd2-b151-40ee-bcef-7e24ce5432f6 + detailed-status: done + id: 4013bbd2-b151-40ee-bcef-7e24ce5432f6 + isAutomaticInvocation: false + isCancelPending: false + lcmOperationType: instantiate + links: + nsInstance: /osm/nslcm/v1/ns_instances/c54b14cb-69a8-45bc-b011-d6bea187dc0a + self: /osm/nslcm/v1/ns_lcm_op_occs/4013bbd2-b151-40ee-bcef-7e24ce5432f6 + nsInstanceId: 0bcb701c-ee4d-41ab-8ee6-f4156f7f114d + operationParams: + lcmOperationType: scale + nsInstanceId: c54b14cb-69a8-45bc-b011-d6bea187dc0a + scaleVnfData: + scaleByStepData: + member-vnf-index: native-kdu + scaling-group-descriptor: kdu_scaling_group_2 + scaleVnfType: SCALE_OUT + scaleType: SCALE_VNF + operationState: COMPLETED + startTime: 1575034637.0445576 + statusEnteredTime: 1575034663.8484545 """ db_nsrs_text = """ @@ -893,6 +953,73 @@ db_nsrs_text = """ vim-network-name: mgmt vnfd-id: - 7ab0d10d-8ce2-4c68-aef6-cc5a437a9c62 + +- _admin: + created: 1575034637.011233 + current-operation: null + deployed: + K8s: + - k8scluster-uuid: 73d96432-d692-40d2-8440-e0c73aee209c + kdu-instance: native-kdu-0 + kdu-model: native-kdu-0 + kdu-name: native-kdu + member-vnf-index: native-kdu + vnfr-id: 5ac34899-a23a-4b3c-918a-cd77acadbea6 + RO: + detailed-status: Deployed at VIM + nsd_id: b03a8de8-1898-4142-bc6d-3b0787df567d + nsr_id: b5ce3e00-8647-415d-afaa-d5a612cf3074 + nsr_status: ACTIVE + operational-status: running + vnfd: + - id: b9493dae-a4c9-4b96-8965-329581efb0a1 + member-vnf-index: native-kdu + VCA: [] + modified: 1575034637.011233 + nsState: INSTANTIATED + nslcmop: null + operation-type: null + projects_read: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + projects_write: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + _id: c54b14cb-69a8-45bc-b011-d6bea187dc0a + additionalParamsForNs: null + admin-status: ENABLED + config-status: configured + constituent-vnfr-ref: + - 5ac34899-a23a-4b3c-918a-cd77acadbea6 + create-time: 1575034636.9990137 + datacenter: ea958ba5-4e58-4405-bf42-6e3be15d4c3a + description: default description + detailed-status: done + id: c54b14cb-69a8-45bc-b011-d6bea187dc0a + instantiate_params: + nsDescription: default description + nsName: native-kdu + nsdId: d0f63683-9032-4c6f-8928-ffd4674b9f69 + vimAccountId: 74337dcb-ef54-41e7-bd2d-8c0d7fcd326f + name: native-kdu + name-ref: native-kdu + ns-instance-config-ref: c54b14cb-69a8-45bc-b011-d6bea187dc0a + nsd-id: d0f63683-9032-4c6f-8928-ffd4674b9f69 + nsd-name-ref: native-kdu_ns + nsd-ref: native-kdu_ns + operational-events: [] + operational-status: init + orchestration-progress: {} + resource-orchestrator: osmopenmano + short-name: native-kdu + ssh-authorized-key: null + vld: + - id: mgmtnet + name: null + status: ACTIVE + status-detailed: null + vim-id: 9b6a2ac4-767e-4ec9-9497-8ba63084c77f + vim-network-name: mgmt + vnfd-id: + - d96b1cdf-5ad6-49f7-bf65-907ada989293 """ ro_ns_text = """ @@ -1511,6 +1638,90 @@ db_vnfds_text = """ short-name: multikdu_knf vendor: Telefonica version: '1.0' + +- _admin: + created: 1575031727.5383403 + modified: 1575031727.5383403 + onboardingState: ONBOARDED + operationalState: ENABLED + projects_read: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + projects_write: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + storage: + descriptor: native-kdu_knf/native-kdu_vnfd.yaml + folder: d96b1cdf-5ad6-49f7-bf65-907ada989293 + fs: local + path: /app/storage/ + pkg-dir: native-kdu_knf + zipfile: native-kdu_knf.tar.gz + usageState: NOT_IN_USE + userDefinedData: {} + _id: d96b1cdf-5ad6-49f7-bf65-907ada989293 + connection-point: + - name: mgmt + description: KNF with two KDU using juju-bundle + df: + - id: native-kdu + kdu-resource-profile: + - id: scale-app + kdu-name: native-kdu + min-number-of-instances: 1 + resource-name: app + - id: scale-app2 + kdu-name: native-kdu + min-number-of-instances: 1 + max-number-of-instances: 10 + resource-name: app2 + scaling-aspect: + - id: kdu_scaling_group + name: kdu_scaling_group + max-scale-level: 10 + aspect-delta-details: + deltas: + - id: native-kdu-delta + kdu-resource-delta: + - id: scale-app + number-of-instances: 1 + - id: kdu_scaling_group_2 + name: kdu_scaling_group_2 + max-scale-level: 10 + aspect-delta-details: + deltas: + - id: native-kdu-delta + kdu-resource-delta: + - id: scale-app + number-of-instances: 1 + - id: scale-app2 + number-of-instances: 2 + lcm-operations-configuration: + operate-vnf-op-config: + day1-2: + - id: native-kdu + initial-config-primitive: + - name: changecontent + parameter: + - data-type: STRING + name: application-name + value: nginx + - data-type: STRING + name: customtitle + value: Initial Config Primitive + seq: '1' + id: native-kdu_knf + k8s-cluster: + nets: + - external-connection-point-ref: mgmt + id: mgmtnet + kdu: + - juju-bundle: stable/native-kdu + name: native-kdu + mgmt-interface: + cp: mgmt + name: native-kdu_knf + short-name: native-kdu_knf + vendor: Ulak Haberlesme A.S. + version: '1.0' """ db_vnfrs_text = """ @@ -1717,6 +1928,42 @@ db_vnfrs_text = """ vim-account-id: 74337dcb-ef54-41e7-bd2d-8c0d7fcd326f vnfd-id: 7ab0d10d-8ce2-4c68-aef6-cc5a437a9c62 vnfd-ref: multikdu_knf + +- _admin: + created: 1575034637.009597 + modified: 1575034637.009597 + nsState: NOT_INSTANTIATED + projects_read: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + projects_write: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + _id: 5ac34899-a23a-4b3c-918a-cd77acadbea6 + additionalParamsForVnf: null + connection-point: + - connection-point-id: null + id: null + name: mgmt + created-time: 1575034636.9990137 + id: 5ac34899-a23a-4b3c-918a-cd77acadbea6 + ip-address: null + k8s-cluster: + nets: + - external-connection-point-ref: mgmt + id: mgmtnet + ns-vld-id: mgmtnet + vim_net: internal + kdur: + - ip-address: null + juju-bundle: app-bundle + k8s-cluster: + id: e7169dab-f71a-4f1f-b82b-432605e8c4b3 + kdu-name: native-kdu + member-vnf-index-ref: native-kdu + nsr-id-ref: c54b14cb-69a8-45bc-b011-d6bea187dc0a + vdur: [] + vim-account-id: 74337dcb-ef54-41e7-bd2d-8c0d7fcd326f + vnfd-id: d96b1cdf-5ad6-49f7-bf65-907ada989293 + vnfd-ref: native-kdu_knf """ db_nslcmops_scale_text = """ @@ -1792,4 +2039,14 @@ test_ids = { "instantiate": "cf3aa178-7640-4174-b921-2330e6f2aad6", "terminate": None, }, + "TEST-NATIVE-KDU": { + "ns": "c54b14cb-69a8-45bc-b011-d6bea187dc0a", + "instantiate": "52770491-a765-40ce-97a1-c6e200bba7b3", + "terminate": None, + }, + "TEST-NATIVE-KDU-2": { + "ns": "c54b14cb-69a8-45bc-b011-d6bea187dc0a", + "instantiate": "4013bbd2-b151-40ee-bcef-7e24ce5432f6", + "terminate": None, + }, } diff --git a/osm_lcm/tests/test_ns.py b/osm_lcm/tests/test_ns.py index 192f8e0..62de111 100644 --- a/osm_lcm/tests/test_ns.py +++ b/osm_lcm/tests/test_ns.py @@ -394,6 +394,37 @@ class TestMyNS(asynctest.TestCase): self.assertEqual(return_value, expected_value) # print("scale_result: {}".format(self.db.get_one("nslcmops", {"_id": nslcmop_id}).get("detailed-status"))) + # Test scale() for native kdu + # this also includes testing _scale_kdu() + nsr_id = descriptors.test_ids["TEST-NATIVE-KDU"]["ns"] + nslcmop_id = descriptors.test_ids["TEST-NATIVE-KDU"]["instantiate"] + + self.my_ns.k8sclusterjuju.scale = asynctest.mock.CoroutineMock() + self.my_ns.k8sclusterjuju.exec_primitive = asynctest.mock.CoroutineMock() + self.my_ns.k8sclusterjuju.get_scale_count = asynctest.mock.CoroutineMock( + return_value=1 + ) + await self.my_ns.scale(nsr_id, nslcmop_id) + expected_value = "COMPLETED" + return_value = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get( + "operationState" + ) + self.assertEqual(return_value, expected_value) + self.my_ns.k8sclusterjuju.scale.assert_called_once() + + # Test scale() for native kdu with 2 resource + nsr_id = descriptors.test_ids["TEST-NATIVE-KDU-2"]["ns"] + nslcmop_id = descriptors.test_ids["TEST-NATIVE-KDU-2"]["instantiate"] + + self.my_ns.k8sclusterjuju.get_scale_count.return_value = 2 + await self.my_ns.scale(nsr_id, nslcmop_id) + expected_value = "COMPLETED" + return_value = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get( + "operationState" + ) + self.assertEqual(return_value, expected_value) + self.my_ns.k8sclusterjuju.scale.assert_called() + async def test_vca_status_refresh(self): nsr_id = descriptors.test_ids["TEST-A"]["ns"] nslcmop_id = descriptors.test_ids["TEST-A"]["instantiate"] @@ -415,7 +446,10 @@ class TestMyNS(asynctest.TestCase): "operate-vnf-op-config" ]["day1-2"] ): - if "juju" in v["execution-environment-list"][k]: + if ( + v.get("execution-environment-list") + and "juju" in v["execution-environment-list"][k] + ): expected_value = self.db.get_list("nsrs")[i][ "vcaStatus" ] -- 2.17.1