X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FNBI.git;a=blobdiff_plain;f=osm_nbi%2Fnbi.py;h=2dfeb22e52bc5398ff740be4d92ea5238203cb1c;hp=c5262a8568de55ebdaaf6cdf0d1f4d0d955d5806;hb=f717cbe40358a8a8246d7936064cf235e2ff7f79;hpb=36ec86019fa668dddbbe0cf9d9ec53b9ea6569cf diff --git a/osm_nbi/nbi.py b/osm_nbi/nbi.py index c5262a8..2dfeb22 100644 --- a/osm_nbi/nbi.py +++ b/osm_nbi/nbi.py @@ -1,6 +1,19 @@ #!/usr/bin/python3 # -*- coding: utf-8 -*- +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import cherrypy import time import json @@ -33,7 +46,7 @@ auth_database_version = '1.0' """ North Bound Interface (O: OSM specific; 5,X: SOL005 not implemented yet; O5: SOL005 implemented) URL: /osm GET POST PUT DELETE PATCH - /nsd/v1 O O + /nsd/v1 /ns_descriptors_content O O / O O O O /ns_descriptors O5 O5 @@ -76,9 +89,11 @@ URL: /osm GET POST / O /subscriptions 5 5 / 5 X + /pdu/v1 /pdu_descriptor O O / O O O O + /admin/v1 /tokens O O / O O @@ -91,6 +106,30 @@ URL: /osm GET POST /sdns O O / O O O + /nst/v1 O O + /netslice_templates_content O O + / O O O O + /netslice_templates O O + / O O O + /nst_content O O + /nst O + /artifacts[/] O + /subscriptions X X + / X X + + /nsilcm/v1 + /netslice_instances_content O O + / O O + /netslice_instances O O + / O O + instantiate O + terminate O + action O + /nsi_lcm_op_occs O O + / O O O + /subscriptions X X + / X X + query string: Follows SOL005 section 4.3.2 It contains extra METHOD to override http method, FORCE to force. simpleFilterExpr := ["."]*["."]"="[","]* @@ -252,6 +291,40 @@ class Server(object): }, } }, + "nst": { + "v1": { + "netslice_templates_content": {"METHODS": ("GET", "POST"), + "": {"METHODS": ("GET", "PUT", "DELETE")} + }, + "netslice_templates": {"METHODS": ("GET", "POST"), + "": {"METHODS": ("GET", "DELETE"), "TODO": "PATCH", + "nst_content": {"METHODS": ("GET", "PUT")}, + "nst": {"METHODS": "GET"}, # descriptor inside package + "artifacts": {"*": {"METHODS": "GET"}} + } + }, + "subscriptions": {"TODO": ("GET", "POST"), + "": {"TODO": ("GET", "DELETE")} + }, + } + }, + "nsilcm": { + "v1": { + "netslice_instances_content": {"METHODS": ("GET", "POST"), + "": {"METHODS": ("GET", "DELETE")} + }, + "netslice_instances": {"METHODS": ("GET", "POST"), + "": {"METHODS": ("GET", "DELETE"), + "terminate": {"METHODS": "POST"}, + "instantiate": {"METHODS": "POST"}, + "action": {"METHODS": "POST"}, + } + }, + "nsi_lcm_op_occs": {"METHODS": "GET", + "": {"METHODS": "GET"}, + }, + } + }, } def _format_in(self, kwargs): @@ -371,7 +444,8 @@ class Server(object): elif "application/yaml" in accept or "*/*" in accept or "text/plain" in accept: pass - else: + # if there is not any valid accept, raise an error. But if response is already an error, format in yaml + elif cherrypy.response.status >= 400: raise cherrypy.HTTPError(HTTPStatus.NOT_ACCEPTABLE.value, "Only 'Accept' of type 'application/json' or 'application/yaml' " "for output format are available") @@ -471,7 +545,7 @@ class Server(object): def test(self, *args, **kwargs): thread_info = None if args and args[0] == "help": - return "
\ninit\nfile/  download file\ndb-clear/table\nprune\nlogin\nlogin2\n"\
+            return "
\ninit\nfile/  download file\ndb-clear/table\nfs-clear[/folder]\nlogin\nlogin2\n"\
                    "sleep/
