Added KDU actions to VnfTopic 90/8290/6
authordelacruzramo <pedro.delacruzramos@altran.com>
Mon, 2 Dec 2019 20:00:37 +0000 (21:00 +0100)
committerdelacruzramo <pedro.delacruzramos@altran.com>
Mon, 24 Feb 2020 17:53:35 +0000 (17:53 +0000)
Change-Id: I2797a7b470f84a445bc9b648701112969f8790e6
Signed-off-by: delacruzramo <pedro.delacruzramos@altran.com>
osm_nbi/descriptor_topics.py
osm_nbi/engine.py
osm_nbi/nbi.py
osm_nbi/resources_to_operations.yml
osm_nbi/validation.py

index bcd6a03..c1c1f63 100644 (file)
@@ -21,7 +21,10 @@ from hashlib import md5
 from osm_common.dbbase import DbException, deep_update_rfc7396
 from http import HTTPStatus
 from time import time
 from osm_common.dbbase import DbException, deep_update_rfc7396
 from http import HTTPStatus
 from time import time
-from osm_nbi.validation import ValidationError, pdu_new_schema, pdu_edit_schema
+from uuid import uuid4
+from re import fullmatch
+from osm_nbi.validation import ValidationError, pdu_new_schema, pdu_edit_schema, \
+    validate_input, vnfpkgop_new_schema
 from osm_nbi.base_topic import BaseTopic, EngineException, get_iterable
 from osm_im.vnfd import vnfd as vnfd_im
 from osm_im.nsd import nsd as nsd_im
 from osm_nbi.base_topic import BaseTopic, EngineException, get_iterable
 from osm_im.vnfd import vnfd as vnfd_im
 from osm_im.nsd import nsd as nsd_im
@@ -690,6 +693,19 @@ class VnfdTopic(DescriptorTopic):
                         return True
             return False
 
                         return True
             return False
 
+    def delete_extra(self, session, _id, db_content, not_send_msg=None):
+        """
+        Deletes associate file system storage (via super)
+        Deletes associated vnfpkgops from database.
+        :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+        :param _id: server internal id
+        :param db_content: The database content of the descriptor
+        :return: None
+        :raises: FsException in case of error while deleting associated storage
+        """
+        super().delete_extra(session, _id, db_content, not_send_msg)
+        self.db.del_list("vnfpkgops", {"vnfPkgId": _id})
+
 
 class NsdTopic(DescriptorTopic):
     topic = "nsds"
 
 class NsdTopic(DescriptorTopic):
     topic = "nsds"
@@ -942,3 +958,97 @@ class PduTopic(BaseTopic):
         _filter["vdur.pdu-id"] = _id
         if self.db.get_list("vnfrs", _filter):
             raise EngineException("There is at least one VNF using this PDU", http_code=HTTPStatus.CONFLICT)
         _filter["vdur.pdu-id"] = _id
         if self.db.get_list("vnfrs", _filter):
             raise EngineException("There is at least one VNF using this PDU", http_code=HTTPStatus.CONFLICT)
