Adding NSI operations (Create, Read, Delete) 84/6784/12 netslice
authorFelipe Vicens <felipe.vicens@atos.net>
Mon, 29 Oct 2018 14:16:44 +0000 (15:16 +0100)
committerFelipe Vicens <felipe.vicens@atos.net>
Fri, 16 Nov 2018 14:34:31 +0000 (15:34 +0100)
Change-Id: I013e3d54014ed266e6232e5410ad53ddf8df70ea
Signed-off-by: Felipe Vicens <felipe.vicens@atos.net>
Dockerfile.local
osm_nbi/descriptor_topics.py
osm_nbi/engine.py
osm_nbi/html_out.py
osm_nbi/instance_topics.py
osm_nbi/nbi.py
osm_nbi/tests/cirros_slice/cirros_slice.yaml
osm_nbi/tests/clear-all.sh
osm_nbi/tests/test.py
osm_nbi/validation.py

index da13878..0d2a3d6 100644 (file)
@@ -6,7 +6,7 @@ FROM ubuntu:16.04
 WORKDIR /app/NBI/osm_nbi
 
 # Copy the current directory contents into the container at /app
-ADD . /app/NBI
+#ADD . /app
 
 RUN apt-get update && apt-get install -y git python3 python3-jsonschema \
     python3-pymongo python3-yaml python3-pip python3-keystoneclient \
@@ -80,6 +80,8 @@ ENV OSMNBI_AUTHENTICATION_BACKEND               internal
 #ENV OSMNBI_AUTHENTICATION_SERVICE_PASSWORD      nbi
 #ENV OSMNBI_AUTHENTICATION_SERVICE_PROJECT       service
 
+ADD . /app/NBI
+
 # Run app.py when the container launches
 CMD ["python3", "nbi.py"]
 
index 9e367c9..3ace489 100644 (file)
@@ -40,7 +40,7 @@ class DescriptorTopic(BaseTopic):
         BaseTopic.format_on_new(content, project_id=project_id, make_public=make_public)
         content["_admin"]["onboardingState"] = "CREATED"
         content["_admin"]["operationalState"] = "DISABLED"
-        content["_admin"]["usageSate"] = "NOT_IN_USE"
+        content["_admin"]["usageState"] = "NOT_IN_USE"
 
     def delete(self, session, _id, force=False, dry_run=False):
         """
@@ -657,16 +657,6 @@ class NstTopic(DescriptorTopic):
             clean_indata = clean_indata['nst'][0]
         return clean_indata
 
-    def _validate_input_new(self, indata, force=False):
-        # transform netslice-subnet:nsd-ref to string
-        if indata.get("netslice-subnet"):
-            for nsd_ref in indata["netslice-subnet"]:
-                if "nsd-ref" in nsd_ref:
-                    nsd_ref["nsd-ref"] = str(nsd_ref["nsd-ref"])
-
-        # TODO validate with pyangbind, serialize
-        return indata
-
     def _validate_input_edit(self, indata, force=False):
         # TODO validate with pyangbind, serialize
         return indata
@@ -698,15 +688,21 @@ class NstTopic(DescriptorTopic):
         Check that there is not any NSIR that uses this NST. Only NSIRs belonging to this project are considered. Note
         that NST can be public and be used by other projects.
         :param session:
-        :param _id: nsd internal id
+        :param _id: nst internal id
         :param force: Avoid this checking
         :return: None or raises EngineException with the conflict
         """
         # TODO: Check this method
         if force:
             return
+        # Get Network Slice Template from Database
+        _filter = self._get_project_filter(session, write=False, show_all=False)
+        _filter["_id"] = _id
+        nst = self.db.get_one("nst", _filter)
+        
+        # Search NSIs using NST via nst-ref
         _filter = self._get_project_filter(session, write=False, show_all=False)
-        _filter["nst"] = _id
+        _filter["nst-ref"] = nst["id"]
         if self.db.get_list("nsis", _filter):
             raise EngineException("There is some NSIS that depends on this NST", http_code=HTTPStatus.CONFLICT)
 
