Feature 11038: Enhancement of Vertical Scale Feature and merge in update API 89/14389/4
authorRahul Kumar <rahul.k4@tataelxsi.co.in>
Fri, 24 May 2024 09:11:41 +0000 (14:41 +0530)
committerrahulkumarr <rahul.k4@tataelxsi.co.in>
Fri, 28 Jun 2024 06:49:25 +0000 (12:19 +0530)
Change-Id: Id291cf9138aedbe4226abc6b6ab4cd5ecda48640
Signed-off-by: Rahul Kumar <rahul.k4@tataelxsi.co.in>
osm_lcm/lcm.py
osm_lcm/ns.py
osm_lcm/tests/test_ns.py

index f8a97ae..1c81da1 100644 (file)
@@ -499,21 +499,6 @@ class Lcm:
                 task = asyncio.ensure_future(self.ns.migrate(nsr_id, nslcmop_id))
                 self.lcm_tasks.register("ns", nsr_id, nslcmop_id, "ns_migrate", task)
                 return
-            elif command == "verticalscale":
-                nslcmop = params
-                nslcmop_id = nslcmop["_id"]
-                nsr_id = nslcmop["nsInstanceId"]
-                task = asyncio.ensure_future(self.ns.vertical_scale(nsr_id, nslcmop_id))
-                self.logger.debug(
-                    "nsr_id,nslcmop_id,task {},{},{}".format(nsr_id, nslcmop_id, task)
-                )
-                self.lcm_tasks.register(
-                    "ns", nsr_id, nslcmop_id, "ns_verticalscale", task
-                )
-                self.logger.debug(
-                    "LCM task registered {},{},{} ".format(nsr_id, nslcmop_id, task)
-                )
-                return
             elif command == "show":
                 nsr_id = params
                 try:
@@ -546,7 +531,6 @@ class Lcm:
                 "actioned",
                 "updated",
                 "migrated",
-                "verticalscaled",
             ):  # "scaled-cooldown-time"
                 return
 
index 1714985..ea57400 100644 (file)
@@ -6191,6 +6191,79 @@ class NsLcm(LcmBase):
                         nslcmop_operation_state, detailed_status
                     )
                 )
+            elif update_type == "VERTICAL_SCALE":
+                self.logger.debug(
+                    "Prepare for VERTICAL_SCALE update operation {}".format(db_nslcmop)
+                )
+                # Get the input parameters given through update request
+                vnf_instance_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
+                    "vnfInstanceId"
+                )
+
+                vnfd_id = db_nslcmop["operationParams"]["verticalScaleVnf"].get(
+                    "vnfdId"
+                )
+                step = "Getting vnfr from database"
+                db_vnfr = self.db.get_one(
+                    "vnfrs", {"_id": vnf_instance_id}, fail_on_empty=False
+                )
+                self.logger.debug(step)
+                step = "Getting vnfds from database"
+                self.logger.debug("Start" + step)
+                # Latest VNFD
+                latest_vnfd = self.db.get_one(
+                    "vnfds", {"_id": vnfd_id}, fail_on_empty=False
+                )
+                latest_vnfd_revision = latest_vnfd["_admin"].get("revision")
+                # Current VNFD
+                current_vnf_revision = db_vnfr.get("revision", 1)
+                current_vnfd = self.db.get_one(
+                    "vnfds_revisions",
+                    {"_id": vnfd_id + ":" + str(current_vnf_revision)},
+                    fail_on_empty=False,
+                )
+                self.logger.debug("End" + step)
+                # verify flavor changes
+                step = "Checking for flavor change"
+                if find_software_version(current_vnfd) != find_software_version(
+                    latest_vnfd
+                ):
+                    self.logger.debug("Start" + step)
+                    if current_vnfd.get("virtual-compute-desc") == latest_vnfd.get(
+                        "virtual-compute-desc"
+                    ) and current_vnfd.get("virtual-storage-desc") == latest_vnfd.get(
+                        "virtual-storage-desc"
+                    ):
+                        raise LcmException(
+                            "No change in flavor check vnfd {}".format(vnfd_id)
+                        )
+                else:
+                    raise LcmException(
+                        "No change in software_version of vnfd {}".format(vnfd_id)
+                    )
+
+                self.logger.debug("End" + step)
+
+                (result, detailed_status) = await self.vertical_scale(
+                    nsr_id, nslcmop_id
+                )
+                self.logger.debug(
+                    "vertical_scale result: {} detailed_status :{}".format(
+                        result, detailed_status
+                    )
+                )
+                if result == "FAILED":
+                    nslcmop_operation_state = result
+                    error_description_nslcmop = detailed_status
+                db_nslcmop_update["detailed-status"] = detailed_status
+                if not nslcmop_operation_state:
+                    nslcmop_operation_state = "COMPLETED"
+                self.logger.debug(
+                    logging_text
+                    + " task Done with result {} {}".format(
+                        nslcmop_operation_state, detailed_status
+                    )
+                )
 
             #  If nslcmop_operation_state is None, so any operation is not failed.
             #  All operations are executed in overall.
