Feature 10922: Stop, start and rebuild 87/11987/7
authork4.rahul <rahul.k4@tataelxsi.co.in>
Mon, 2 May 2022 16:35:02 +0000 (16:35 +0000)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Tue, 21 Jun 2022 11:10:26 +0000 (13:10 +0200)
Added support for feature start stop rebuild of VNF instances
Added unit test case for feature start stop rebuild of VNF instances
Change-Id: I4a56fc116c998d0698be7e97118ce85207814b4b
Signed-off-by: k4.rahul <rahul.k4@tataelxsi.co.in>
osm_lcm/ng_ro.py
osm_lcm/ns.py
osm_lcm/tests/test_db_descriptors.py
osm_lcm/tests/test_ns.py

index 0acccc4..5dd3cc4 100644 (file)
@@ -156,6 +156,42 @@ class NgRoClient:
         except asyncio.TimeoutError:
             raise NgRoException("Timeout", http_code=504)
 
+    async def operate(self, nsr_id, target, operation_type):
+        """
+        Performs start/stop/rebuil of VNFs
+        :param nsr_id: NS Instance Id
+        :param target: payload data for migrate operation
+        :param operation_type: start/stop/rebuil of VNFs
+        :return: dictionary with the information or raises NgRoException on Error
+        """
+        try:
+            if isinstance(target, str):
+                target = self._parse_yaml(target)
+            payload_req = yaml.safe_dump(target)
+
+            url = "{}/ns/v1/{operation_type}/{nsr_id}".format(
+                self.endpoint_url, operation_type=operation_type, nsr_id=nsr_id
+            )
+            async with aiohttp.ClientSession(loop=self.loop) as session:
+                self.logger.debug("NG-RO POST %s %s", url, payload_req)
+                # timeout = aiohttp.ClientTimeout(total=self.timeout_large)
+                async with session.post(
+                    url, headers=self.headers_req, data=payload_req
+                ) as response:
+                    response_text = await response.read()
+                    self.logger.debug(
+                        "POST {} [{}] {}".format(
+                            url, response.status, response_text[:100]
+                        )
+                    )
+                    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 status(self, nsr_id, action_id):
         try:
             url = "{}/ns/v1/deploy/{nsr_id}/{action_id}".format(
index 5345d78..2e9c1bc 100644 (file)
@@ -133,7 +133,7 @@ class NsLcm(LcmBase):
         10 * 60
     )  # timeout for some progress in a primitive execution
     timeout_migrate = 1800  # default global timeout for migrating vnfs
-
+    timeout_operate = 1800  # default global timeout for migrating vnfs
     SUBOPERATION_STATUS_NOT_FOUND = -1
     SUBOPERATION_STATUS_NEW = -2
     SUBOPERATION_STATUS_SKIP = -3
@@ -5913,6 +5913,26 @@ class NsLcm(LcmBase):
                     )
                 )
 
+            elif update_type == "OPERATE_VNF":
+                vnf_id = db_nslcmop["operationParams"]["operateVnfData"]["vnfInstanceId"]
+                operation_type = db_nslcmop["operationParams"]["operateVnfData"]["changeStateTo"]
+                additional_param = db_nslcmop["operationParams"]["operateVnfData"]["additionalParam"]
+                (result, detailed_status) = await self.rebuild_start_stop(
+                    nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
+                    )
+                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.
             if not nslcmop_operation_state:
@@ -7202,6 +7222,79 @@ class NsLcm(LcmBase):
             job["vnfr_id"] = vnfr_id
         return job_list
 