@@ -725,7 +721,7 @@ class PduTopic(BaseTopic):
         BaseTopic.format_on_new(content, project_id=None, make_public=make_public)
         content["_admin"]["onboardingState"] = "CREATED"
         content["_admin"]["operationalState"] = "DISABLED"
-        content["_admin"]["usageSate"] = "NOT_IN_USE"
+        content["_admin"]["usageState"] = "NOT_IN_USE"
 
     def check_conflict_on_del(self, session, _id, force=False):
         if force:
index 3de3d15..4713b89 100644 (file)
@@ -9,7 +9,7 @@ from http import HTTPStatus
 from base_topic import EngineException, versiontuple
 from admin_topics import UserTopic, ProjectTopic, VimAccountTopic, SdnTopic
 from descriptor_topics import VnfdTopic, NsdTopic, PduTopic, NstTopic
-from instance_topics import NsrTopic, VnfrTopic, NsLcmOpTopic, NsiTopic
+from instance_topics import NsrTopic, VnfrTopic, NsLcmOpTopic, NsiTopic, NsiLcmOpTopic
 from base64 import b64encode
 from os import urandom
 
@@ -31,6 +31,7 @@ class Engine(object):
         "users": UserTopic,
         "projects": ProjectTopic,
         "nsis": NsiTopic,
+        "nsilcmops": NsiLcmOpTopic
         # [NEW_TOPIC]: add an entry here
     }
 
index e9237e9..8d3baab 100644 (file)
@@ -25,6 +25,7 @@ html_start = """
       <a href="/osm/nsd/v1/ns_descriptors">NSDs </a>
       <a href="/osm/nslcm/v1/ns_instances">NSs </a>
       <a href="/osm/nst/v1/netslice_templates">NSTDs </a>
+      <a href="/osm/nsilcm/v1/netslice_instances">NSIs </a>
       <a href="/osm/admin/v1/users">USERs </a>
       <a href="/osm/admin/v1/projects">PROJECTs </a>
       <a href="/osm/admin/v1/tokens">TOKENs </a>
@@ -102,6 +103,15 @@ html_nslcmop_body = """
 </form>
 """
 
+html_nsilcmop_body = """
+<a href="/osm/nsilcm/v1/nsi_lcm_op_occs?nsiInstanceId={id}">nsilcm operations </a>
+<form action="/osm/nsilcm/v1/netslice_instances/{id}/terminate" method="post" enctype="multipart/form-data">
+    <h3> <table style="border: 0;"> <tr>
+        <td> <input type="submit" value="Terminate"/> </td>
+    </tr> </table> </h3>
+</form>
+"""
+
 
 def format(data, request, response, session):
     """
@@ -145,6 +155,10 @@ def format(data, request, response, session):
                     request.path_info.startswith("/nslcm/v1/ns_instances/"):
                 _id = request.path_info[request.path_info.rfind("/")+1:]
                 body += html_nslcmop_body.format(id=_id)
+            elif request.path_info.startswith("/nsilcm/v1/netslice_instances_content/") or \
+                    request.path_info.startswith("/nsilcm/v1/netslice_instances/"):
+                _id = request.path_info[request.path_info.rfind("/")+1:]
+                body += html_nsilcmop_body.format(id=_id)
         body += "<pre>" + html_escape(yaml.safe_dump(data, explicit_start=True, indent=4, default_flow_style=False)) + \
                 "</pre>"
     elif data is None:
index 4228bc5..41187dc 100644 (file)
@@ -5,7 +5,7 @@ from uuid import uuid4
 from http import HTTPStatus
 from time import time
 from copy import copy, deepcopy
-from validation import validate_input, ValidationError, ns_instantiate, ns_action, ns_scale
+from validation import validate_input, ValidationError, ns_instantiate, ns_action, ns_scale, nsi_instantiate
 from base_topic import BaseTopic, EngineException, get_iterable
 from descriptor_topics import DescriptorTopic
 