+
+
+class VnfPkgOpTopic(BaseTopic):
+    topic = "vnfpkgops"
+    topic_msg = "vnfd"
+    schema_new = vnfpkgop_new_schema
+    schema_edit = None
+
+    def __init__(self, db, fs, msg, auth):
+        BaseTopic.__init__(self, db, fs, msg, auth)
+
+    def edit(self, session, _id, indata=None, kwargs=None, content=None):
+        raise EngineException("Method 'edit' not allowed for topic '{}'".format(self.topic),
+                              HTTPStatus.METHOD_NOT_ALLOWED)
+
+    def delete(self, session, _id, dry_run=False):
+        raise EngineException("Method 'delete' not allowed for topic '{}'".format(self.topic),
+                              HTTPStatus.METHOD_NOT_ALLOWED)
+
+    def delete_list(self, session, filter_q=None):
+        raise EngineException("Method 'delete_list' not allowed for topic '{}'".format(self.topic),
+                              HTTPStatus.METHOD_NOT_ALLOWED)
+
+    def new(self, rollback, session, indata=None, kwargs=None, headers=None):
+        """
+        Creates a new entry into database.
+        :param rollback: list to append created items at database in case a rollback may to be done
+        :param session: contains "username", "admin", "force", "public", "project_id", "set_project"
+        :param indata: data to be inserted
+        :param kwargs: used to override the indata descriptor
+        :param headers: http request headers
+        :return: _id, op_id:
+            _id: identity of the inserted data.
+             op_id: None
+        """
+        self._update_input_with_kwargs(indata, kwargs)
+        validate_input(indata, self.schema_new)
+        vnfpkg_id = indata["vnfPkgId"]
+        filter_q = BaseTopic._get_project_filter(session)
+        filter_q["_id"] = vnfpkg_id
+        vnfd = self.db.get_one("vnfds", filter_q)
+        operation = indata["lcmOperationType"]
+        kdu_name = indata["kdu_name"]
+        for kdu in vnfd.get("kdu", []):
+            if kdu["name"] == kdu_name:
+                helm_chart = kdu.get("helm-chart")
+                juju_bundle = kdu.get("juju-bundle")
+                break
+        else:
+            raise EngineException("Not found vnfd[id='{}']:kdu[name='{}']".format(vnfpkg_id, kdu_name))
+        if helm_chart:
+            indata["helm-chart"] = helm_chart
+            match = fullmatch(r"([^/]*)/([^/]*)", helm_chart)
+            repo_name = match.group(1) if match else None
+        elif juju_bundle:
+            indata["juju-bundle"] = juju_bundle
+            match = fullmatch(r"([^/]*)/([^/]*)", juju_bundle)
+            repo_name = match.group(1) if match else None
+        else:
+            raise EngineException("Found neither 'helm-chart' nor 'juju-bundle' in vnfd[id='{}']:kdu[name='{}']"
+                                  .format(vnfpkg_id, kdu_name))
+        if repo_name:
+            del filter_q["_id"]
+            filter_q["name"] = repo_name
+            repo = self.db.get_one("k8srepos", filter_q)
+            k8srepo_id = repo.get("_id")
+            k8srepo_url = repo.get("url")
+        else:
+            k8srepo_id = None
+            k8srepo_url = None
+        indata["k8srepoId"] = k8srepo_id
+        indata["k8srepo_url"] = k8srepo_url
+        vnfpkgop_id = str(uuid4())
+        vnfpkgop_desc = {
+            "_id": vnfpkgop_id,
+            "operationState": "PROCESSING",
+            "vnfPkgId": vnfpkg_id,
+            "lcmOperationType": operation,
+            "isAutomaticInvocation": False,
+            "isCancelPending": False,
+            "operationParams": indata,
+            "links": {
+                "self": "/osm/vnfpkgm/v1/vnfpkg_op_occs/" + vnfpkgop_id,
+                "vnfpkg": "/osm/vnfpkgm/v1/vnf_packages/" + vnfpkg_id,
+            }
+        }
+        self.format_on_new(vnfpkgop_desc, session["project_id"], make_public=session["public"])
+        ctime = vnfpkgop_desc["_admin"]["created"]
+        vnfpkgop_desc["statusEnteredTime"] = ctime
+        vnfpkgop_desc["startTime"] = ctime
+        self.db.create(self.topic, vnfpkgop_desc)
+        rollback.append({"topic": self.topic, "_id": vnfpkgop_id})
+        self.msg.write(self.topic_msg, operation, vnfpkgop_desc)
+        return vnfpkgop_id, None
index ca7a837..cd02b1d 100644 (file)
@@ -27,7 +27,7 @@ from osm_nbi.base_topic import EngineException, versiontuple
 from osm_nbi.admin_topics import VimAccountTopic, WimAccountTopic, SdnTopic
 from osm_nbi.admin_topics import K8sClusterTopic, K8sRepoTopic
 from osm_nbi.admin_topics import UserTopicAuth, ProjectTopicAuth, RoleTopicAuth
 from osm_nbi.admin_topics import VimAccountTopic, WimAccountTopic, SdnTopic
 from osm_nbi.admin_topics import K8sClusterTopic, K8sRepoTopic
 from osm_nbi.admin_topics import UserTopicAuth, ProjectTopicAuth, RoleTopicAuth
-from osm_nbi.descriptor_topics import VnfdTopic, NsdTopic, PduTopic, NstTopic
+from osm_nbi.descriptor_topics import VnfdTopic, NsdTopic, PduTopic, NstTopic, VnfPkgOpTopic
 from osm_nbi.instance_topics import NsrTopic, VnfrTopic, NsLcmOpTopic, NsiTopic, NsiLcmOpTopic
 from osm_nbi.pmjobs_topics import PmJobsTopic
 from base64 import b64encode
 from osm_nbi.instance_topics import NsrTopic, VnfrTopic, NsLcmOpTopic, NsiTopic, NsiLcmOpTopic
 from osm_nbi.pmjobs_topics import PmJobsTopic
 from base64 import b64encode