+    async def rebuild_start_stop(self, nsr_id, nslcmop_id, vnf_id, additional_param, operation_type):
+        logging_text = "Task ns={} {}={} ".format(nsr_id, operation_type, nslcmop_id)
+        self.logger.info(logging_text + "Enter")
+        stage = ["Preparing the environment", ""]
+        # database nsrs record
+        db_nsr_update = {}
+        vdu_vim_name = None
+        vim_vm_id = None
+        # in case of error, indicates what part of scale was failed to put nsr at error status
+        start_deploy = time()
+        try:
+            db_vnfr = self.db.get_one("vnfrs", {"_id": vnf_id})
+            vim_account_id = db_vnfr.get("vim-account-id")
+            vim_info_key = "vim:" + vim_account_id
+            vdur = find_in_list(
+                db_vnfr["vdur"], lambda vdu: vdu["count-index"] == additional_param["count-index"]
+                )
+            if vdur:
+                vdu_vim_name = vdur["name"]
+                vim_vm_id = vdur["vim_info"][vim_info_key]["vim_id"]
+                target_vim, _ = next(k_v for k_v in vdur["vim_info"].items())
+            self.logger.info("vdu_vim_name >> {} ".format(vdu_vim_name))
+            # wait for any previous tasks in process
+            stage[1] = "Waiting for previous operations to terminate"
+            self.logger.info(stage[1])
+            await self.lcm_tasks.waitfor_related_HA('ns', 'nslcmops', nslcmop_id)
+
+            stage[1] = "Reading from database."
+            self.logger.info(stage[1])
+            self._write_ns_status(
+                nsr_id=nsr_id,
+                ns_state=None,
+                current_operation=operation_type.upper(),
+                current_operation_id=nslcmop_id
+            )
+            self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
+
+            # read from db: ns
+            stage[1] = "Getting nsr={} from db.".format(nsr_id)
+            db_nsr_update["operational-status"] = operation_type
+            self.update_db_2("nsrs", nsr_id, db_nsr_update)
+            # Payload for RO
+            desc = {
+                operation_type: {
+                    "vim_vm_id": vim_vm_id,
+                    "vnf_id": vnf_id,
+                    "vdu_index": additional_param["count-index"],
+                    "vdu_id": vdur["id"],
+                    "target_vim": target_vim,
+                    "vim_account_id": vim_account_id
+                }
+            }
+            stage[1] = "Sending rebuild request to RO... {}".format(desc)
+            self._write_op_status(op_id=nslcmop_id, stage=stage, queuePosition=0)
+            self.logger.info("ro nsr id: {}".format(nsr_id))
+            result_dict = await self.RO.operate(nsr_id, desc, operation_type)
+            self.logger.info("response from RO: {}".format(result_dict))
+            action_id = result_dict["action_id"]
+            await self._wait_ng_ro(
+                nsr_id, action_id, nslcmop_id, start_deploy, self.timeout_operate
+            )
+            return "COMPLETED", "Done"
+        except (ROclient.ROClientException, DbException, LcmException) as e:
+            self.logger.error("Exit Exception {}".format(e))
+            exc = e
+        except asyncio.CancelledError:
+            self.logger.error("Cancelled Exception while '{}'".format(stage))
+            exc = "Operation was cancelled"
+        except Exception as e:
+            exc = traceback.format_exc()
+            self.logger.critical("Exit Exception {} {}".format(type(e).__name__, e), exc_info=True)
+            return "FAILED", "Error in operate VNF {}".format(exc)
+
     def get_vca_cloud_and_credentials(self, vim_account_id: str) -> (str, str):
         """
         Get VCA Cloud and VCA Cloud Credentials for the VIM account
index 2e001c0..dbb3e1d 100644 (file)
@@ -349,6 +349,81 @@ db_nslcmops_text = """
     operationState: FAILED
     startTime: 1566823354.414689
     statusEnteredTime: 1566824534.5112448