@@ -66,7 +66,7 @@ class NsrTopic(BaseTopic):
         self.db.del_list("vnfrs", {"nsr-id-ref": _id})
         # set all used pdus as free
         self.db.set_list("pdus", {"_admin.usage.nsr_id": _id},
-                         {"_admin.usageSate": "NOT_IN_USE", "_admin.usage": None})
+                         {"_admin.usageState": "NOT_IN_USE", "_admin.usage": None})
         self._send_msg("deleted", {"_id": _id})
         return v
 
@@ -266,17 +266,6 @@ class NsLcmOpTopic(BaseTopic):
     def __init__(self, db, fs, msg):
         BaseTopic.__init__(self, db, fs, msg)
 
-    def _validate_input_new(self, input, force=False):
-        """
-        Validates input user content for a new entry. It uses jsonschema for each type or operation.
-        :param input: user input content for the new topic
-        :param force: may be used for being more tolerant
-        :return: The same input content, or a changed version of it.
-        """
-        if self.schema_new:
-            validate_input(input, self.schema_new)
-        return input
-
     def _check_ns_operation(self, session, nsr, operation, indata):
         """
         Check that user has enter right parameters for the operation
@@ -432,7 +421,7 @@ class NsLcmOpTopic(BaseTopic):
             pdu_filter["vim.vim_accounts"] = vim_account
             pdu_filter["type"] = pdu_type
             pdu_filter["_admin.operationalState"] = "ENABLED"
-            pdu_filter["_admin.usageSate"] = "NOT_IN_USE",
+            pdu_filter["_admin.usageState"] = "NOT_IN_USE",
             # TODO feature 1417: "shared": True,
 
             available_pdus = self.db.get_list("pdus", pdu_filter)
@@ -462,7 +451,7 @@ class NsLcmOpTopic(BaseTopic):
                 "_admin.usage.vdur": None,
             }
             self.db.set_one("pdus", {"_id": pdu["_id"]},
-                            {"_admin.usageSate": "IN_USE",
+                            {"_admin.usageState": "IN_USE",
                              "_admin.usage.vnfr_id": vnfr["_id"],
                              "_admin.usage.nsr_id": vnfr["nsr-id-ref"],
                              "_admin.usage.vdur": vdur["vdu-id-ref"]}
@@ -535,7 +524,8 @@ class NsLcmOpTopic(BaseTopic):
         }
         return nslcmop
 
-    def new(self, rollback, session, indata=None, kwargs=None, headers=None, force=False, make_public=False):
+    def new(self, rollback, session, indata=None, kwargs=None, headers=None, force=False, make_public=False,
+            slice_object=False):
         """
         Performs a new operation over a ns
         :param rollback: list to append created items at database in case a rollback must to be done
@@ -580,7 +570,8 @@ class NsLcmOpTopic(BaseTopic):
             self.format_on_new(nslcmop_desc, session["project_id"], make_public=make_public)
             _id = self.db.create("nslcmops", nslcmop_desc)
             rollback.append({"topic": "nslcmops", "_id": _id})
-            self.msg.write("ns", operation, nslcmop_desc)
+            if not slice_object:
+                self.msg.write("ns", operation, nslcmop_desc)
             return _id
         except ValidationError as e:
             raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
