fix(scale): manual scaling now works 81/10081/2
authorbravof <fbravo@whitestack.com>
Mon, 7 Dec 2020 15:57:31 +0000 (12:57 -0300)
committerbravof <fbravo@whitestack.com>
Mon, 7 Dec 2020 16:18:26 +0000 (13:18 -0300)
Change-Id: I1f54930996368626d292ace5b55e45e9472775a7
Signed-off-by: bravof <fbravo@whitestack.com>
osm_lcm/data_utils/vnfd.py
osm_lcm/ns.py

index 5774060..668fab9 100644 (file)
@@ -135,3 +135,23 @@ def get_vdu_index(vnfd, vdu_id):
         return vnfd.get("vdu", ()).index(target_vdu)
     else:
         return -1
+
+
+def get_scaling_aspect(vnfd):
+    return vnfd.get("df", ())[0].get("scaling-aspect", ())
+
+
+def get_number_of_instances(vnfd, vdu_id):
+    return list_utils.find_in_list(
+        vnfd.get(
+            "df",
+            ()
+        )[0].get(
+            "instantiation-level",
+            ()
+        )[0].get(
+            "vdu-level",
+            ()
+        ),
+        lambda a_vdu: a_vdu["vdu-id"] == vdu_id
+    )["number-of-instances"]
index ea2320f..a90f4e8 100644 (file)
@@ -31,7 +31,7 @@ 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, \
     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_vdu_index, get_scaling_aspect, get_number_of_instances
 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.dict_utils import parse_yaml_strings
@@ -3627,7 +3627,6 @@ class NsLcm(LcmBase):
             # vdu_name = db_nslcmop["operationParams"].get("vdu_name")
             #######
 
-            RO_nsr_id = nsr_deployed["RO"].get("nsr_id")
             vnf_index = db_nslcmop["operationParams"]["scaleVnfData"]["scaleByStepData"]["member-vnf-index"]
             scaling_group = db_nslcmop["operationParams"]["scaleVnfData"]["scaleByStepData"]["scaling-group-descriptor"]
             scaling_type = db_nslcmop["operationParams"]["scaleVnfData"]["scaleVnfType"]
@@ -3644,10 +3643,13 @@ class NsLcm(LcmBase):
             db_vnfd = self.db.get_one("vnfds", {"_id": db_vnfr["vnfd-id"]})
 
             step = "Getting scaling-group-descriptor"
-            for scaling_descriptor in db_vnfd["scaling-group-descriptor"]:
-                if scaling_descriptor["name"] == scaling_group:
-                    break
-            else:
+            scaling_descriptor = find_in_list(
+                get_scaling_aspect(
+                    db_vnfd
+                ),
+                lambda scale_desc: scale_desc["name"] == scaling_group
+            )
+            if not scaling_descriptor:
                 raise LcmException("input parameter 'scaleByStepData':'scaling-group-descriptor':'{}' is not present "
                                    "at vnfd:scaling-group-descriptor".format(scaling_group))
 
@@ -3668,63 +3670,94 @@ class NsLcm(LcmBase):
             RO_scaling_info = []
             vdu_scaling_info = {"scaling_group_name": scaling_group, "vdu": []}
             if scaling_type == "SCALE_OUT":
+                if "aspect-delta-details" not in scaling_descriptor:
+                    raise LcmException(
+                        "Aspect delta details not fount in scaling descriptor {}".format(
+                            scaling_descriptor["name"]
+                        )
+                    )
                 # count if max-instance-count is reached
-                max_instance_count = scaling_descriptor.get("max-instance-count", 10)
-                # self.logger.debug("MAX_INSTANCE_COUNT is {}".format(max_instance_count))
-                if nb_scale_op >= max_instance_count:
-                    raise LcmException("reached the limit of {} (max-instance-count) "
-                                       "scaling-out operations for the "
-                                       "scaling-group-descriptor '{}'".format(nb_scale_op, scaling_group))
-
-                nb_scale_op += 1
+                deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
+
                 vdu_scaling_info["scaling_direction"] = "OUT"
                 vdu_scaling_info["vdu-create"] = {}