+
+-   _id: 1bd4b60a-e15d-49e5-b75e-2b3224f15dda
+    id: 1bd4b60a-e15d-49e5-b75e-2b3224f15dda
+    operationState: COMPLETED
+    queuePosition: 0
+    stage: ''
+    errorMessage: ''
+    detailedStatus:
+    statusEnteredTime: 1652349205.9499352
+    nsInstanceId: 52f0b3ac-1574-481f-a48f-528fc02912f7
+    lcmOperationType: update
+    startTime: 1652349205.7415159
+    isAutomaticInvocation: false
+    operationParams:
+      updateType: OPERATE_VNF
+      operateVnfData:
+        vnfInstanceId: a6df8aa0-1271-4dfc-85a5-e0484fea303f
+        changeStateTo: start
+        additionalParam:
+          run-day1: false
+          vdu-id: mgmtVM
+          count-index: 0
+      lcmOperationType: update
+      nsInstanceId: 52f0b3ac-1574-481f-a48f-528fc02912f7
+    isCancelPending: false
+    links:
+      self: "/osm/nslcm/v1/ns_lcm_op_occs/1bd4b60a-e15d-49e5-b75e-2b3224f15dda"
+      nsInstance: "/osm/nslcm/v1/ns_instances/52f0b3ac-1574-481f-a48f-528fc02912f7"
+    _admin:
+      created: 1652349205.7415788
+      modified: 1652349205.9499364
+      projects_read:
+      - e38990e1-6724-4292-ab6f-2ecc109f9af4
+      projects_write:
+      - e38990e1-6724-4292-ab6f-2ecc109f9af4
+      worker: fbf6b5aa99e2
+    detailed-status: Done
+
+-   _id: 6eace44b-2ef4-4de5-b15f-63f2e8898bfb
+    id: 6eace44b-2ef4-4de5-b15f-63f2e8898bfb
+    operationState: Error
+    queuePosition: 0
+    stage: ''
+    errorMessage: ''
+    detailedStatus:
+    statusEnteredTime: 1652349205.9499352
+    nsInstanceId: 52f0b3ac-1574-481f-a48f-528fc02912f7
+    lcmOperationType: update
+    startTime: 1652349205.7415159
+    isAutomaticInvocation: false
+    operationParams:
+      updateType: OPERATE_VNF
+      operateVnfData:
+        vnfInstanceId: a6df8aa0-1271-4dfc-85a5-e0484fea303f
+        changeStateTo: stop
+        additionalParam:
+          run-day1: false
+          vdu-id: mgmtVM
+          count-index: 0
+      lcmOperationType: update
+      nsInstanceId: 52f0b3ac-1574-481f-a48f-528fc02912f7
+    isCancelPending: false
+    links:
+      self: "/osm/nslcm/v1/ns_lcm_op_occs/1bd4b60a-e15d-49e5-b75e-2b3224f15dda"
+      nsInstance: "/osm/nslcm/v1/ns_instances/52f0b3ac-1574-481f-a48f-528fc02912f7"
+    _admin:
+      created: 1652349205.7415788
+      modified: 1652349205.9499364
+      projects_read:
+      - e38990e1-6724-4292-ab6f-2ecc109f9af4
+      projects_write:
+      - e38990e1-6724-4292-ab6f-2ecc109f9af4
+      worker: fbf6b5aa99e2
+    detailed-status: Done
+
 """
 
 db_nsrs_text = """
