From 07f3172ef24dab2c7c47c9a8e726f1f9876f13b3 Mon Sep 17 00:00:00 2001 From: Felipe Vicens Date: Mon, 29 Oct 2018 15:16:44 +0100 Subject: [PATCH 1/1] Adding NSI operations (Create, Read, Delete) Change-Id: I013e3d54014ed266e6232e5410ad53ddf8df70ea Signed-off-by: Felipe Vicens --- Dockerfile.local | 4 +- osm_nbi/descriptor_topics.py | 24 +- osm_nbi/engine.py | 3 +- osm_nbi/html_out.py | 14 ++ osm_nbi/instance_topics.py | 252 +++++++++++++++---- osm_nbi/nbi.py | 13 +- osm_nbi/tests/cirros_slice/cirros_slice.yaml | 16 +- osm_nbi/tests/clear-all.sh | 2 +- osm_nbi/tests/test.py | 10 +- osm_nbi/validation.py | 33 +++ 10 files changed, 278 insertions(+), 93 deletions(-) diff --git a/Dockerfile.local b/Dockerfile.local index da13878..0d2a3d6 100644 --- a/Dockerfile.local +++ b/Dockerfile.local @@ -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"] diff --git a/osm_nbi/descriptor_topics.py b/osm_nbi/descriptor_topics.py index 9e367c9..3ace489 100644 --- a/osm_nbi/descriptor_topics.py +++ b/osm_nbi/descriptor_topics.py @@ -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: diff --git a/osm_nbi/engine.py b/osm_nbi/engine.py index 3de3d15..4713b89 100644 --- a/osm_nbi/engine.py +++ b/osm_nbi/engine.py @@ -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 } diff --git a/osm_nbi/html_out.py b/osm_nbi/html_out.py index e9237e9..8d3baab 100644 --- a/osm_nbi/html_out.py +++ b/osm_nbi/html_out.py @@ -25,6 +25,7 @@ html_start = """ NSDs NSs NSTDs + NSIs USERs PROJECTs TOKENs @@ -102,6 +103,15 @@ html_nslcmop_body = """ """ +html_nsilcmop_body = """ +nsilcm operations +
+

+ +

+
+""" + 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 += "
" + html_escape(yaml.safe_dump(data, explicit_start=True, indent=4, default_flow_style=False)) + \
                 "
" elif data is None: diff --git a/osm_nbi/instance_topics.py b/osm_nbi/instance_topics.py index 4228bc5..41187dc 100644 --- a/osm_nbi/instance_topics.py +++ b/osm_nbi/instance_topics.py @@ -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) diff --git a/osm_nbi/nbi.py b/osm_nbi/nbi.py index e8f2246..1354f2c 100644 --- a/osm_nbi/nbi.py +++ b/osm_nbi/nbi.py @@ -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 diff --git a/osm_nbi/tests/cirros_slice/cirros_slice.yaml b/osm_nbi/tests/cirros_slice/cirros_slice.yaml index 3b5c963..6f66c27 100644 --- a/osm_nbi/tests/cirros_slice/cirros_slice.yaml +++ b/osm_nbi/tests/cirros_slice/cirros_slice.yaml @@ -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 diff --git a/osm_nbi/tests/clear-all.sh b/osm_nbi/tests/clear-all.sh index 5ba9d4b..c670106 100755 --- a/osm_nbi/tests/clear-all.sh +++ b/osm_nbi/tests/clear-all.sh @@ -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}" diff --git a/osm_nbi/tests/test.py b/osm_nbi/tests/test.py index bcdfadf..2fbc217 100755 --- a/osm_nbi/tests/test.py +++ b/osm_nbi/tests/test.py @@ -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) diff --git a/osm_nbi/validation.py b/osm_nbi/validation.py index da3dd04..62d9d22 100644 --- a/osm_nbi/validation.py +++ b/osm_nbi/validation.py @@ -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 -- 2.17.1