@@ -608,17 +599,16 @@ class NsiTopic(BaseTopic):
         :param descriptor: descriptor to be inserted or edit
         :return: None or raises exception
         """
-        if not descriptor.get("nstdId"):
+        if not descriptor.get("nst-ref"):
             return
-        nstd_id = descriptor["nstdId"]
+        nstd_id = descriptor["nst-ref"]
         if not self.get_item_list(session, "nsts", {"id": nstd_id}):
-            raise EngineException("Descriptor error at nstdId='{}' references a non exist nstd".format(nstd_id),
+            raise EngineException("Descriptor error at nst-ref='{}' references a non exist nstd".format(nstd_id),
                                   http_code=HTTPStatus.CONFLICT)
 
     @staticmethod
     def format_on_new(content, project_id=None, make_public=False):
         BaseTopic.format_on_new(content, project_id=project_id, make_public=make_public)
-        content["_admin"]["nstState"] = "NOT_INSTANTIATED"
 
     def check_conflict_on_del(self, session, _id, force=False):
         if force:
@@ -642,17 +632,28 @@ class NsiTopic(BaseTopic):
         BaseTopic.delete(self, session, _id, force, dry_run=True)
         if dry_run:
             return
+
+        # deletes NetSlice instance object
         v = self.db.del_one("nsis", {"_id": _id})
-        self.db.del_list("nstlcmops", {"nstInstanceId": _id})
-        self.db.del_list("vnfrs", {"nsr-id-ref": _id})
-        # set all used pdus as free
-        self.db.set_list("pdus", {"_admin.usage.nsr_id": _id}, {"_admin.usageSate": "NOT_IN_USE", "_admin.usage": None})
+
+        # makes a temporal list of nsilcmops objects related to the _id given and deletes them from db
+        _filter = {"netsliceInstanceId": _id} 
+        self.db.del_list("nsilcmops", _filter)
+
+        _filter = {"operationParams.netsliceInstanceId": _id}
+        nslcmops_list = self.db.get_list("nslcmops", _filter)
+
+        for id_item in nslcmops_list:
+            _filter = {"_id": id_item}
+            nslcmop = self.db.get_one("nslcmops", _filter)
+            nsr_id = nslcmop["operationParams"]["nsr_id"]
+            NsrTopic.delete(self, session, nsr_id, force=False, dry_run=False)
         self._send_msg("deleted", {"_id": _id})
         return v
 
     def new(self, rollback, session, indata=None, kwargs=None, headers=None, force=False, make_public=False):
         """
-        Creates a new nsr into database. It also creates needed vnfrs
+        Creates a new netslice instance record into database. It also creates needed nsrs and vnfrs
         :param rollback: list to append the created items at database in case a rollback must be done
         :param session: contains the used login username and working project
         :param indata: params to be used for the nsir
@@ -671,13 +672,18 @@ class NsiTopic(BaseTopic):
 
             step = ""
             # look for nstd
+            self.logger.info(str(slice_request))
             step = "getting nstd id='{}' from database".format(slice_request.get("nstdId"))
-            _filter = {"_id": slice_request["nstdId"]}
+            _filter = {"id": slice_request["nstdId"]}
             _filter.update(BaseTopic._get_project_filter(session, write=False, show_all=True))
             nstd = self.db.get_one("nsts", _filter)
+            nstd.pop("_admin", None)
+            nstd.pop("_id", None)
             nsi_id = str(uuid4())
-            # now = time()
             step = "filling nsi_descriptor with input data"
+
+            # "instantiation-parameters.netslice-subnet": []
+            # TODO: Equal as template for now
             nsi_descriptor = {
                 "id": nsi_id,
                 "nst-ref": nstd["id"],
@@ -685,28 +691,12 @@ class NsiTopic(BaseTopic):
                     "netslice-subnet": []
                 },
                 "network-slice-template": nstd,
-                # "nsr-ref-list": [],    #TODO: not used for now...
-                # "vlr-ref-list": [],    #TODO: not used for now...
                 "_id": nsi_id,
-                
-                # TODO CHECK: what about the following params?
-                # "admin-status": "ENABLED",
-                # "description": slice_request.get("nsDescription", ""),
-                # "operational-status": "init",    # typedef ns-operational-
-                # "config-status": "init",         # typedef config-states
-                # "detailed-status": "scheduled",
-                # "orchestration-progress": {},
-                # # {"networks": {"active": 0, "total": 0}, "vms": {"active": 0, "total": 0}},
-                # "create-time": now,
-                # "operational-events": [],   # "id", "timestamp", "description", "event",
-                # "ssh-authorized-key": slice_request.get("key-pair-ref"),
             }
-            # nstd["nsi_id"] = nsi_id
 
-            # TODO: ask if we have to develop the VNFR here or we can imply call the NsrTopic() for each service to 
-            # instantiate.
-            # Create netslice-subnet_record
+            # Creating netslice-subnet_record. 
             needed_nsds = {}