@@ -2310,6 +2385,63 @@ db_vnfrs_text = """
     vim-account-id: 74337dcb-ef54-41e7-bd2d-8c0d7fcd326f
     vnfd-id: d96b1cdf-5ad6-49f7-bf65-907ada989293
     vnfd-ref: native-kdu_knf
+
+-   _id: a6df8aa0-1271-4dfc-85a5-e0484fea303f
+    id: a6df8aa0-1271-4dfc-85a5-e0484fea303f
+    nsr-id-ref: 52f0b3ac-1574-481f-a48f-528fc02912f7
+    member-vnf-index-ref: '1'
+    additionalParamsForVnf:
+    created-time: 1652105830.965044
+    vnfd-ref: ha_proxy_charm-vnf
+    vnfd-id: 8b42078a-9d42-4def-8b5d-7dd0f041d078
+    vim-account-id: dff4014e-bb5e-441a-a28d-6dd5d86c7175
+    vca-id:
+    vdur:
+    - _id: 392e010d-3a39-4516-acc0-76993c19691f
+      alt-image-ids:
+      - '1'
+      - '2'
+      - '3'
+      cloud-init: 8b42078a-9d42-4def-8b5d-7dd0f041d078:file:cloud-config.txt
+      count-index: 0
+      id: 392e010d-3a39-4516-acc0-76993c19691f
+      internal-connection-point:
+      - connection-point-id: mgmtVM-eth0-int
+        id: mgmtVM-eth0-int
+        name: mgmtVM-eth0-int
+      - connection-point-id: dataVM-xe0-int
+        id: dataVM-xe0-int
+        name: dataVM-xe0-int
+      ip-address: 10.45.28.134
+      ns-flavor-id: '0'
+      ns-image-id: '0'
+      ssh-access-required: true
+      vdu-id-ref: mgmtVM
+      vdu-name: mgmtVM
+      vim_info:
+        vim:05357241-1a01-416f-9e02-af20f65f51cd:
+          vim_id: 1f8c18e3-b3aa-484c-a211-e88d6654f24a
+          vim_status: ACTIVE
+          vim_name: test_ns_ch-1-mgmtVM-0
+      status: ACTIVE
+      vim-id: 1f8c18e3-b3aa-484c-a211-e88d6654f24a
+      name: test_ns_ch-1-mgmtVM-0
+      vim_details:
+      vim_id: 1f8c18e3-b3aa-484c-a211-e88d6654f24a
+      vim_status: DONE
+      vim_message:
+    ip-address: 10.45.28.134
+    _admin:
+      created: 1652105830.9652078
+      modified: 1652105830.9652078
+      projects_read:
+      - e38990e1-6724-4292-ab6f-2ecc109f9af4
+      projects_write:
+      - e38990e1-6724-4292-ab6f-2ecc109f9af4
+      nsState: INSTANTIATED
+    vdu:
+      status: DONE
+      vim-id: 1f8c18e3-b3aa-484c-a211-e88d6654f24a
 """
 
 db_nslcmops_scale_text = """
@@ -2417,4 +2549,10 @@ test_ids = {
         "vnf": "88d90b0c-faff-4b9f-bccd-017f33985984",
         "removeVnf": "a639fac7-e0bb-4225-8ecb-c1f8efcc125f",
     },
+    "TEST-OP-VNF": {
+        "ns": "f48163a6-c807-47bc-9682-f72caef5af85",
+        "nslcmops": "1bd4b60a-e15d-49e5-b75e-2b3224f15dda",
+        "nslcmops1": "6eace44b-2ef4-4de5-b15f-63f2e8898bfb",
+        "vnfrs": "a6df8aa0-1271-4dfc-85a5-e0484fea303f",
+    },
 }
index 5e248a2..466976c 100644 (file)
@@ -390,6 +390,38 @@ class TestMyNS(asynctest.TestCase):
     #     await self.test_instantiate()
     #     # this will check that the initial-congig-primitive 'not_to_be_called' is not called
 
+    @asynctest.fail_on(active_handles=True)
+    async def test_start_stop_rebuild_pass(self):
+        nsr_id = descriptors.test_ids["TEST-OP-VNF"]["ns"]
+        nslcmop_id = descriptors.test_ids["TEST-OP-VNF"]["nslcmops"]
+        vnf_id = descriptors.test_ids["TEST-OP-VNF"]["vnfrs"]
+        additional_param = {"count-index": "0"}
+        operation_type = "start"
+        await self.my_ns.rebuild_start_stop(
+            nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
+        )
+        expected_value = "COMPLETED"
+        return_value = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "operationState"
+        )
+        self.assertEqual(return_value, expected_value)
+
+    @asynctest.fail_on(active_handles=True)
+    async def test_start_stop_rebuild_fail(self):
+        nsr_id = descriptors.test_ids["TEST-OP-VNF"]["ns"]
+        nslcmop_id = descriptors.test_ids["TEST-OP-VNF"]["nslcmops1"]
+        vnf_id = descriptors.test_ids["TEST-OP-VNF"]["vnfrs"]
+        additional_param = {"count-index": "0"}
+        operation_type = "stop"
+        await self.my_ns.rebuild_start_stop(
+            nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
+        )
+        expected_value = "Error"
+        return_value = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "operationState"
+        )
+        self.assertEqual(return_value, expected_value)
+
     # Test scale() and related methods
     @asynctest.fail_on(active_handles=True)  # all async tasks must be completed
     async def test_scale(self):