ENV OSMNBI_MESSAGE_DRIVER kafka
ENV OSMNBI_MESSAGE_HOST kafka
ENV OSMNBI_MESSAGE_PORT 9092
+# logs
+ENV OSMNBI_LOG_FILE /app/log/nbi.log
+ENV OSMNBI_LOG_LEVEL DEBUG
# Run app.py when the container launches
CMD ["python3", "nbi.py"]
raise EngineException("name '{}' already exists for {}".format(indata["name"], item),
HTTPStatus.CONFLICT)
+ def _check_ns_operation(self, session, nsr, 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
+ """
+ if operation == "action":
+ if indata.get("vnf_member_index"):
+ indata["member_vnf_index"] = indata.pop("vnf_member_index") # for backward compatibility
+ for vnf in nsr["nsd"]["constituent-vnfd"]:
+ if indata["member_vnf_index"] == vnf["member-vnf-index"]:
+ # TODO get vnfd, check primitives
+ break
+ else:
+ raise EngineException("Invalid parameter member_vnf_index='{}' is not one of the nsd "
+ "constituent-vnfd".format(indata["member_vnf_index"]))
+
def _format_new_data(self, session, item, indata):
now = time()
if not "_admin" in indata:
except ValidationError as e:
raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
- def new_nslcmop(self, session, nsInstanceId, action, params):
+ def new_nslcmop(self, session, nsInstanceId, operation, params):
now = time()
_id = str(uuid4())
nslcmop = {
"operationState": "PROCESSING", # COMPLETED,PARTIALLY_COMPLETED,FAILED_TEMP,FAILED,ROLLING_BACK,ROLLED_BACK
"statusEnteredTime": now,
"nsInstanceId": nsInstanceId,
- "lcmOperationType": action,
+ "lcmOperationType": operation,
"startTime": now,
"isAutomaticInvocation": False,
"operationParams": params,
}
return nslcmop
- def ns_action(self, session, nsInstanceId, action, indata, kwargs=None):
+ def ns_operation(self, session, nsInstanceId, operation, indata, kwargs=None):
"""
- Performs a new action over a ns
+ Performs a new operation over a ns
:param session: contains the used login username and working project
- :param nsInstanceId: _id of the nsr to perform the action
- :param action: it can be: instantiate, terminate, action, TODO: update, heal
- :param indata: descriptor with the parameters of the action
+ :param nsInstanceId: _id of the nsr to perform the operation
+ :param operation: it can be: instantiate, terminate, action, TODO: update, heal
+ :param indata: descriptor with the parameters of the operation
:param kwargs: used to override the indata descriptor
:return: id of the nslcmops
"""
try:
# Override descriptor with query string kwargs
self._update_descriptor(indata, kwargs)
- validate_input(indata, "ns_" + action, new=True)
+ validate_input(indata, "ns_" + operation, new=True)
# get ns from nsr_id
nsr = self.get_item(session, "nsrs", nsInstanceId)
if not nsr["_admin"].get("nsState") or nsr["_admin"]["nsState"] == "NOT_INSTANTIATED":
- if action == "terminate" and indata.get("autoremove"):
+ if operation == "terminate" and indata.get("autoremove"):
# NSR must be deleted
return self.del_item(session, "nsrs", nsInstanceId)
- if action != "instantiate":
+ if operation != "instantiate":
raise EngineException("ns_instance '{}' cannot be '{}' because it is not instantiated".format(
- nsInstanceId, action), HTTPStatus.CONFLICT)
+ nsInstanceId, operation), HTTPStatus.CONFLICT)
else:
- if action == "instantiate" and not indata.get("force"):
+ if operation == "instantiate" and not indata.get("force"):
raise EngineException("ns_instance '{}' cannot be '{}' because it is already instantiated".format(
- nsInstanceId, action), HTTPStatus.CONFLICT)
+ nsInstanceId, operation), HTTPStatus.CONFLICT)
indata["nsInstanceId"] = nsInstanceId
- # TODO
- nslcmop = self.new_nslcmop(session, nsInstanceId, action, indata)
+ self._check_ns_operation(session, nsr, operation, indata)
+ nslcmop = self.new_nslcmop(session, nsInstanceId, operation, indata)
self._format_new_data(session, "nslcmops", nslcmop)
_id = self.db.create("nslcmops", nslcmop)
indata["_id"] = _id
- self.msg.write("ns", action, nslcmop)
+ self.msg.write("ns", operation, nslcmop)
return _id
except ValidationError as e:
raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY)
nsr = self.db.get_one(item, filter)
if nsr["_admin"]["nsState"] == "INSTANTIATED" and not force:
raise EngineException("nsr '{}' cannot be deleted because it is in 'INSTANTIATED' state. "
- "Launch 'terminate' action first; or force deletion".format(_id),
+ "Launch 'terminate' operation first; or force deletion".format(_id),
http_code=HTTPStatus.CONFLICT)
v = self.db.del_one(item, {"_id": _id})
self.db.del_list("nslcmops", {"nsInstanceId": _id})
-0.1.5
-2018-05-14
+0.1.6
+2018-05-16
log.access_file: ""
log.error_file: ""
-loglevel: "DEBUG"
-#logfile: /var/log/osm/nbi.log
+log.level: "DEBUG"
+#log.file: /var/log/osm/nbi.log
[database]
import yaml
import html_out as html
import logging
+import logging.handlers
+import getopt
+import sys
from engine import Engine, EngineException
from osm_common.dbbase import DbException
from osm_common.fsbase import FsException
from http import HTTPStatus
#from http.client import responses as http_responses
from codecs import getreader
-from os import environ
+from os import environ, path
__author__ = "Alfonso Tierno <alfonso.tiernosepulveda@telefonica.com>"
elif item == "ns_instances_content":
_id = self.engine.new_item(session, engine_item, indata, kwargs, force=force)
rollback = {"session": session, "item": engine_item, "_id": _id, "force": True}
- self.engine.ns_action(session, _id, "instantiate", {}, None)
+ self.engine.ns_operation(session, _id, "instantiate", {}, None)
self._set_location_header(topic, version, item, _id)
outdata = {"id": _id}
elif item == "ns_instances" and item2:
- _id = self.engine.ns_action(session, _id, item2, indata, kwargs)
+ _id = self.engine.ns_operation(session, _id, item2, indata, kwargs)
self._set_location_header(topic, version, "ns_lcm_op_occs", _id)
outdata = {"id": _id}
cherrypy.response.status = HTTPStatus.ACCEPTED.value
cherrypy.response.status = HTTPStatus.OK.value
else: # len(args) > 1
if item == "ns_instances_content":
- opp_id = self.engine.ns_action(session, _id, "terminate", {"autoremove": True}, None)
+ opp_id = self.engine.ns_operation(session, _id, "terminate", {"autoremove": True}, None)
outdata = {"_id": opp_id}
cherrypy.response.status = HTTPStatus.ACCEPTED.value
else:
update_dict['server.socket_port'] = int(v)
elif k == 'OSMNBI_SOCKET_HOST' or k == 'OSMNBI_SERVER_HOST':
update_dict['server.socket_host'] = v
- elif k1 == "server":
- update_dict['server' + k2] = v
- # TODO add more entries
+ elif k1 in ("server", "test", "auth", "log"):
+ update_dict[k1 + '.' + k2] = v
elif k1 in ("message", "database", "storage"):
+ # k2 = k2.replace('_', '.')
if k2 == "port":
engine_config[k1][k2] = int(v)
else:
if update_dict:
cherrypy.config.update(update_dict)
+ engine_config["global"].update(update_dict)
# logging cherrypy
log_format_simple = "%(asctime)s %(levelname)s %(name)s %(filename)s:%(lineno)s %(message)s"
logger_cherry = logging.getLogger("cherrypy")
logger_nbi = logging.getLogger("nbi")
- if "logfile" in engine_config["global"]:
- file_handler = logging.handlers.RotatingFileHandler(engine_config["global"]["logfile"],
+ if "log.file" in engine_config["global"]:
+ file_handler = logging.handlers.RotatingFileHandler(engine_config["global"]["log.file"],
maxBytes=100e6, backupCount=9, delay=0)
file_handler.setFormatter(log_formatter_simple)
logger_cherry.addHandler(file_handler)
str_handler.setFormatter(log_formatter_cherry)
logger.addHandler(str_handler)
- if engine_config["global"].get("loglevel"):
- logger_cherry.setLevel(engine_config["global"]["loglevel"])
- logger_nbi.setLevel(engine_config["global"]["loglevel"])
+ if engine_config["global"].get("log.level"):
+ logger_cherry.setLevel(engine_config["global"]["log.level"])
+ logger_nbi.setLevel(engine_config["global"]["log.level"])
# logging other modules
for k1, logname in {"message": "nbi.msg", "database": "nbi.db", "storage": "nbi.fs"}.items():
cherrypy.tree.apps['/osm'].root.engine.stop()
cherrypy.log.error("Stopping osm_nbi")
-def nbi():
+def nbi(config_file):
# conf = {
# '/': {
# #'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
# 'tools.auth_basic.checkpassword': validate_password})
cherrypy.engine.subscribe('start', _start_service)
cherrypy.engine.subscribe('stop', _stop_service)
- cherrypy.quickstart(Server(), '/osm', "nbi.cfg")
+ cherrypy.quickstart(Server(), '/osm', config_file)
+
+
+def usage():
+ print("""Usage: {} [options]
+ -c|--config [configuration_file]: loads the configuration file (default: ./nbi.cfg)
+ -h|--help: shows this help
+ """.format(sys.argv[0]))
+ # --log-socket-host HOST: send logs to this host")
+ # --log-socket-port PORT: send logs using this port (default: 9022)")
if __name__ == '__main__':
- nbi()
+ try:
+ # load parameters and configuration
+ opts, args = getopt.getopt(sys.argv[1:], "hvc:", ["config=", "help"])
+ # TODO add "log-socket-host=", "log-socket-port=", "log-file="
+ config_file = None
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ usage()
+ sys.exit()
+ elif o in ("-c", "--config"):
+ config_file = a
+ # elif o == "--log-socket-port":
+ # log_socket_port = a
+ # elif o == "--log-socket-host":
+ # log_socket_host = a
+ # elif o == "--log-file":
+ # log_file = a
+ else:
+ assert False, "Unhandled option"
+ if config_file:
+ if not path.isfile(config_file):
+ print("configuration file '{}' that not exist".format(config_file), file=sys.stderr)
+ exit(1)
+ else:
+ for config_file in (__file__[:__file__.rfind(".")] + ".cfg", "./nbi.cfg", "/etc/osm/nbi.cfg"):
+ if path.isfile(config_file):
+ break
+ else:
+ print("No configuration file 'nbi.cfg' found neither at local folder nor at /etc/osm/", file=sys.stderr)
+ exit(1)
+ nbi(config_file)
+ except getopt.GetoptError as e:
+ print(str(e), file=sys.stderr)
+ # usage()
+ exit(1)
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
- "vnf_member_index": name_schema,
+ "member_vnf_index": name_schema,
+ "vnf_member_index": name_schema, # TODO for backward compatibility. To remove in future
"primitive": name_schema,
"primitive_params": {"type": "object"},
},
- "required": ["vnf_member_index", "primitive", "primitive_params"],
+ "required": ["primitive", "primitive_params"], # TODO add member_vnf_index
"additionalProperties": False
}