+            services = []
             for member_ns in nstd["netslice-subnet"]:
                 nsd_id = member_ns["nsd-ref"]
                 step = "getting nstd id='{}' constituent-nsd='{}' from database".format(
@@ -716,20 +706,38 @@ class NsiTopic(BaseTopic):
                     nsd = DescriptorTopic.get_one_by_id(self.db, session, "nsds", nsd_id)
                     nsd.pop("_admin")
                     needed_nsds[nsd_id] = nsd
+                    member_ns["_id"] = needed_nsds[nsd_id].get("_id")
+                    services.append(member_ns)
                 else:
                     nsd = needed_nsds[nsd_id]
-                
+                    member_ns["_id"] = needed_nsds[nsd_id].get("_id")
+                    services.append(member_ns)
+
                 step = "filling nsir nsd-id='{}' constituent-nsd='{}' from database".format(
                     member_ns["nsd-ref"], member_ns["id"])
-                netslice_subnet_descriptor = {
-                    "nsName": member_ns["instantiation-parameters"]["name"],
-                    "nsdId": member_ns["instantiation-parameters"]["nsdId"],
-                    "vimAccountId": member_ns["instantiation-parameters"]["vimAccountId"]
-                }
-                nsi_descriptor["instantiation-parameters"]["netslice-subnet"].append(netslice_subnet_descriptor)
 
             step = "creating nsi at database"
             self.format_on_new(nsi_descriptor, session["project_id"], make_public=make_public)
+            nsi_descriptor["_admin"]["nsiState"] = "NOT_INSTANTIATED"          
+
+            # creates Network Services records (NSRs)
+            step = "creating nsrs at database using NsrTopic.new()"
+            nsrs_list = []
+            for service in services:
+                indata_ns = {}
+                indata_ns["nsdId"] = service["_id"]
+                indata_ns["nsName"] = service["name"]
+                indata_ns["vimAccountId"] = indata.get("vimAccountId")
+                indata_ns["nsDescription"] = service["description"]
+                indata_ns["key-pair-ref"] = None
+                # NsrTopic(rollback, session, indata_ns, kwargs, headers, force)
+                _id_nsr = NsrTopic.new(self, rollback, session, indata_ns, kwargs, headers, force)
+                nsrs_item = {"nsrId": _id_nsr}
+                nsrs_list.append(nsrs_item)
+
+            # Adding the nsrs list to the nsi
+            nsi_descriptor["_admin"]["nsrs-detailed-list"] = nsrs_list
+            # Creating the entry in the database
             self.db.create("nsis", nsi_descriptor)
             rollback.append({"topic": "nsis", "_id": nsi_id})
             return nsi_id
@@ -741,3 +749,141 @@ class NsiTopic(BaseTopic):
 
     def edit(self, session, _id, indata=None, kwargs=None, force=False, content=None):
         raise EngineException("Method edit called directly", HTTPStatus.INTERNAL_SERVER_ERROR)
+
+
+class NsiLcmOpTopic(BaseTopic):
+    topic = "nsilcmops"
+    topic_msg = "nsi"
+    operation_schema = {  # mapping between operation and jsonschema to validate
+        "instantiate": nsi_instantiate,
+        "terminate": None
+    }
+
+    def __init__(self, db, fs, msg):
+        BaseTopic.__init__(self, db, fs, msg)
+
+    def _check_nsi_operation(self, session, nsir, operation, indata):
+        """
+        Check that user has enter right parameters for the operation
+        :param session:
+        :param operation: it can be: instantiate, terminate, action, TODO: update, heal
+        :param indata: descriptor with the parameters of the operation
+        :return: None
+        """
+        nsds = {}
+        nstd = nsir["network-slice-template"]
+
+        def check_valid_netslice_subnet_id(nsId):
+            # TODO change to vnfR (??)
+            for ns in nstd["netslice-subnet"]:
+                if nsId == ns["id"]:
+                    nsd_id = ns["nsd-ref"]
+                    if nsd_id not in nsds:
+                        nsds[nsd_id] = self.db.get_one("nsds", {"id": nsd_id})
+                    return nsds[nsd_id]
+            else:
+                raise EngineException("Invalid parameter nsId='{}' is not one of the "
+                                      "nst:netslice-subnet".format(nsId))
+        if operation == "instantiate":
+            # check the existance of netslice-subnet items
+            for in_nst in get_iterable(indata.get("netslice-subnet")):           
+                nstd = check_valid_netslice_subnet_id(in_nst["nsdId"])
+
+    def _create_nsilcmop(self, session, netsliceInstanceId, operation, params):
+        now = time()
+        _id = str(uuid4())
+        nsilcmop = {
+            "id": _id,
+            "_id": _id,
+            "operationState": "PROCESSING",  # COMPLETED,PARTIALLY_COMPLETED,FAILED_TEMP,FAILED,ROLLING_BACK,ROLLED_BACK
+            "statusEnteredTime": now,
+            "netsliceInstanceId": netsliceInstanceId,
+            "lcmOperationType": operation,
+            "startTime": now,
+            "isAutomaticInvocation": False,
+            "operationParams": params,
+            "isCancelPending": False,
+            "links": {
+                "self": "/osm/nsilcm/v1/nsi_lcm_op_occs/" + _id,
+                "nsInstance": "/osm/nsilcm/v1/netslice_instances/" + netsliceInstanceId,
+            }
+        }
+        return nsilcmop
+
+    def new(self, rollback, session, indata=None, kwargs=None, headers=None, force=False, make_public=False):
+        """
+        Performs a new operation over a ns
+        :param rollback: list to append created items at database in case a rollback must to be done
+        :param session: contains the used login username and working project
+        :param indata: descriptor with the parameters of the operation. It must contains among others
+            nsiInstanceId: _id of the nsir to perform the operation
+            operation: it can be: instantiate, terminate, action, TODO: update, heal
+        :param kwargs: used to override the indata descriptor
+        :param headers: http request headers
+        :param force: If True avoid some dependence checks
+        :param make_public: Make the created item public to all projects
+        :return: id of the nslcmops
+        """
+        try:
+            # Override descriptor with query string kwargs
+            self._update_input_with_kwargs(indata, kwargs)
+            operation = indata["lcmOperationType"]
+            nsiInstanceId = indata["nsiInstanceId"]
+            validate_input(indata, self.operation_schema[operation])
+
+            # get nsi from nsiInstanceId
+            _filter = BaseTopic._get_project_filter(session, write=True, show_all=False)
+            _filter["_id"] = nsiInstanceId
+            nsir = self.db.get_one("nsis", _filter)
+
+            # initial checking
+            if not nsir["_admin"].get("nsiState") or nsir["_admin"]["nsiState"] == "NOT_INSTANTIATED":
+                if operation == "terminate" and indata.get("autoremove"):
+                    # NSIR must be deleted
+                    return self.delete(session, nsiInstanceId)
+                if operation != "instantiate":
+                    raise EngineException("netslice_instance '{}' cannot be '{}' because it is not instantiated".format(
+                        nsiInstanceId, operation), HTTPStatus.CONFLICT)
+            else:
+                if operation == "instantiate" and not indata.get("force"):
+                    raise EngineException("netslice_instance '{}' cannot be '{}' because it is already instantiated".
+                                          format(nsiInstanceId, operation), HTTPStatus.CONFLICT)
+            
+            # Creating all the NS_operation (nslcmop)
+            # Get service list from db
+            nsrs_list = nsir["_admin"]["nsrs-detailed-list"]
+            nslcmops = []
+            for nsr_item in nsrs_list:
+                service = self.db.get_one("nsrs", {"_id": nsr_item["nsrId"]})
+                indata_ns = {}
+                indata_ns = service["instantiate_params"]
+                indata_ns["lcmOperationType"] = operation
+                indata_ns["nsInstanceId"] = service["_id"]
+                # Including netslice_id in the ns instantiate Operation
+                indata_ns["netsliceInstanceId"] = nsiInstanceId
+                del indata_ns["key-pair-ref"]
+                nsi_NsLcmOpTopic = NsLcmOpTopic(self.db, self.fs, self.msg)
+                # Creating NS_LCM_OP with the flag slice_object=True to not trigger the service instantiation 
+                # message via kafka bus
+                nslcmop = nsi_NsLcmOpTopic.new(rollback, session, indata_ns, kwargs, headers, force, slice_object=True)
+                nslcmops.append(nslcmop)
+
+            # Creates nsilcmop
+            indata["nslcmops_ids"] = nslcmops
+            self._check_nsi_operation(session, nsir, operation, indata)
+            nsilcmop_desc = self._create_nsilcmop(session, nsiInstanceId, operation, indata)
+            self.format_on_new(nsilcmop_desc, session["project_id"], make_public=make_public)
+            _id = self.db.create("nsilcmops", nsilcmop_desc)
+            rollback.append({"topic": "nsilcmops", "_id": _id})
+            self.msg.write("nsi", operation, nsilcmop_desc)
+            return _id
+        except ValidationError as e:
+            raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
+        # except DbException as e:
+        #     raise EngineException("Cannot get nsi_instance '{}': {}".format(e), HTTPStatus.NOT_FOUND)
+
+    def delete(self, session, _id, force=False, dry_run=False):
+        raise EngineException("Method delete called directly", HTTPStatus.INTERNAL_SERVER_ERROR)
+
+    def edit(self, session, _id, indata=None, kwargs=None, force=False, content=None):
+        raise EngineException("Method edit called directly", HTTPStatus.INTERNAL_SERVER_ERROR)
index e8f2246..1354f2c 100644 (file)
@@ -675,9 +675,7 @@ class Server(object):
                 force = kwargs.pop("FORCE")
             else:
                 force = False
-
             self._check_valid_url_method(method, main_topic, version, topic, _id, item, *args)
-
             if main_topic == "admin" and topic == "tokens":
                 return self.token(method, _id, kwargs)
 
@@ -712,8 +710,7 @@ class Server(object):
                 engine_topic = "vim_accounts"
 
             if method == "GET":
-                if item in ("nsd_content", "package_content", "artifacts", "vnfd", "nsd", "nst", "nst_content", 
-                            "netslice_instances"):
+                if item in ("nsd_content", "package_content", "artifacts", "vnfd", "nsd", "nst", "nst_content"):
                     if item in ("vnfd", "nsd", "nst"):
                         path = "$DESCRIPTOR"
                     elif args:
@@ -759,14 +756,14 @@ class Server(object):
                     outdata = {"id": _id}
                     cherrypy.response.status = HTTPStatus.ACCEPTED.value
                 elif topic == "netslice_instances_content":
-                    # creates NSI
+                    # creates NetSlice_Instance_record (NSIR)
                     _id = self.engine.new_item(rollback, session, engine_topic, indata, kwargs, force=force)
-                    # creates nsilcmop
+                    self._set_location_header(main_topic, version, topic, _id)
                     indata["lcmOperationType"] = "instantiate"
                     indata["nsiInstanceId"] = _id
-                    self.engine.new_item(rollback, session, "nsilcmops", indata, None)
-                    self._set_location_header(main_topic, version, topic, _id)
+                    self.engine.new_item(rollback, session, "nsilcmops", indata, kwargs)
                     outdata = {"id": _id}
+                    
                 elif topic == "netslice_instances" and item:
                     indata["lcmOperationType"] = item
                     indata["nsiInstanceId"] = _id
index 3b5c963..6f66c27 100644 (file)
@@ -1,21 +1,17 @@
 nst:
     nst:
     -   id: cirros_nst
-        name: cirros_slice_template
+        name: cirros_netslice_template
         SNSSAI-identifier:
         -   slice-service-type: eMBB
         quality-of-service:
         -   id: 1
         netslice-subnet:
-        -   id: cirros_nsd_nst
-            name: cirros_ns
-            short-name: cirros_ns
-            vendor: OSM
+        -   id: cirros_nsd
             is-shared-nss: 'false'
-            description: Slice for osm-3.0-three 2nd-hackfest nsd2vnfs package
-            version: '1.0'
-            nsd-ref: cirros_2vnf_nsd
+            description: Slice example for osm-5.0
+            nsd-ref: cirros_nsd
             instantiation-parameters:
-            -   name: cirros_2vnf_nsd
-                nsdId: cirros_2vnf_nsd
+            -   nsName: cirros_nsd
+                nsdId: cirros_nsd
                 vimAccountId: openstack_18
\ No newline at end of file
index 5ba9d4b..c670106 100755 (executable)
@@ -66,7 +66,7 @@ then
     done
 fi
 
-for item in vim_accounts sdns nsrs vnfrs nslcmops nsds vnfds projects nsts # vims
+for item in vim_accounts sdns nsrs vnfrs nslcmops nsds vnfds projects nsts nsis nsilcmops # vims
 do
     curl --insecure ${OSMNBI_URL}/test/db-clear/${item}
     echo " ${item}"
index bcdfadf..2fbc217 100755 (executable)
@@ -1343,7 +1343,7 @@ class TestNstTemplates:
     def run(self, engine, test_osm, manual_check, test_params=None):
         # nst CREATE
         engine.get_autorization()
-        r = engine.test("NST", "Onboard NST", "POST", "/nst/v1/netslice_templates_content", headers_yaml, 
+        r = engine.test("NST1", "Onboard NST", "POST", "/nst/v1/netslice_templates_content", headers_yaml, 
                         self.nst_filenames, 
                         201, {"Location": "/nst/v1/netslice_templates_content", "Content-Type": "application/yaml"}, 
                         "yaml")
@@ -1351,13 +1351,13 @@ class TestNstTemplates:
         nst_id = location[location.rfind("/")+1:]
 
         # nstd SHOW OSM format
-        r = engine.test("NST", "Show NSTD OSM format", "GET", 
-                        "/nst/v1/netslice_templates_content/{}".format(nst_id), headers_json, None, 
+        r = engine.test("NST2", "Show NSTD OSM format", "GET", 
+                        "/nst/v1/netslice_templates/{}".format(nst_id), headers_json, None, 
                         200, r_header_json, "json")      
 
         # nstd DELETE
-        r = engine.test("NST", "Delete NSTD", "DELETE", 
-                        "/nst/v1/netslice_templates_content/{}".format(nst_id), headers_json, None, 
+        r = engine.test("NST3", "Delete NSTD", "DELETE", 
+                        "/nst/v1/netslice_templates/{}".format(nst_id), headers_json, None, 
                         204, None, 0)
 
 
index da3dd04..62d9d22 100644 (file)
@@ -192,6 +192,7 @@ ns_instantiate = {
     "properties": {
         "lcmOperationType": string_schema,
         "nsInstanceId": id_schema,
+        "netsliceInstanceId": id_schema,
         "nsName": name_schema,
         "nsDescription": {"oneOf": [description_schema, {"type": "null"}]},
         "nsdId": id_schema,
@@ -559,6 +560,38 @@ nbi_edit_input_schemas = {
     "pdus": pdu_edit_schema,
 }
 
+# NETSLICE SCHEMAS
+nsi_instantiate = {
+    "title": "netslice action instantiate input schema",
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "type": "object",
+    "properties": {
+        "lcmOperationType": string_schema,
+        "nsiInstanceId": id_schema,
+        "nsiName": name_schema,
+        "nsiDescription": {"oneOf": [description_schema, {"type": "null"}]},
+        "nstdId": string_schema,
+        "vimAccountId": id_schema,
+        "ssh_keys": {"type": "string"},
+        "nsi_id": id_schema,
+        "ns": {
+            "type": "array",
+            "minItems": 1,
+            "items": ns_instantiate
+        },
+    },
+    "required": ["nsiName", "nstdId", "vimAccountId"],
+    "additionalProperties": False
+}
+
+nsi_action = {
+
+}
+
+nsi_terminate = {
+    
+}
+
 
 class ValidationError(Exception):
     pass