-                for vdu_scale_info in scaling_descriptor["vdu"]:
-                    vdud = next(vdu for vdu in db_vnfd.get("vdu") if vdu["id"] == vdu_scale_info["vdu-id-ref"])
-                    vdu_index = len([x for x in db_vnfr.get("vdur", ())
-                                     if x.get("vdu-id-ref") == vdu_scale_info["vdu-id-ref"] and
-                                     x.get("member-vnf-index-ref") == vnf_index])
-                    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 {}
-                    cloud_init_list = []
-                    for x in range(vdu_scale_info.get("count", 1)):
+                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"])
+                        cloud_init_text = self._get_vdu_cloud_init_content(vdud, db_vnfd)
                         if cloud_init_text:
-                            # TODO Information of its own ip is not available because db_vnfr is not updated.
-                            additional_params["OSM"] = get_osm_params(
-                                db_vnfr,
-                                vdu_scale_info["vdu-id-ref"],
-                                vdu_index + x
+                            additional_params = self._get_vdu_additional_params(db_vnfr, vdud["id"]) or {}
+                        cloud_init_list = []
+
+                        vdu_profile = get_vdu_profile(db_vnfd, vdu_delta["id"])
+                        max_instance_count = 10
+                        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"])
+
+                        nb_scale_op += vdu_delta.get("number-of-instances", 1)
+
+                        if nb_scale_op + deafult_instance_num > max_instance_count:
+                            raise LcmException(
+                                "reached the limit of {} (max-instance-count) "
+                                "scaling-out operations for the "
+                                "scaling-group-descriptor '{}'".format(nb_scale_op, scaling_group)
                             )
-                            cloud_init_list.append(
-                                self._parse_cloud_init(
-                                    cloud_init_text,
-                                    additional_params,
-                                    db_vnfd["id"],
-                                    vdud["id"]
+                        for x in range(vdu_delta.get("number-of-instances", 1)):
+                            if cloud_init_text:
+                                # TODO Information of its own ip is not available because db_vnfr is not updated.
+                                additional_params["OSM"] = get_osm_params(
+                                    db_vnfr,
+                                    vdu_delta["id"],
+                                    vdu_index + x
                                 )
-                            )
-                    RO_scaling_info.append({"osm_vdu_id": vdu_scale_info["vdu-id-ref"], "member-vnf-index": vnf_index,
-                                            "type": "create", "count": vdu_scale_info.get("count", 1)})
-                    if cloud_init_list:
-                        RO_scaling_info[-1]["cloud_init"] = cloud_init_list
-                    vdu_scaling_info["vdu-create"][vdu_scale_info["vdu-id-ref"]] = vdu_scale_info.get("count", 1)
+                                cloud_init_list.append(
+                                    self._parse_cloud_init(
+                                        cloud_init_text,
+                                        additional_params,
+                                        db_vnfd["id"],
+                                        vdud["id"]
+                                    )
+                                )
+                        RO_scaling_info.append(
+                            {
+                                "osm_vdu_id": vdu_delta["id"],
+                                "member-vnf-index": vnf_index,
+                                "type": "create",
+                                "count": vdu_delta.get("number-of-instances", 1)
+                            }
+                        )
+                        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":
-                # count if min-instance-count is reached
-                min_instance_count = 0
                 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"])
-                if nb_scale_op <= 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))
-                nb_scale_op -= 1
+                
                 vdu_scaling_info["scaling_direction"] = "IN"
                 vdu_scaling_info["vdu-delete"] = {}
-                for vdu_scale_info in scaling_descriptor["vdu"]:
-                    RO_scaling_info.append({"osm_vdu_id": vdu_scale_info["vdu-id-ref"], "member-vnf-index": vnf_index,
-                                            "type": "delete", "count": vdu_scale_info.get("count", 1)})
-                    vdu_scaling_info["vdu-delete"][vdu_scale_info["vdu-id-ref"]] = vdu_scale_info.get("count", 1)
+                deltas = scaling_descriptor.get("aspect-delta-details")["deltas"]
+                for delta in deltas:
+                    for vdu_delta in delta["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"])
+
+                        nb_scale_op -= vdu_delta.get("number-of-instances", 1)
+                        if nb_scale_op + deafult_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)})
+                        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
             vdu_delete = copy(vdu_scaling_info.get("vdu-delete"))
