Fix age key generation to convert pubkey to string
[osm/NBI.git] / osm_nbi / instance_topics.py
index 6072267..6308e56 100644 (file)
@@ -30,7 +30,7 @@ from osm_nbi.validation import (
     ns_heal,
     nsi_instantiate,
     ns_migrate,
-    ns_verticalscale,
+    nslcmop_cancel,
 )
 from osm_nbi.base_topic import (
     BaseTopic,
@@ -119,6 +119,24 @@ class NsrTopic(BaseTopic):
                     "nsds", {"_id": used_nsd_id}, {"_admin.usageState": "NOT_IN_USE"}
                 )
 
+        # Set NS CONFIG TEMPLATE usageState
+        if nsr.get("instantiate_params", {}).get("nsConfigTemplateId"):
+            nsconfigtemplate_id = nsr.get("instantiate_params", {}).get(
+                "nsConfigTemplateId"
+            )
+            nsconfigtemplate_list = self.db.get_one(
+                "nsrs",
+                {"instantiate_params.nsConfigTemplateId": nsconfigtemplate_id},
+                fail_on_empty=False,
+                fail_on_more=False,
+            )
+            if not nsconfigtemplate_list:
+                self.db.set_one(
+                    "ns_config_template",
+                    {"_id": nsconfigtemplate_id},
+                    {"_admin.usageState": "NOT_IN_USE"},
+                )
+
         # Set VNFD usageState
         used_vnfd_id_list = nsr.get("vnfd-id")
         if used_vnfd_id_list:
@@ -324,6 +342,38 @@ class NsrTopic(BaseTopic):
             nsd = self._get_nsd_from_db(ns_request["nsdId"], session)
             ns_k8s_namespace = self._get_ns_k8s_namespace(nsd, ns_request, session)
 
+            # Uploading the instantiation parameters to ns_request from ns config template
+            if ns_request.get("nsConfigTemplateId"):
+                step = "getting ns_config_template is='{}' from database".format(
+                    ns_request.get("nsConfigTemplateId")
+                )
+                ns_config_template_db = self._get_nsConfigTemplate_from_db(
+                    ns_request.get("nsConfigTemplateId"), session
+                )
+                ns_config_params = ns_config_template_db.get("config")
+                for key, value in ns_config_params.items():
+                    if key == "vnf":
+                        ns_request["vnf"] = ns_config_params.get("vnf")
+                    elif key == "additionalParamsForVnf":
+                        ns_request["additionalParamsForVnf"] = ns_config_params.get(
+                            "additionalParamsForVnf"
+                        )
+                    elif key == "additionalParamsForNs":
+                        ns_request["additionalParamsForNs"] = ns_config_params.get(
+                            "additionalParamsForNs"
+                        )
+                    elif key == "vld":
+                        ns_request["vld"] = ns_config_params.get("vld")
+                step = "checking ns_config_templateOperationalState"
+                self._check_ns_config_template_operational_state(
+                    ns_config_template_db, ns_request
+                )
+
+                step = "Updating NSCONFIG TEMPLATE usageState"
+                update_descriptor_usage_state(
+                    ns_config_template_db, "ns_config_template", self.db
+                )
+
             step = "checking nsdOperationalState"
             self._check_nsd_operational_state(nsd, ns_request)
 
@@ -399,6 +449,14 @@ class NsrTopic(BaseTopic):
         _filter["_id"] = nsd_id
         return self.db.get_one("nsds", _filter)
 
+    def _get_nsConfigTemplate_from_db(self, nsConfigTemplate_id, session):
+        _filter = self._get_project_filter(session)
+        _filter["_id"] = nsConfigTemplate_id
+        ns_config_template_db = self.db.get_one(
+            "ns_config_template", _filter, fail_on_empty=False
+        )
+        return ns_config_template_db
+
     def _get_vnfd_from_db(self, vnfd_id, session):
         _filter = self._get_project_filter(session)
         _filter["id"] = vnfd_id
@@ -427,6 +485,16 @@ class NsrTopic(BaseTopic):
                 http_code=HTTPStatus.CONFLICT,
             )
 
+    def _check_ns_config_template_operational_state(
+        self, ns_config_template_db, ns_request
+    ):
+        if ns_config_template_db["_admin"]["operationalState"] == "DISABLED":
+            raise EngineException(
+                "ns_config_template with id '{}' is DISABLED, and thus cannot be used to create "
+                "a network service".format(ns_request["nsConfigTemplateId"]),
+                http_code=HTTPStatus.CONFLICT,
+            )
+
     def _get_ns_k8s_namespace(self, nsd, ns_request, session):
         additional_params, _ = self._format_additional_params(
             ns_request, descriptor=nsd
@@ -561,6 +629,7 @@ class NsrTopic(BaseTopic):
             "image": [],
             "affinity-or-anti-affinity-group": [],
             "shared-volumes": [],
+            "vnffgd": [],
         }
         if "revision" in nsd["_admin"]:
             nsr_descriptor["revision"] = nsd["_admin"]["revision"]