@@ -56,7 +56,8 @@ class Engine(object):
         "projects": ProjectTopicAuth,   # Valid for both internal and keystone authentication backends
         "roles": RoleTopicAuth,   # Valid for both internal and keystone authentication backends
         "nsis": NsiTopic,
         "projects": ProjectTopicAuth,   # Valid for both internal and keystone authentication backends
         "roles": RoleTopicAuth,   # Valid for both internal and keystone authentication backends
         "nsis": NsiTopic,
-        "nsilcmops": NsiLcmOpTopic
+        "nsilcmops": NsiLcmOpTopic,
+        "vnfpkgops": VnfPkgOpTopic,
         # [NEW_TOPIC]: add an entry here
         # "pm_jobs": PmJobsTopic will be added manually because it needs other parameters
     }
         # [NEW_TOPIC]: add an entry here
         # "pm_jobs": PmJobsTopic will be added manually because it needs other parameters
     }
index 06b39f3..c9d33b5 100644 (file)
@@ -337,12 +337,21 @@ valid_url_methods = {
                                       "artifacts": {"*": {"METHODS": ("GET", ),
                                                           "ROLE_PERMISSION": "vnfds:id:vnfd_artifact:"
                                                           }
                                       "artifacts": {"*": {"METHODS": ("GET", ),
                                                           "ROLE_PERMISSION": "vnfds:id:vnfd_artifact:"
                                                           }
-                                                    }
+                                                    },
+                                      "action": {"METHODS": ("POST", ),
+                                                 "ROLE_PERMISSION": "vnfds:id:action:"
+                                                 },
                                       }
                              },
             "subscriptions": {"TODO": ("GET", "POST"),
                               "<ID>": {"TODO": ("GET", "DELETE")}
                               },
                                       }
                              },
             "subscriptions": {"TODO": ("GET", "POST"),
                               "<ID>": {"TODO": ("GET", "DELETE")}
                               },
+            "vnfpkg_op_occs": {"METHODS": ("GET", ),
+                               "ROLE_PERMISSION": "vnfds:vnfpkgops:",
+                               "<ID>": {"METHODS": ("GET", ),
+                                        "ROLE_PERMISSION": "vnfds:vnfpkgops:id:"
+                                        }
+                               },
         }
     },
     "nslcm": {
         }
     },
     "nslcm": {
@@ -978,6 +987,10 @@ class Server(object):
                 engine_topic = "nsds"
             elif main_topic == "vnfpkgm":
                 engine_topic = "vnfds"
                 engine_topic = "nsds"
             elif main_topic == "vnfpkgm":
                 engine_topic = "vnfds"
+                if topic == "vnfpkg_op_occs":
+                    engine_topic = "vnfpkgops"
+                if topic == "vnf_packages" and item == "action":
+                    engine_topic = "vnfpkgops"
             elif main_topic == "nslcm":
                 engine_topic = "nsrs"
                 if topic == "ns_lcm_op_occs":
             elif main_topic == "nslcm":
                 engine_topic = "nsrs"
                 if topic == "ns_lcm_op_occs":
@@ -1015,6 +1028,7 @@ class Server(object):
                         # TODO check that project_id (_id in this context) has permissions
                         _id = args[0]
                     outdata = self.engine.get_item(engine_session, engine_topic, _id)
                         # TODO check that project_id (_id in this context) has permissions
                         _id = args[0]
                     outdata = self.engine.get_item(engine_session, engine_topic, _id)
+
             elif method == "POST":
                 cherrypy.response.status = HTTPStatus.CREATED.value
                 if topic in ("ns_descriptors_content", "vnf_packages_content", "netslice_templates_content"):
             elif method == "POST":
                 cherrypy.response.status = HTTPStatus.CREATED.value
                 if topic in ("ns_descriptors_content", "vnf_packages_content", "netslice_templates_content"):
@@ -1053,7 +1067,6 @@ class Server(object):
                     indata["netsliceInstanceId"] = _id
                     nsilcmop_id, _ = self.engine.new_item(rollback, engine_session, "nsilcmops", indata, kwargs)
                     outdata = {"id": _id, "nsilcmop_id": nsilcmop_id}
                     indata["netsliceInstanceId"] = _id
                     nsilcmop_id, _ = self.engine.new_item(rollback, engine_session, "nsilcmops", indata, kwargs)
                     outdata = {"id": _id, "nsilcmop_id": nsilcmop_id}
-
                 elif topic == "netslice_instances" and item:
                     indata["lcmOperationType"] = item
                     indata["netsliceInstanceId"] = _id
                 elif topic == "netslice_instances" and item:
                     indata["lcmOperationType"] = item
                     indata["netsliceInstanceId"] = _id
@@ -1061,6 +1074,13 @@ class Server(object):
                     self._set_location_header(main_topic, version, "nsi_lcm_op_occs", _id)
                     outdata = {"id": _id}
                     cherrypy.response.status = HTTPStatus.ACCEPTED.value
                     self._set_location_header(main_topic, version, "nsi_lcm_op_occs", _id)
                     outdata = {"id": _id}
                     cherrypy.response.status = HTTPStatus.ACCEPTED.value
+                elif topic == "vnf_packages" and item == "action":
+                    indata["lcmOperationType"] = item
+                    indata["vnfPkgId"] = _id
+                    _id, _ = self.engine.new_item(rollback, engine_session, "vnfpkgops", indata, kwargs)
+                    self._set_location_header(main_topic, version, "vnfpkg_op_occs", _id)
+                    outdata = {"id": _id}
+                    cherrypy.response.status = HTTPStatus.ACCEPTED.value
                 else:
                     _id, op_id = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs,
                                                       cherrypy.request.headers)
                 else:
                     _id, op_id = self.engine.new_item(rollback, engine_session, engine_topic, indata, kwargs,
                                                       cherrypy.request.headers)