@@ -8872,20 +8945,11 @@ class NsLcm(LcmBase):
         :param: nslcmop_id: nslcmop ID of migrate
 
         """
-        # Try to lock HA task here
-        task_is_locked_by_me = self.lcm_tasks.lock_HA("ns", "nslcmops", nslcmop_id)
-        if not task_is_locked_by_me:
-            return
         logging_text = "Task ns={} vertical scale ".format(nsr_id)
-        self.logger.debug(logging_text + "Enter")
+        self.logger.info(logging_text + "Enter")
+        stage = ["Preparing the environment", ""]
         # get all needed from database
         db_nslcmop = None
-        db_nslcmop_update = {}
-        nslcmop_operation_state = None
-        old_db_update = {}
-        q_filter = {}
-        old_vdu_index = None
-        old_flavor_id = None
         db_nsr_update = {}
         target = {}
         exc = None
@@ -8893,79 +8957,113 @@ class NsLcm(LcmBase):
         start_deploy = time()
 
         try:
+            db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
+            operationParams = db_nslcmop.get("operationParams")
+            vertical_scale_data = operationParams["verticalScaleVnf"]
+            vnfd_id = vertical_scale_data["vnfdId"]
+            count_index = vertical_scale_data["countIndex"]
+            vdu_id_ref = vertical_scale_data["vduId"]
+            vnfr_id = vertical_scale_data["vnfInstanceId"]
+            db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
+            db_flavor = db_nsr.get("flavor")
+            db_flavor_index = str(len(db_flavor))
+
+            def set_flavor_refrence_to_vdur(diff=0):
+                """
+                Utility function to add and remove the
+                ref to new ns-flavor-id to vdurs
+                :param: diff: default 0
+                """
+                q_filter = {}
+                db_vnfr = self.db.get_one("vnfrs", {"_id": vnfr_id})
+                for vdu_index, vdur in enumerate(db_vnfr.get("vdur", ())):
+                    if (
+                        vdur.get("count-index") == count_index
+                        and vdur.get("vdu-id-ref") == vdu_id_ref
+                    ):
+                        filter_text = {
+                            "_id": vnfr_id,
+                            "vdur.count-index": count_index,
+                            "vdur.vdu-id-ref": vdu_id_ref,
+                        }
+                        q_filter.update(filter_text)
+                        db_update = {}
+                        db_update["vdur.{}.ns-flavor-id".format(vdu_index)] = str(
+                            int(db_flavor_index) - diff
+                        )
+                        self.db.set_one(
+                            "vnfrs",
+                            q_filter=q_filter,
+                            update_dict=db_update,
+                            fail_on_empty=True,
+                        )
+
             # wait for any previous tasks in process
-            step = "Waiting for previous operations to terminate"
+            stage[1] = "Waiting for previous operations to terminate"
             await self.lcm_tasks.waitfor_related_HA("ns", "nslcmops", nslcmop_id)
 
             self._write_ns_status(
                 nsr_id=nsr_id,
                 ns_state=None,
-                current_operation="VerticalScale",
+                current_operation="VERTICALSCALE",
                 current_operation_id=nslcmop_id,
             )
-            step = "Getting nslcmop from database"
+            self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
             self.logger.debug(
-                step + " after having waited for previous tasks to be completed"
+                stage[1] + " after having waited for previous tasks to be completed"
             )
-            db_nslcmop = self.db.get_one("nslcmops", {"_id": nslcmop_id})
-            operationParams = db_nslcmop.get("operationParams")
-            # Update the VNFRS and NSRS with the requested flavour detail, So that ro tasks can function properly
-            db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
-            db_flavor = db_nsr.get("flavor")
-            db_flavor_index = str(len(db_flavor))
-            change_vnf_flavor_data = operationParams["changeVnfFlavorData"]
-            flavor_dict = change_vnf_flavor_data["additionalParams"]
-            count_index = flavor_dict["vduCountIndex"]
-            vdu_id_ref = flavor_dict["vduid"]
+            self.update_db_2("nsrs", nsr_id, db_nsr_update)
+            vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
+            virtual_compute = vnfd["virtual-compute-desc"][0]
+            virtual_memory = round(
+                float(virtual_compute["virtual-memory"]["size"]) * 1024
+            )
+            virtual_cpu = virtual_compute["virtual-cpu"]["num-virtual-cpu"]
+            virtual_storage = vnfd["virtual-storage-desc"][0]["size-of-storage"]
             flavor_dict_update = {
                 "id": db_flavor_index,
-                "memory-mb": flavor_dict["virtualMemory"],
+                "memory-mb": virtual_memory,
                 "name": f"{vdu_id_ref}-{count_index}-flv",
-                "storage-gb": flavor_dict["sizeOfStorage"],
-                "vcpu-count": flavor_dict["numVirtualCpu"],
+                "storage-gb": str(virtual_storage),
+                "vcpu-count": virtual_cpu,
             }
             db_flavor.append(flavor_dict_update)
             db_update = {}
             db_update["flavor"] = db_flavor
-            ns_q_filter = {
+            q_filter = {
                 "_id": nsr_id,
             }
+            # Update the VNFRS and NSRS with the requested flavour detail, So that ro tasks can function properly
             self.db.set_one(
                 "nsrs",
-                q_filter=ns_q_filter,
+                q_filter=q_filter,
                 update_dict=db_update,
                 fail_on_empty=True,
             )
-            db_vnfr = self.db.get_one(
-                "vnfrs", {"_id": change_vnf_flavor_data["vnfInstanceId"]}
-            )
-            for vdu_index, vdur in enumerate(db_vnfr.get("vdur", ())):
-                if (
-                    vdur.get("count-index") == count_index
-                    and vdur.get("vdu-id-ref") == vdu_id_ref
-                ):
-                    old_flavor_id = vdur.get("ns-flavor-id", 0)
-                    old_vdu_index = vdu_index
-                    filter_text = {
-                        "_id": change_vnf_flavor_data["vnfInstanceId"],
-                        "vdur.count-index": count_index,
-                        "vdur.vdu-id-ref": vdu_id_ref,
-                    }
-                    q_filter.update(filter_text)
-                    db_update = {}
-                    db_update[
-                        "vdur.{}.ns-flavor-id".format(vdu_index)
-                    ] = db_flavor_index
-                    self.db.set_one(
-                        "vnfrs",
-                        q_filter=q_filter,
-                        update_dict=db_update,
-                        fail_on_empty=True,
-                    )
+            set_flavor_refrence_to_vdur()
             target = {}
-            target.update(operationParams)
+            new_operationParams = {
+                "lcmOperationType": "verticalscale",
+                "verticalScale": "CHANGE_VNFFLAVOR",
+                "nsInstanceId": nsr_id,
+                "changeVnfFlavorData": {
+                    "vnfInstanceId": vnfr_id,
+                    "additionalParams": {
+                        "vduid": vdu_id_ref,
+                        "vduCountIndex": count_index,
+                        "virtualMemory": virtual_memory,
+                        "numVirtualCpu": int(virtual_cpu),
+                        "sizeOfStorage": int(virtual_storage),
+                    },
+                },
+            }
+            target.update(new_operationParams)
+
+            stage[1] = "Sending vertical scale request to RO... {}".format(target)
+            self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
+            self.logger.info("RO target > {}".format(target))
             desc = await self.RO.vertical_scale(nsr_id, target)
-            self.logger.debug("RO return > {}".format(desc))
+            self.logger.info("RO.vertical_scale return value - {}".format(desc))
             action_id = desc["action_id"]
             await self._wait_ng_ro(
                 nsr_id,
@@ -8984,7 +9082,7 @@ class NsLcm(LcmBase):
             self.logger.error("Exit Exception {}".format(e))
             exc = e
         except asyncio.CancelledError:
-            self.logger.error("Cancelled Exception while '{}'".format(step))
+            self.logger.error("Cancelled Exception while '{}'".format(stage))
             exc = "Operation was cancelled"
         except Exception as e:
             exc = traceback.format_exc()
@@ -8992,51 +9090,17 @@ class NsLcm(LcmBase):
                 "Exit Exception {} {}".format(type(e).__name__, e), exc_info=True
             )
         finally:
-            self._write_ns_status(
-                nsr_id=nsr_id,
-                ns_state=None,
-                current_operation="IDLE",
-                current_operation_id=None,
-            )
             if exc:
-                db_nslcmop_update["detailed-status"] = "FAILED {}: {}".format(step, exc)
-                nslcmop_operation_state = "FAILED"
-                old_db_update[
-                    "vdur.{}.ns-flavor-id".format(old_vdu_index)
-                ] = old_flavor_id
-            else:
-                nslcmop_operation_state = "COMPLETED"
-                db_nslcmop_update["detailed-status"] = "Done"
-                db_nsr_update["detailed-status"] = "Done"
-
-            self._write_op_status(
-                op_id=nslcmop_id,
-                stage="",
-                error_message="",
-                operation_state=nslcmop_operation_state,
-                other_update=db_nslcmop_update,
-            )
-            if old_vdu_index and old_db_update != {}:
                 self.logger.critical(
-                    "Reverting Old Flavor -- : {}".format(old_db_update)
+                    "Vertical-Scale operation Failed, cleaning up nsrs and vnfrs flavor detail"
                 )
                 self.db.set_one(
-                    "vnfrs",
-                    q_filter=q_filter,
-                    update_dict=old_db_update,
-                    fail_on_empty=True,
+                    "nsrs",
+                    {"_id": nsr_id},
+                    None,
+                    pull={"flavor": {"id": db_flavor_index}},
                 )
-            if nslcmop_operation_state:
-                try:
-                    msg = {
-                        "nsr_id": nsr_id,
-                        "nslcmop_id": nslcmop_id,
-                        "operationState": nslcmop_operation_state,
-                    }
-                    await self.msg.aiowrite("ns", "verticalscaled", msg)
-                except Exception as e:
-                    self.logger.error(
-                        logging_text + "kafka_write notification Exception {}".format(e)
-                    )
-            self.logger.debug(logging_text + "Exit")
-            self.lcm_tasks.remove("ns", nsr_id, nslcmop_id, "ns_verticalscale")
+                set_flavor_refrence_to_vdur(diff=1)
+                return "FAILED", "Error in verticalscale VNF {}".format(exc)
+            else:
+                return "COMPLETED", "Done"
index 931551d..3415fa1 100644 (file)
@@ -783,39 +783,6 @@ class TestMyNS(TestBaseNS):
                 in str(context.exception)
             )
 
-    # test vertical scale executes sucessfully
-    # @patch("osm_lcm.ng_ro.status.response")
-    @asynctest.fail_on(active_handles=True)
-    async def test_vertical_scaling(self):
-        nsr_id = descriptors.test_ids["TEST-V-SCALE"]["ns"]
-        nslcmop_id = descriptors.test_ids["TEST-V-SCALE"]["instantiate"]
-
-        # calling the vertical scale fucntion
-        # self.my_ns.RO.status = asynctest.CoroutineMock(self.my_ns.RO.status, side_effect=self._ro_status("update"))
-        mock_wait_ng_ro = asynctest.CoroutineMock()
-        with patch("osm_lcm.ns.NsLcm._wait_ng_ro", mock_wait_ng_ro):
-            await self.my_ns.vertical_scale(nsr_id, nslcmop_id)
-            return_value = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
-                "operationState"
-            )
-            expected_value = "COMPLETED"
-            self.assertNotEqual(return_value, expected_value)
-
-    # test vertical scale executes fail
-    @asynctest.fail_on(active_handles=True)
-    async def test_vertical_scaling_fail(self):
-        # get th nsr nad nslcmops id from descriptors
-        nsr_id = descriptors.test_ids["TEST-V-SCALE"]["ns"]
-        nslcmop_id = descriptors.test_ids["TEST-V-SCALE"]["instantiate-1"]
-
-        # calling the vertical scale fucntion
-        await self.my_ns.vertical_scale(nsr_id, nslcmop_id)
-        return_value = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
-            "operationState"
-        )
-        expected_value = "FAILED"
-        self.assertEqual(return_value, expected_value)
-
     # async def test_instantiate_pdu(self):
     #     nsr_id = descriptors.test_ids["TEST-A"]["ns"]
     #     nslcmop_id = descriptors.test_ids["TEST-A"]["instantiate"]