@@ -640,6 +709,17 @@ class NsrTopic(BaseTopic):
                 )
                 vld["name"] = vld["id"]
             nsr_descriptor["vld"] = nsr_vld
+        if nsd.get("vnffgd"):
+            vnffgd = nsd.get("vnffgd")
+            for vnffg in vnffgd:
+                info = {}
+                for k, v in vnffg.items():
+                    if k == "id":
+                        info.update({k: v})
+                    if k == "nfpd":
+                        info.update({k: v})
+                nsr_descriptor["vnffgd"].append(info)
+
         return nsr_descriptor
 
     def _get_affinity_or_anti_affinity_group_data_from_vnfd(
@@ -1201,7 +1281,7 @@ class NsLcmOpTopic(BaseTopic):
         "heal": ns_heal,
         "terminate": ns_terminate,
         "migrate": ns_migrate,
-        "verticalscale": ns_verticalscale,
+        "cancel": nslcmop_cancel,
     }
 
     def __init__(self, db, fs, msg, auth):
@@ -1326,6 +1406,11 @@ class NsLcmOpTopic(BaseTopic):
         If updateType is REMOVE_VNF:
         - it checks if the vnfInstanceId is available in the ns instance
         - Otherwise exception will be raised.
+        If updateType is OPERATE_VNF
+        - it checks if the vdu-id is persent in the descriptor or not
+        - it checks if the changeStateTo is either start, stop or rebuild
+        If updateType is VERTICAL_SCALE
+        - it checks if the vdu-id is persent in the descriptor or not
 
         Args:
             indata: includes updateType such as CHANGE_VNFPKG,
@@ -1392,6 +1477,36 @@ class NsLcmOpTopic(BaseTopic):
                         "Invalid VNF Instance Id. '{}' is not "
                         "present in the NS '{}'".format(vnf_instance_id, ns_instance_id)
                     )