" elif args and args[0] == "init": @@ -492,9 +566,16 @@ class Server(object): return f elif len(args) == 2 and args[0] == "db-clear": - return self.engine.db.del_list(args[1], kwargs) - elif args and args[0] == "prune": - return self.engine.prune() + deleted_info = self.engine.db.del_list(args[1], kwargs) + return "{} {} deleted\n".format(deleted_info["deleted"], args[1]) + elif len(args) and args[0] == "fs-clear": + if len(args) >= 2: + folders = (args[1],) + else: + folders = self.engine.fs.dir_ls(".") + for folder in folders: + self.engine.fs.file_delete(folder) + return ",".join(folders) + " folders deleted\n" elif args and args[0] == "login": if not cherrypy.request.headers.get("Authorization"): cherrypy.response.headers["WWW-Authenticate"] = 'Basic realm="Access to OSM site", charset="UTF-8"' @@ -541,7 +622,7 @@ class Server(object): " session: {}\n".format(cherrypy.session) + " cookie: {}\n".format(cherrypy.request.cookie) + " method: {}\n".format(cherrypy.request.method) + - " session: {}\n".format(cherrypy.session.get('fieldname')) + + " session: {}\n".format(cherrypy.session.get('fieldname')) + " body:\n") return_text += " length: {}\n".format(cherrypy.request.body.length) if cherrypy.request.body.length: @@ -606,7 +687,7 @@ class Server(object): if not main_topic or not version or not topic: raise NbiException("URL must contain at least 'main_topic/version/topic'", HTTPStatus.METHOD_NOT_ALLOWED) - if main_topic not in ("admin", "vnfpkgm", "nsd", "nslcm", "pdu"): + if main_topic not in ("admin", "vnfpkgm", "nsd", "nslcm", "pdu", "nst", "nsilcm"): raise NbiException("URL main_topic '{}' not supported".format(main_topic), HTTPStatus.METHOD_NOT_ALLOWED) if version != 'v1': @@ -620,9 +701,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) @@ -645,14 +724,20 @@ class Server(object): engine_topic = "nslcmops" if topic == "vnfrs" or topic == "vnf_instances": engine_topic = "vnfrs" + elif main_topic == "nst": + engine_topic = "nsts" + elif main_topic == "nsilcm": + engine_topic = "nsis" + if topic == "nsi_lcm_op_occs": + engine_topic = "nsilcmops" elif main_topic == "pdu": engine_topic = "pdus" if engine_topic == "vims": # TODO this is for backward compatibility, it will remove in the future engine_topic = "vim_accounts" if method == "GET": - if item in ("nsd_content", "package_content", "artifacts", "vnfd", "nsd"): - if item in ("vnfd", "nsd"): + if item in ("nsd_content", "package_content", "artifacts", "vnfd", "nsd", "nst", "nst_content"): + if item in ("vnfd", "nsd", "nst"): path = "$DESCRIPTOR" elif args: path = args @@ -668,7 +753,7 @@ class Server(object): else: outdata = self.engine.get_item(session, engine_topic, _id) elif method == "POST": - if topic in ("ns_descriptors_content", "vnf_packages_content"): + if topic in ("ns_descriptors_content", "vnf_packages_content", "netslice_templates_content"): _id = cherrypy.request.headers.get("Transaction-Id") if not _id: _id = self.engine.new_item(rollback, session, engine_topic, {}, None, cherrypy.request.headers, @@ -696,6 +781,22 @@ class Server(object): self._set_location_header(main_topic, version, "ns_lcm_op_occs", _id) outdata = {"id": _id} cherrypy.response.status = HTTPStatus.ACCEPTED.value + elif topic == "netslice_instances_content": + # creates NetSlice_Instance_record (NSIR) + _id = self.engine.new_item(rollback, session, engine_topic, indata, kwargs, force=force) + self._set_location_header(main_topic, version, topic, _id) + indata["lcmOperationType"] = "instantiate" + indata["nsiInstanceId"] = _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 + _id = self.engine.new_item(rollback, session, "nsilcmops", indata, kwargs) + self._set_location_header(main_topic, version, "nsi_lcm_op_occs", _id) + outdata = {"id": _id} + cherrypy.response.status = HTTPStatus.ACCEPTED.value else: _id = self.engine.new_item(rollback, session, engine_topic, indata, kwargs, cherrypy.request.headers, force=force) @@ -718,6 +819,15 @@ class Server(object): opp_id = self.engine.new_item(rollback, session, "nslcmops", nslcmop_desc, None) outdata = {"_id": opp_id} cherrypy.response.status = HTTPStatus.ACCEPTED.value + elif topic == "netslice_instances_content" and not force: + nsilcmop_desc = { + "lcmOperationType": "terminate", + "nsiInstanceId": _id, + "autoremove": True + } + opp_id = self.engine.new_item(rollback, session, "nsilcmops", nsilcmop_desc, None) + outdata = {"_id": opp_id} + cherrypy.response.status = HTTPStatus.ACCEPTED.value else: self.engine.del_item(session, engine_topic, _id, force) cherrypy.response.status = HTTPStatus.NO_CONTENT.value @@ -729,7 +839,7 @@ class Server(object): if not indata and not kwargs: raise NbiException("Nothing to update. Provide payload and/or query string", HTTPStatus.BAD_REQUEST) - if item in ("nsd_content", "package_content") and method == "PUT": + if item in ("nsd_content", "package_content", "nst_content") and method == "PUT": completed = self.engine.upload_content(session, engine_topic, _id, indata, kwargs, cherrypy.request.headers, force=force) if not completed: @@ -748,7 +858,7 @@ class Server(object): cherrypy.log("Exception {}".format(e)) else: http_code_value = cherrypy.response.status = HTTPStatus.BAD_REQUEST.value # INTERNAL_SERVER_ERROR - cherrypy.log("CRITICAL: Exception {}".format(e)) + cherrypy.log("CRITICAL: Exception {}".format(e), traceback=True) http_code_name = HTTPStatus.BAD_REQUEST.name if hasattr(outdata, "close"): # is an open file outdata.close()