index 523d1f8..8d81353 100644 (file)
@@ -103,6 +103,11 @@ resources_to_operations:
   "GET /vnfpkgm/v1/vnf_packages/<vnfPkgId>/artifacts": "vnfds:id:vnfd_artifact:get"
   "GET /vnfpkgm/v1/vnf_packages/<vnfPkgId>/artifacts/<artifactPath>": "vnfds:id:vnfd_artifact:get"
 
   "GET /vnfpkgm/v1/vnf_packages/<vnfPkgId>/artifacts": "vnfds:id:vnfd_artifact:get"
   "GET /vnfpkgm/v1/vnf_packages/<vnfPkgId>/artifacts/<artifactPath>": "vnfds:id:vnfd_artifact:get"
 
+  "POST /vnfpkgm/v1/vnf_packages/<vnfPkgId>/action": "vnfds:id:action:post"
+
+  "GET /vnfpkgm/v1/vnfpkg_op_occs": "vnfds:vnfpkgops:get"
+  "GET /vnfpkgm/v1/vnfpkg_op_occs/<vnfPkgOpId>": "vnfds:vnfpkgops:id:get"
+
 ################################################################################
 ################################## NS Instances ################################
 ################################################################################
 ################################################################################
 ################################## NS Instances ################################
 ################################################################################
index e40d0ec..13b16d7 100644 (file)
@@ -657,7 +657,6 @@ pdu_new_schema = {
     "required": ["name", "type", "interfaces"],
     "additionalProperties": False
 }
     "required": ["name", "type", "interfaces"],
     "additionalProperties": False
 }
-
 pdu_edit_schema = {
     "title": "pdu edit input schema",
     "$schema": "http://json-schema.org/draft-04/schema#",
 pdu_edit_schema = {
     "title": "pdu edit input schema",
     "$schema": "http://json-schema.org/draft-04/schema#",
@@ -682,6 +681,22 @@ pdu_edit_schema = {
     "minProperties": 1
 }
 
     "minProperties": 1
 }
 
+# VNF PKG OPERATIONS
+vnfpkgop_new_schema = {
+    "title": "VNF PKG operation creation input schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type": "object",
+    "properties": {
+        "lcmOperationType": string_schema,
+        "vnfPkgId": id_schema,
+        "kdu_name": name_schema,
+        "primitive": name_schema,
+        "primitive_params": {"type": "object"},
+    },
+    "required": ["lcmOperationType", "vnfPkgId", "kdu_name", "primitive", "primitive_params"],
+    "additionalProperties": False
+}
+
 # USERS
 project_role_mappings = {
     "title": "list pf projects/roles",
 # USERS
 project_role_mappings = {
     "title": "list pf projects/roles",