+            elif indata["updateType"] == "OPERATE_VNF":
+                if indata.get("operateVnfData"):
+                    if indata["operateVnfData"]["changeStateTo"] not in (
+                        "start",
+                        "stop",
+                        "rebuild",
+                    ):
+                        raise EngineException(
+                            f"The operate type should be either start, stop or rebuild not {indata['operateVnfData']['changeStateTo']}",
+                            http_code=HTTPStatus.UNPROCESSABLE_ENTITY,
+                        )
+                    if indata["operateVnfData"].get("additionalParam"):
+                        vdu_id = indata["operateVnfData"]["additionalParam"]["vdu_id"]
+                        vnfinstance_id = indata["operateVnfData"]["vnfInstanceId"]
+                        vnf = self.db.get_one("vnfrs", {"_id": vnfinstance_id})
+                        vnfd_member_vnf_index = vnf.get("member-vnf-index-ref")
+                        vnfd = self._get_vnfd_from_vnf_member_index(
+                            vnfd_member_vnf_index, nsr["_id"]
+                        )
+                        self._check_valid_vdu(vnfd, vdu_id)
+            elif indata["updateType"] == "VERTICAL_SCALE":
+                if indata.get("verticalScaleVnf"):
+                    vdu_id = indata["verticalScaleVnf"]["vduId"]
+                    vnfinstance_id = indata["verticalScaleVnf"]["vnfInstanceId"]
+                    vnf = self.db.get_one("vnfrs", {"_id": vnfinstance_id})
+                    vnfd_member_vnf_index = vnf.get("member-vnf-index-ref")
+                    vnfd = self._get_vnfd_from_vnf_member_index(
+                        vnfd_member_vnf_index, nsr["_id"]
+                    )
+                    self._check_valid_vdu(vnfd, vdu_id)
 
         except (
             DbException,
@@ -2264,6 +2379,7 @@ class NsLcmOpTopic(BaseTopic):
                     return (
                         None,
                         None,
+                        None,
                     )  # a none in this case is used to indicate not instantiated. It can be removed
                 if operation != "instantiate":
                     raise EngineException(
@@ -2311,7 +2427,6 @@ class NsLcmOpTopic(BaseTopic):
                     new_sw_version = vnfd.get("software-version", "1.0")
                     if new_sw_version != old_sw_version:
                         vnf_index = vnfr["member-vnf-index-ref"]
-                        self.logger.info("nsr {}".format(nsr))
                         for vdu in vnfd["vdu"]:
                             self.nsrtopic._add_shared_volumes_to_nsr(
                                 vdu, vnfd, nsr, vnf_index, latest_vnfd_revision
@@ -2352,6 +2467,7 @@ class NsLcmOpTopic(BaseTopic):
                         indata["newVdur"] = vnfr_descriptor["vdur"]
             nslcmop_desc = self._create_nslcmop(nsInstanceId, operation, indata)
             _id = nslcmop_desc["_id"]
+            nsName = nsr.get("name")
             self.format_on_new(
                 nslcmop_desc, session["project_id"], make_public=session["public"]
             )
@@ -2364,12 +2480,47 @@ class NsLcmOpTopic(BaseTopic):
             rollback.append({"topic": "nslcmops", "_id": _id})
             if not slice_object:
                 self.msg.write("ns", operation, nslcmop_desc)
-            return _id, None
+            return _id, nsName, None
         except ValidationError as e:  # TODO remove try Except, it is captured at nbi.py
             raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
         # except DbException as e:
         #     raise EngineException("Cannot get ns_instance '{}': {}".format(e), HTTPStatus.NOT_FOUND)
 
+    def cancel(self, rollback, session, indata=None, kwargs=None, headers=None):
+        validate_input(indata, self.operation_schema["cancel"])
+        # Override descriptor with query string kwargs
+        self._update_input_with_kwargs(indata, kwargs, yaml_format=True)
+        nsLcmOpOccId = indata["nsLcmOpOccId"]
+        cancelMode = indata["cancelMode"]
+        # get nslcmop from nsLcmOpOccId
+        _filter = BaseTopic._get_project_filter(session)
+        _filter["_id"] = nsLcmOpOccId
+        nslcmop = self.db.get_one("nslcmops", _filter)
+        # Fail is this is not an ongoing nslcmop
+        if nslcmop.get("operationState") not in [
+            "STARTING",
+            "PROCESSING",
+            "ROLLING_BACK",
+        ]:
+            raise EngineException(
+                "Operation is not in STARTING, PROCESSING or ROLLING_BACK state",
+                http_code=HTTPStatus.CONFLICT,
+            )
+        nsInstanceId = nslcmop["nsInstanceId"]
+        update_dict = {
+            "isCancelPending": True,
+            "cancelMode": cancelMode,
+        }
+        self.db.set_one(
+            "nslcmops", q_filter=_filter, update_dict=update_dict, fail_on_empty=False
+        )
+        data = {
+            "_id": nsLcmOpOccId,
+            "nsInstanceId": nsInstanceId,
+            "cancelMode": cancelMode,
+        }
+        self.msg.write("nslcmops", "cancel", data)
+
     def delete(self, session, _id, dry_run=False, not_send_msg=None):
         raise EngineException(
             "Method delete called directly", HTTPStatus.INTERNAL_SERVER_ERROR
@@ -2699,9 +2850,9 @@ class NsiTopic(BaseTopic):
         except ValidationError as e:
             raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
         except Exception as e:  # TODO remove try Except, it is captured at nbi.py
-            self.logger.exception(
-                "Exception {} at NsiTopic.new()".format(e), exc_info=True
-            )
+            self.logger.exception(
+            #    "Exception {} at NsiTopic.new()".format(e), exc_info=True
+            )
             raise EngineException("Error {}: {}".format(step, e))
 
     def edit(self, session, _id, indata=None, kwargs=None, content=None):
@@ -2827,7 +2978,7 @@ class NsiLcmOpTopic(BaseTopic):
             _filter = self._get_project_filter(session)
             _filter["_id"] = netsliceInstanceId
             nsir = self.db.get_one("nsis", _filter)
-            logging_prefix = "nsi={} {} ".format(netsliceInstanceId, operation)
+            logging_prefix = "nsi={} {} ".format(netsliceInstanceId, operation)
             del _filter["_id"]
 
             # initial checking
@@ -2922,7 +3073,7 @@ class NsiLcmOpTopic(BaseTopic):
 
                     # Creating NS_LCM_OP with the flag slice_object=True to not trigger the service instantiation
                     # message via kafka bus
-                    nslcmop, _ = self.nsi_NsLcmOpTopic.new(
+                    nslcmop, _, _ = self.nsi_NsLcmOpTopic.new(
                         rollback, session, indata_ns, None, headers, slice_object=True
                     )
                     nslcmops.append(nslcmop)
@@ -2935,10 +3086,6 @@ class NsiLcmOpTopic(BaseTopic):
                         self.db.set_one("nsis", {"_id": nsir["_id"]}, _update)
                 except (DbException, EngineException) as e:
                     if e.http_code == HTTPStatus.NOT_FOUND:
-                        self.logger.info(
-                            logging_prefix
-                            + "skipping NS={} because not found".format(nsr_id)
-                        )
                         pass
                     else:
                         raise