Feature 11052: support for opening a console for vCenter 82/15182/7
authorIsabel Lloret <illoret@indra.es>
Fri, 25 Apr 2025 09:27:11 +0000 (11:27 +0200)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Mon, 23 Jun 2025 15:32:55 +0000 (17:32 +0200)
Change-Id: I63b09dc23b7fd03fd2c68219cb46b6d2e8987f42
Signed-off-by: Isabel Lloret <illoret@indra.es>
osm_lcm/ng_ro.py
osm_lcm/ns.py

index 9426488..8570d52 100644 (file)
@@ -206,6 +206,32 @@ class NgRoClient:
                             url, response.status, response_text[:100]
                         )
                     )
+                    self.logger.debug("Get response text: %s", response_text)
+                    if response.status >= 300:
+                        raise NgRoException(response_text, http_code=response.status)
+                    return self._parse_yaml(response_text, response=True)
+
+        except (aiohttp.ClientOSError, aiohttp.ClientError) as e:
+            raise NgRoException(e, http_code=504)
+        except asyncio.TimeoutError:
+            raise NgRoException("Timeout", http_code=504)
+
+    async def get_action_vim_info(self, nsr_id, action_id):
+        try:
+            url = "{}/ns/v1/deploy/{nsr_id}/{action_id}/viminfo".format(
+                self.endpoint_url, nsr_id=nsr_id, action_id=action_id
+            )
+            async with aiohttp.ClientSession() as session:
+                self.logger.debug("GET %s", url)
+                # timeout = aiohttp.ClientTimeout(total=self.timeout_short)
+                async with session.get(url, headers=self.headers_req) as response:
+                    response_text = await response.read()
+                    self.logger.debug(
+                        "GET {} [{}] {}".format(
+                            url, response.status, response_text[:100]
+                        )
+                    )
+                    self.logger.debug("Get response text: %s", response_text)
                     if response.status >= 300:
                         raise NgRoException(response_text, http_code=response.status)
                     return self._parse_yaml(response_text, response=True)
index 8906e2a..b2c1c08 100644 (file)
@@ -217,6 +217,7 @@ class NsLcm(LcmBase):
             "healing": self.RO.recreate_status,
             "verticalscale": self.RO.status,
             "start_stop_rebuild": self.RO.status,
+            "console": self.RO.status,
         }
 
     @staticmethod
@@ -6300,9 +6301,23 @@ class NsLcm(LcmBase):
                 additional_param = db_nslcmop["operationParams"]["operateVnfData"][
                     "additionalParam"
                 ]
-                (result, detailed_status) = await self.rebuild_start_stop(
+                self.logger.debug(
+                    "Operate VNF, operation_type: %s, params: %s",
+                    operation_type,
+                    additional_param,
+                )
+                (
+                    result,
+                    detailed_status,
+                    operation_result_data,
+                ) = await self.process_operate_vnf(
                     nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
                 )
+                self.logger.debug("operation_result_data: %s", operation_result_data)
+                # In case the operation has a result store it in the ddbb
+                if operation_result_data:
+                    db_nslcmop_update["operationResultData"] = operation_result_data
+
                 if result == "FAILED":
                     nslcmop_operation_state = result
                     error_description_nslcmop = detailed_status
@@ -7910,6 +7925,126 @@ class NsLcm(LcmBase):
             job["vnfr_id"] = vnfr_id
         return job_list
 
+    async def process_operate_vnf(
+        self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
+    ):
+        self.logger.debug("Process operate vnf, operation_type: %s", operation_type)
+        operations = {"console": self.get_console_operation}
+        default_operation = self.rebuild_start_stop
+
+        operation_func = operations.get(operation_type, default_operation)
+        if callable(operation_func):
+            result = await operation_func(
+                nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
+            )
+            if len(result) == 2:
+                result = (*result, None)
+            return result
+        return "FAILED", f"Unknown operation type: {operation_type}", None
+
+    async def get_console_operation(
+        self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
+    ):
+        self.logger.debug(
+            "Get console operation, nsr_id: %s, nslcmop_id: %s, vnf_id: %s, additional_param: %s, operation_type: %s",
+            nsr_id,
+            nslcmop_id,
+            vnf_id,
+            additional_param,
+            operation_type,
+        )
+        status = "PROCESSING"
+        detailed_status = ""
+        start_deploy = time()
+        try:
+            # Obtain vnf data from database
+            operation_data = self._get_vdu_operation_data(
+                vnf_id, additional_param["count-index"], additional_param["vdu_id"]
+            )
+            self.logger.debug("Operation data: %s", operation_data)
+
+            # Execute operation
+            desc = {"console": operation_data}
+            result_dict = await self.RO.operate(nsr_id, desc, operation_type)
+            self.logger.debug("Result dict: %s", result_dict)
+
+            # Wait for response
+            action_id = result_dict["action_id"]
+            await self._wait_ng_ro(
+                nsr_id,
+                action_id,
+                nslcmop_id,
+                start_deploy,
+                self.timeout.operate,
+                None,
+                "console",
+            )
+
+            # Obtain the console vim data
+            result_vim_info = await self.RO.get_action_vim_info(nsr_id, action_id)
+            self.logger.debug("Result vim info: %s", result_vim_info)
+            console_data = None
+            if result_vim_info.get("vim_info_list"):
+                for vim_info in result_vim_info.get("vim_info_list"):
+                    if vim_info.get("vim_console_data"):
+                        console_data = vim_info.get("vim_console_data")
+
+            self.logger.debug("console_data: %s", console_data)
+            if not console_data:
+                raise ROclient.ROClientException("console data not properly returned")
+
+            return "COMPLETED", "Done", console_data
+
+        except (ROclient.ROClientException, DbException, LcmException) as e:
+            self.logger.error("Exit Exception {}".format(e))
+            status = "FAILED"
+            detailed_status = str(e)
+        except asyncio.CancelledError:
+            self.logger.error("Cancelled Exception obtaining console data")
+            exc = "Operation was cancelled"
+            status = "FAILED"
+            detailed_status = exc
+        except Exception as e:
+            exc = traceback.format_exc()
+            self.logger.critical(
+                "Processing get_console_operation, end operation Exception {} {}".format(
+                    type(e).__name__, e
+                ),
+                exc_info=True,
+            )
+            status = "FAILED"
+            detailed_status = "Error in operate VNF {}".format(exc)
+
+        return status, detailed_status
+
+    def _get_vdu_operation_data(self, vnf_id, count_index, vdu_id):
+        """
+        Obtains vdu required data from database
+        """
+        operation_data = {"vnf_id": vnf_id, "vdu_index": count_index}
+        # Obtain vnf from the database
+        db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
+
+        self.logger.debug("db_vnfr: %s", db_vnfr)
+        # Obtain additional data and vdu data
+        vim_account_id = db_vnfr.get("vim-account-id")
+        vim_info_key = "vim:" + vim_account_id
+        vdurs = [item for item in db_vnfr["vdur"] if item["vdu-id-ref"] == vdu_id]
+        vdur = find_in_list(vdurs, lambda vdu: vdu["count-index"] == count_index)
+        self.logger.debug("vdur: %s", vdur)
+        if vdur:
+            vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
+            target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
+        else:
+            raise LcmException("Target vdu is not found")
+
+        # Store all the needed data for the operation
+        operation_data["vim_vm_id"] = vim_vm_id
+        operation_data["vdu_id"] = vdur["id"]
+        operation_data["target_vim"] = target_vim
+        operation_data["vim_account_id"] = vim_account_id
+        return operation_data
+
     async def rebuild_start_stop(
         self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
     ):