@@ -3828,9 +3861,6 @@ class NsLcm(LcmBase):
                 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)
-                else:
-                    await self._RO_scale(logging_text, RO_nsr_id, RO_scaling_info, db_nslcmop, db_vnfr,
-                                         db_nslcmop_update, vdu_scaling_info)
             vdu_scaling_info.pop("vdu-create", None)
             vdu_scaling_info.pop("vdu-delete", None)
 
@@ -3969,18 +3999,17 @@ class NsLcm(LcmBase):
         db_vnfrs = {}
 
         # read from db: vnfd's for every vnf
-        db_vnfds = {}  # every vnfd data indexed by vnf id
-        db_vnfds = {}
+        db_vnfds = []
 
         # for each vnf in ns, read vnfd
         for vnfr in self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id}):
             db_vnfrs[vnfr["member-vnf-index-ref"]] = vnfr
             vnfd_id = vnfr["vnfd-id"]  # vnfd uuid for this vnf
             # if we haven't this vnfd, read it from db
-            if vnfd_id not in db_vnfds:
+            if not find_in_list(db_vnfds, lambda a_vnfd: a_vnfd["id"] == vnfd_id):
                 # read from db
                 vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
-                db_vnfds[vnfd_id] = vnfd  # vnfd's indexed by id
+                db_vnfds.append(vnfd)
         n2vc_key = self.n2vc.get_public_key()
         n2vc_key_list = [n2vc_key]
         self.scale_vnfr(db_vnfr, vdu_scaling_info.get("vdu-create"), vdu_scaling_info.get("vdu-delete"),
@@ -3993,115 +4022,6 @@ class NsLcm(LcmBase):
         if vdu_scaling_info.get("vdu-delete"):
             self.scale_vnfr(db_vnfr, None, vdu_scaling_info["vdu-delete"], mark_delete=False)
 
-    async def _RO_scale(self, logging_text, RO_nsr_id, RO_scaling_info, db_nslcmop, db_vnfr, db_nslcmop_update,
-                        vdu_scaling_info):
-        nslcmop_id = db_nslcmop["_id"]
-        nsr_id = db_nslcmop["nsInstanceId"]
-        vdu_create = vdu_scaling_info.get("vdu-create")
-        vdu_delete = vdu_scaling_info.get("vdu-delete")
-        # Scale RO retry check: Check if this sub-operation has been executed before
-        op_index = self._check_or_add_scale_suboperation(
-            db_nslcmop, db_vnfr["member-vnf-index-ref"], None, None, 'SCALE-RO', RO_nsr_id, RO_scaling_info)
-        if op_index == self.SUBOPERATION_STATUS_SKIP:
-            # Skip sub-operation
-            result = 'COMPLETED'
-            result_detail = 'Done'
-            self.logger.debug(logging_text + "Skipped sub-operation RO, result {} {}".format(result, result_detail))
-        else:
-            if op_index == self.SUBOPERATION_STATUS_NEW:
-                # New sub-operation: Get index of this sub-operation
-                op_index = len(db_nslcmop.get('_admin', {}).get('operations')) - 1
-                self.logger.debug(logging_text + "New sub-operation RO")
-            else:
-                # retry:  Get registered params for this existing sub-operation
-                op = db_nslcmop.get('_admin', {}).get('operations', [])[op_index]
-                RO_nsr_id = op.get('RO_nsr_id')
-                RO_scaling_info = op.get('RO_scaling_info')
-                self.logger.debug(logging_text + "Sub-operation RO retry")
-
-            RO_desc = await self.RO.create_action("ns", RO_nsr_id, {"vdu-scaling": RO_scaling_info})
-            # wait until ready
-            RO_nslcmop_id = RO_desc["instance_action_id"]
-            db_nslcmop_update["_admin.deploy.RO"] = RO_nslcmop_id
-
-            RO_task_done = False
-            step = detailed_status = "Waiting for VIM to scale. RO_task_id={}.".format(RO_nslcmop_id)
-            detailed_status_old = None
-            self.logger.debug(logging_text + step)
-
-            deployment_timeout = 1 * 3600  # One hour
-            while deployment_timeout > 0:
-                if not RO_task_done:
-                    desc = await self.RO.show("ns", item_id_name=RO_nsr_id, extra_item="action",
-                                              extra_item_id=RO_nslcmop_id)
-
-                    # deploymentStatus
-                    self._on_update_ro_db(nsrs_id=nsr_id, ro_descriptor=desc)
-
-                    ns_status, ns_status_info = self.RO.check_action_status(desc)
-                    if ns_status == "ERROR":
-                        raise ROclient.ROClientException(ns_status_info)
-                    elif ns_status == "BUILD":
-                        detailed_status = step + "; {}".format(ns_status_info)
-                    elif ns_status == "ACTIVE":
-                        RO_task_done = True
-                        self.scale_vnfr(db_vnfr, vdu_create=vdu_create, vdu_delete=vdu_delete)
-                        step = detailed_status = "Waiting ns ready at RO. RO_id={}".format(RO_nsr_id)
-                        self.logger.debug(logging_text + step)
-                    else:
-                        assert False, "ROclient.check_action_status returns unknown {}".format(ns_status)
-                else:
-                    desc = await self.RO.show("ns", RO_nsr_id)
-                    ns_status, ns_status_info = self.RO.check_ns_status(desc)
-                    # deploymentStatus
-                    self._on_update_ro_db(nsrs_id=nsr_id, ro_descriptor=desc)
-
-                    if ns_status == "ERROR":
-                        raise ROclient.ROClientException(ns_status_info)
-                    elif ns_status == "BUILD":
-                        detailed_status = step + "; {}".format(ns_status_info)
-                    elif ns_status == "ACTIVE":
-                        step = detailed_status = \
-                            "Waiting for management IP address reported by the VIM. Updating VNFRs"
-                        try:
-                            # nsr_deployed["nsr_ip"] = RO.get_ns_vnf_info(desc)
-                            self.ns_update_vnfr({db_vnfr["member-vnf-index-ref"]: db_vnfr}, desc)
-                            break
-                        except LcmExceptionNoMgmtIP:
-                            pass
-                    else:
-                        assert False, "ROclient.check_ns_status returns unknown {}".format(ns_status)
-                if detailed_status != detailed_status_old:
-                    self._update_suboperation_status(
-                        db_nslcmop, op_index, 'COMPLETED', detailed_status)
-                    detailed_status_old = db_nslcmop_update["detailed-status"] = detailed_status
-                    self.update_db_2("nslcmops", nslcmop_id, db_nslcmop_update)
-
-                await asyncio.sleep(5, loop=self.loop)
-                deployment_timeout -= 5
-            if deployment_timeout <= 0:
-                self._update_suboperation_status(
-                    db_nslcmop, nslcmop_id, op_index, 'FAILED', "Timeout when waiting for ns to get ready")
-                raise ROclient.ROClientException("Timeout waiting ns to be ready")
-
-            # update VDU_SCALING_INFO with the obtained ip_addresses
-            if vdu_scaling_info["scaling_direction"] == "OUT":
-                for vdur in reversed(db_vnfr["vdur"]):
-                    if vdu_scaling_info["vdu-create"].get(vdur["vdu-id-ref"]):
-                        vdu_scaling_info["vdu-create"][vdur["vdu-id-ref"]] -= 1
-                        vdu_scaling_info["vdu"].append({
-                            "name": vdur["name"] or vdur.get("vdu-name"),
-                            "vdu_id": vdur["vdu-id-ref"],
-                            "interface": []
-                        })
-                        for interface in vdur["interfaces"]:
-                            vdu_scaling_info["vdu"][-1]["interface"].append({
-                                "name": interface["name"],
-                                "ip_address": interface["ip-address"],
-                                "mac_address": interface.get("mac-address"),
-                            })
-            self._update_suboperation_status(db_nslcmop, op_index, 'COMPLETED', 'Done')
-
     async def add_prometheus_metrics(self, ee_id, artifact_path, ee_config_descriptor, vnfr_id, nsr_id, target_ip):
         if not self.prometheus:
             return