blob: 38cff6774b4748ed316cf41e64cf3a15d8b9f746 [file] [log] [blame]
tierno7edb6752016-03-21 17:37:52 +01001#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4##
tierno92021022018-09-12 16:29:23 +02005# Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
tierno7edb6752016-03-21 17:37:52 +01006# This file is part of openmano
7# All Rights Reserved.
8#
9# Licensed under the Apache License, Version 2.0 (the "License"); you may
10# not use this file except in compliance with the License. You may obtain
11# a copy of the License at
12#
13# http://www.apache.org/licenses/LICENSE-2.0
14#
15# Unless required by applicable law or agreed to in writing, software
16# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18# License for the specific language governing permissions and limitations
19# under the License.
20#
21# For those usages not covered by the Apache License, Version 2.0 please
22# contact with: nfvlabs@tid.es
23##
24
tierno99314902017-04-26 13:23:09 +020025"""
tierno7edb6752016-03-21 17:37:52 +010026openmano server.
27Main program that implements a reference NFVO (Network Functions Virtualisation Orchestrator).
28It interfaces with an NFV VIM through its API and offers a northbound interface, based on REST (openmano API),
29where NFV services are offered including the creation and deletion of VNF templates, VNF instances,
30network service templates and network service instances.
31
32It loads the configuration file and launches the http_server thread that will listen requests using openmano API.
tierno99314902017-04-26 13:23:09 +020033"""
tierno7edb6752016-03-21 17:37:52 +010034
tierno7edb6752016-03-21 17:37:52 +010035import time
tierno7edb6752016-03-21 17:37:52 +010036import sys
37import getopt
38import yaml
tierno92021022018-09-12 16:29:23 +020039from os import environ, path as os_path
tierno7edb6752016-03-21 17:37:52 +010040from jsonschema import validate as js_v, exceptions as js_e
tiernoae4a8d12016-07-08 12:30:39 +020041import logging
tiernof97fd272016-07-11 14:32:37 +020042import logging.handlers as log_handlers
tierno72f35a52016-07-15 13:18:30 +020043import socket
garciadeblas2c290ca2017-04-06 03:12:51 +020044from osm_ro import httpserver, nfvo, nfvo_db
45from osm_ro.openmano_schemas import config_schema
46from osm_ro.db_base import db_base_Exception
garciadeblas4b6216b2017-04-20 16:41:52 +020047import osm_ro
tierno7edb6752016-03-21 17:37:52 +010048
tierno11f81f62017-04-27 17:22:14 +020049__author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes"
50__date__ = "$26-aug-2014 11:09:29$"
tierno307a1ca2018-10-25 14:27:36 +020051__version__ = "0.5.80-r590"
tierno20a608c2018-10-02 13:43:47 +020052version_date = "Oct 2018"
tiernofc5f80b2018-05-29 16:00:43 +020053database_version = 32 # expected database schema version
gcalvinoe580c7d2017-09-22 14:09:51 +020054
tierno99314902017-04-26 13:23:09 +020055
tierno7edb6752016-03-21 17:37:52 +010056global global_config
tiernof97fd272016-07-11 14:32:37 +020057global logger
tiernoae4a8d12016-07-08 12:30:39 +020058
mirabal29356312017-07-27 12:21:22 +020059
tiernoae4a8d12016-07-08 12:30:39 +020060class LoadConfigurationException(Exception):
61 pass
tierno7edb6752016-03-21 17:37:52 +010062
tiernoad6bdd42018-01-10 10:43:46 +010063
tierno7edb6752016-03-21 17:37:52 +010064def load_configuration(configuration_file):
tiernoad6bdd42018-01-10 10:43:46 +010065 default_tokens = {'http_port': 9090,
66 'http_host': 'localhost',
tierno639520f2017-04-05 19:55:36 +020067 'http_console_proxy': True,
68 'http_console_host': None,
69 'log_level': 'DEBUG',
70 'log_socket_port': 9022,
71 'auto_push_VNF_to_VIMs': True,
72 'db_host': 'localhost',
73 'db_ovim_host': 'localhost'
74 }
tierno7edb6752016-03-21 17:37:52 +010075 try:
76 #Check config file exists
tierno72f35a52016-07-15 13:18:30 +020077 with open(configuration_file, 'r') as f:
78 config_str = f.read()
tierno7edb6752016-03-21 17:37:52 +010079 #Parse configuration file
tierno72f35a52016-07-15 13:18:30 +020080 config = yaml.load(config_str)
tierno7edb6752016-03-21 17:37:52 +010081 #Validate configuration file with the config_schema
tierno72f35a52016-07-15 13:18:30 +020082 js_v(config, config_schema)
tierno46df9672017-05-26 13:12:21 +020083
tierno72f35a52016-07-15 13:18:30 +020084 #Add default values tokens
tierno7edb6752016-03-21 17:37:52 +010085 for k,v in default_tokens.items():
tierno72f35a52016-07-15 13:18:30 +020086 if k not in config:
87 config[k]=v
88 return config
tierno46df9672017-05-26 13:12:21 +020089
tierno72f35a52016-07-15 13:18:30 +020090 except yaml.YAMLError as e:
91 error_pos = ""
92 if hasattr(e, 'problem_mark'):
93 mark = e.problem_mark
94 error_pos = " at line:{} column:{}".format(mark.line+1, mark.column+1)
tierno46df9672017-05-26 13:12:21 +020095 raise LoadConfigurationException("Bad YAML format at configuration file '{file}'{pos}: {message}".format(
96 file=configuration_file, pos=error_pos, message=e))
tierno72f35a52016-07-15 13:18:30 +020097 except js_e.ValidationError as e:
98 error_pos = ""
99 if e.path:
100 error_pos=" at '" + ":".join(map(str, e.path))+"'"
tierno46df9672017-05-26 13:12:21 +0200101 raise LoadConfigurationException("Invalid field at configuration file '{file}'{pos} {message}".format(
102 file=configuration_file, pos=error_pos, message=e))
tierno72f35a52016-07-15 13:18:30 +0200103 except Exception as e:
tierno46df9672017-05-26 13:12:21 +0200104 raise LoadConfigurationException("Cannot load configuration file '{file}' {message}".format(
105 file=configuration_file, message=e))
106
tierno7edb6752016-03-21 17:37:52 +0100107
108def console_port_iterator():
109 '''this iterator deals with the http_console_ports
110 returning the ports one by one
111 '''
112 index = 0
113 while index < len(global_config["http_console_ports"]):
114 port = global_config["http_console_ports"][index]
tiernoae4a8d12016-07-08 12:30:39 +0200115 #print("ports -> ", port)
tierno7edb6752016-03-21 17:37:52 +0100116 if type(port) is int:
117 yield port
118 else: #this is dictionary with from to keys
119 port2 = port["from"]
tiernoae4a8d12016-07-08 12:30:39 +0200120 #print("ports -> ", port, port2)
tierno7edb6752016-03-21 17:37:52 +0100121 while port2 <= port["to"]:
tiernoae4a8d12016-07-08 12:30:39 +0200122 #print("ports -> ", port, port2)
tierno7edb6752016-03-21 17:37:52 +0100123 yield port2
124 port2 += 1
125 index += 1
tierno46df9672017-05-26 13:12:21 +0200126
127
tierno7edb6752016-03-21 17:37:52 +0100128def usage():
tiernoae4a8d12016-07-08 12:30:39 +0200129 print("Usage: ", sys.argv[0], "[options]")
tiernod4d5e252018-01-23 17:07:46 +0100130 print(" -v|--version: prints current version")
131 print(" -c|--config [configuration_file]: loads the configuration file (default: openmanod.cfg)")
132 print(" -h|--help: shows this help")
133 print(" -p|--port [port_number]: changes port number and overrides the port number in the configuration file (default: 9090)")
134 print(" -P|--adminport [port_number]: changes admin port number and overrides the port number in the configuration file (default: 9095)")
135 # print( " -V|--vnf-repository: changes the path of the vnf-repository and overrides the path in the configuration file")
136 print(" --log-socket-host HOST: send logs to this host")
137 print(" --log-socket-port PORT: send logs using this port (default: 9022)")
138 print(" --log-file FILE: send logs to this file")
tierno9c5c8322018-03-23 15:44:03 +0100139 print(" --create-tenant NAME: Try to creates this tenant name before starting, ignoring any errors as e.g. conflict")
tierno7edb6752016-03-21 17:37:52 +0100140 return
tierno46df9672017-05-26 13:12:21 +0200141
142
143def set_logging_file(log_file):
144 try:
145 file_handler = logging.handlers.RotatingFileHandler(log_file, maxBytes=100e6, backupCount=9, delay=0)
146 file_handler.setFormatter(log_formatter_simple)
147 logger.addHandler(file_handler)
148 # logger.debug("moving logs to '%s'", global_config["log_file"])
149 # remove initial stream handler
150 logging.root.removeHandler(logging.root.handlers[0])
151 print ("logging on '{}'".format(log_file))
152 except IOError as e:
153 raise LoadConfigurationException(
154 "Cannot open logging file '{}': {}. Check folder exist and permissions".format(log_file, e))
155
156
tierno7edb6752016-03-21 17:37:52 +0100157if __name__=="__main__":
tierno92021022018-09-12 16:29:23 +0200158 # env2config contains envioron variable names and the correspondence with configuration file openmanod.cfg keys.
159 # If this environ is defined, this value is taken instead of the one at at configuration file
160 env2config = {
161 'RO_DB_HOST': 'db_host',
162 'RO_DB_NAME': 'db_name',
163 'RO_DB_USER': 'db_user',
164 'RO_DB_PASSWORD': 'db_passwd',
165 # 'RO_DB_PORT': 'db_port',
166 'RO_DB_OVIM_HOST': 'db_ovim_host',
167 'RO_DB_OVIM_NAME': 'db_ovim_name',
168 'RO_DB_OVIM_USER': 'db_ovim_user',
169 'RO_DB_OVIM_PASSWORD': 'db_ovim_passwd',
170 # 'RO_DB_OVIM_PORT': 'db_ovim_port',
tierno307a1ca2018-10-25 14:27:36 +0200171 'RO_LOG_LEVEL': 'log_level',
172 'RO_LOG_FILE': 'log_file',
tiernod4d5e252018-01-23 17:07:46 +0100173 }
tierno46df9672017-05-26 13:12:21 +0200174 # Configure logging step 1
tierno72f35a52016-07-15 13:18:30 +0200175 hostname = socket.gethostname()
tierno46df9672017-05-26 13:12:21 +0200176 # streamformat = "%(levelname)s (%(module)s:%(lineno)d) %(message)s"
tierno72f35a52016-07-15 13:18:30 +0200177 # "%(asctime)s %(name)s %(levelname)s %(filename)s:%(lineno)d %(funcName)s %(process)d: %(message)s"
tierno46df9672017-05-26 13:12:21 +0200178 log_formatter_complete = logging.Formatter('%(asctime)s.%(msecs)03d00Z[{host}@openmanod] %(filename)s:%(lineno)s '
179 'severity:%(levelname)s logger:%(name)s log:%(message)s'.format(
180 host=hostname),
181 datefmt='%Y-%m-%dT%H:%M:%S')
Ravi Chamarty0c46a382018-10-29 12:07:03 -0400182 log_format_simple = "%(asctime)s %(levelname)s %(name)s %(thread)d %(filename)s:%(lineno)s %(message)s"
tierno72f35a52016-07-15 13:18:30 +0200183 log_formatter_simple = logging.Formatter(log_format_simple, datefmt='%Y-%m-%dT%H:%M:%S')
184 logging.basicConfig(format=log_format_simple, level= logging.DEBUG)
185 logger = logging.getLogger('openmano')
tiernoae4a8d12016-07-08 12:30:39 +0200186 logger.setLevel(logging.DEBUG)
tierno72f35a52016-07-15 13:18:30 +0200187 socket_handler = None
tierno42026a02017-02-10 15:13:40 +0100188 # Read parameters and configuration file
189 httpthread = None
tierno7edb6752016-03-21 17:37:52 +0100190 try:
tierno9c5c8322018-03-23 15:44:03 +0100191 # load parameters and configuration
192 opts, args = getopt.getopt(sys.argv[1:], "hvc:V:p:P:",
193 ["config=", "help", "version", "port=", "vnf-repository=", "adminport=",
194 "log-socket-host=", "log-socket-port=", "log-file=", "create-tenant="])
tiernoae4a8d12016-07-08 12:30:39 +0200195 port=None
196 port_admin = None
garciadeblas4b6216b2017-04-20 16:41:52 +0200197 config_file = 'osm_ro/openmanod.cfg'
tiernoae4a8d12016-07-08 12:30:39 +0200198 vnf_repository = None
tierno205d1022016-07-21 11:26:22 +0200199 log_file = None
tierno72f35a52016-07-15 13:18:30 +0200200 log_socket_host = None
201 log_socket_port = None
tierno9c5c8322018-03-23 15:44:03 +0100202 create_tenant = None
tierno46df9672017-05-26 13:12:21 +0200203
tiernoae4a8d12016-07-08 12:30:39 +0200204 for o, a in opts:
205 if o in ("-v", "--version"):
tierno72f35a52016-07-15 13:18:30 +0200206 print ("openmanod version " + __version__ + ' ' + version_date)
207 print ("(c) Copyright Telefonica")
tiernoae4a8d12016-07-08 12:30:39 +0200208 sys.exit()
209 elif o in ("-h", "--help"):
210 usage()
211 sys.exit()
212 elif o in ("-V", "--vnf-repository"):
213 vnf_repository = a
214 elif o in ("-c", "--config"):
215 config_file = a
216 elif o in ("-p", "--port"):
217 port = a
218 elif o in ("-P", "--adminport"):
219 port_admin = a
tierno72f35a52016-07-15 13:18:30 +0200220 elif o == "--log-socket-port":
221 log_socket_port = a
tiernoa9a7e622016-09-30 08:43:32 +0000222 elif o == "--log-socket-host":
tierno72f35a52016-07-15 13:18:30 +0200223 log_socket_host = a
tierno205d1022016-07-21 11:26:22 +0200224 elif o == "--log-file":
225 log_file = a
tierno9c5c8322018-03-23 15:44:03 +0100226 elif o == "--create-tenant":
227 create_tenant = a
tiernoae4a8d12016-07-08 12:30:39 +0200228 else:
229 assert False, "Unhandled option"
tierno46df9672017-05-26 13:12:21 +0200230 if log_file:
231 set_logging_file(log_file)
tiernoae4a8d12016-07-08 12:30:39 +0200232 global_config = load_configuration(config_file)
tierno6ddeded2017-05-16 15:40:26 +0200233 global_config["version"] = __version__
234 global_config["version_date"] = version_date
tierno7edb6752016-03-21 17:37:52 +0100235 #print global_config
tiernod4d5e252018-01-23 17:07:46 +0100236 # Override parameters obtained by command line on ENV
tierno72f35a52016-07-15 13:18:30 +0200237 if port:
238 global_config['http_port'] = port
239 if port_admin:
240 global_config['http_admin_port'] = port_admin
241 if log_socket_host:
242 global_config['log_socket_host'] = log_socket_host
243 if log_socket_port:
244 global_config['log_socket_port'] = log_socket_port
tiernod4d5e252018-01-23 17:07:46 +0100245
246 # override with ENV
tierno92021022018-09-12 16:29:23 +0200247 for env_k, env_v in environ.items():
248 try:
249 if not env_k.startswith("RO_") or env_k not in env2config or not env_v:
250 continue
251 global_config[env2config[env_k]] = env_v
252 if env_k.endswith("PORT"): # convert to int, skip if not possible
253 global_config[env2config[env_k]] = int(env_v)
254 except Exception as e:
255 logger.warn("skipping environ '{}={}' because exception '{}'".format(env_k, env_v, e))
tiernod4d5e252018-01-23 17:07:46 +0100256
tierno72f35a52016-07-15 13:18:30 +0200257# if vnf_repository is not None:
258# global_config['vnf_repository'] = vnf_repository
259# else:
tierno46df9672017-05-26 13:12:21 +0200260# if not 'vnf_repository' in global_config:
tierno72f35a52016-07-15 13:18:30 +0200261# logger.error( os.getcwd() )
262# global_config['vnf_repository'] = os.getcwd()+'/vnfrepo'
263# #print global_config
264# if not os.path.exists(global_config['vnf_repository']):
265# logger.error( "Creating folder vnf_repository folder: '%s'.", global_config['vnf_repository'])
266# try:
267# os.makedirs(global_config['vnf_repository'])
268# except Exception as e:
269# logger.error( "Error '%s'. Ensure the path 'vnf_repository' is properly set at %s",e.args[1], config_file)
270# exit(-1)
tierno46df9672017-05-26 13:12:21 +0200271
tierno72f35a52016-07-15 13:18:30 +0200272 global_config["console_port_iterator"] = console_port_iterator
273 global_config["console_thread"]={}
274 global_config["console_ports"]={}
tierno20fc2a22016-08-19 17:02:35 +0200275 if not global_config["http_console_host"]:
276 global_config["http_console_host"] = global_config["http_host"]
277 if global_config["http_host"]=="0.0.0.0":
278 global_config["http_console_host"] = socket.gethostname()
tierno46df9672017-05-26 13:12:21 +0200279
280 # Configure logging STEP 2
tiernof97fd272016-07-11 14:32:37 +0200281 if "log_host" in global_config:
tierno72f35a52016-07-15 13:18:30 +0200282 socket_handler= log_handlers.SocketHandler(global_config["log_socket_host"], global_config["log_socket_port"])
283 socket_handler.setFormatter(log_formatter_complete)
tierno46df9672017-05-26 13:12:21 +0200284 if global_config.get("log_socket_level") and global_config["log_socket_level"] != global_config["log_level"]:
tierno72f35a52016-07-15 13:18:30 +0200285 socket_handler.setLevel(global_config["log_socket_level"])
tiernof97fd272016-07-11 14:32:37 +0200286 logger.addHandler(socket_handler)
tierno46df9672017-05-26 13:12:21 +0200287
288 # logger.addHandler(log_handlers.SysLogHandler())
289 if log_file:
290 global_config['log_file'] = log_file
291 elif global_config.get('log_file'):
292 set_logging_file(global_config['log_file'])
293
294 # logging.basicConfig(level = getattr(logging, global_config.get('log_level',"debug")))
tierno205d1022016-07-21 11:26:22 +0200295 logger.setLevel(getattr(logging, global_config['log_level']))
tierno46df9672017-05-26 13:12:21 +0200296 logger.critical("Starting openmano server version: '%s %s' command: '%s'",
tiernoaceb4642016-10-20 15:12:30 +0000297 __version__, version_date, " ".join(sys.argv))
tierno46df9672017-05-26 13:12:21 +0200298
tierno639520f2017-04-05 19:55:36 +0200299 for log_module in ("nfvo", "http", "vim", "db", "console", "ovim"):
tierno73ad9e42016-09-12 18:11:11 +0200300 log_level_module = "log_level_" + log_module
301 log_file_module = "log_file_" + log_module
302 logger_module = logging.getLogger('openmano.' + log_module)
303 if log_level_module in global_config:
304 logger_module.setLevel(global_config[log_level_module])
305 if log_file_module in global_config:
306 try:
tierno46df9672017-05-26 13:12:21 +0200307 file_handler = logging.handlers.RotatingFileHandler(global_config[log_file_module],
308 maxBytes=100e6, backupCount=9, delay=0)
tierno73ad9e42016-09-12 18:11:11 +0200309 file_handler.setFormatter(log_formatter_simple)
310 logger_module.addHandler(file_handler)
311 except IOError as e:
tierno46df9672017-05-26 13:12:21 +0200312 raise LoadConfigurationException(
313 "Cannot open logging file '{}': {}. Check folder exist and permissions".format(
314 global_config[log_file_module], str(e)) )
tierno73ad9e42016-09-12 18:11:11 +0200315 global_config["logger_"+log_module] = logger_module
316 #httpserver.logger = global_config["logger_http"]
317 #nfvo.logger = global_config["logger_nfvo"]
tierno46df9672017-05-26 13:12:21 +0200318
tierno7edb6752016-03-21 17:37:52 +0100319 # Initialize DB connection
tiernob13f3cc2016-09-26 10:14:44 +0200320 mydb = nfvo_db.nfvo_db();
tierno44528e42016-10-11 12:06:25 +0000321 mydb.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name'])
tierno11f81f62017-04-27 17:22:14 +0200322 db_path = osm_ro.__path__[0] + "/database_utils"
tiernod4d5e252018-01-23 17:07:46 +0100323 if not os_path.exists(db_path + "/migrate_mano_db.sh"):
tierno11f81f62017-04-27 17:22:14 +0200324 db_path = osm_ro.__path__[0] + "/../database_utils"
tierno44528e42016-10-11 12:06:25 +0000325 try:
326 r = mydb.get_db_version()
tierno11f81f62017-04-27 17:22:14 +0200327 if r[0] != database_version:
328 logger.critical("DATABASE wrong version '{current}'. Try to upgrade/downgrade to version '{target}'"
329 " with '{db_path}/migrate_mano_db.sh {target}'".format(
330 current=r[0], target=database_version, db_path=db_path))
tierno44528e42016-10-11 12:06:25 +0000331 exit(-1)
332 except db_base_Exception as e:
tierno11f81f62017-04-27 17:22:14 +0200333 logger.critical("DATABASE is not valid. If you think it is corrupted, you can init it with"
334 " '{db_path}/init_mano_db.sh' script".format(db_path=db_path))
tierno7edb6752016-03-21 17:37:52 +0100335 exit(-1)
tierno44528e42016-10-11 12:06:25 +0000336
tierno7edb6752016-03-21 17:37:52 +0100337 nfvo.global_config=global_config
tierno9c5c8322018-03-23 15:44:03 +0100338 if create_tenant:
339 try:
340 nfvo.new_tenant(mydb, {"name": create_tenant})
341 except Exception as e:
342 if isinstance(e, nfvo.NfvoException) and e.http_code == 409:
343 pass # if tenant exist (NfvoException error 409), ignore
344 else: # otherwise print and error and continue
345 logger.error("Cannot create tenant '{}': {}".format(create_tenant, e))
tierno42026a02017-02-10 15:13:40 +0100346 nfvo.start_service(mydb)
tierno46df9672017-05-26 13:12:21 +0200347
tierno7edb6752016-03-21 17:37:52 +0100348 httpthread = httpserver.httpserver(mydb, False, global_config['http_host'], global_config['http_port'])
tierno46df9672017-05-26 13:12:21 +0200349
tierno7edb6752016-03-21 17:37:52 +0100350 httpthread.start()
tierno46df9672017-05-26 13:12:21 +0200351 if 'http_admin_port' in global_config:
tierno7edb6752016-03-21 17:37:52 +0100352 httpthreadadmin = httpserver.httpserver(mydb, True, global_config['http_host'], global_config['http_admin_port'])
353 httpthreadadmin.start()
tierno46df9672017-05-26 13:12:21 +0200354 time.sleep(1)
tiernoae4a8d12016-07-08 12:30:39 +0200355 logger.info('Waiting for http clients')
tierno205d1022016-07-21 11:26:22 +0200356 print('Waiting for http clients')
tiernoae4a8d12016-07-08 12:30:39 +0200357 print('openmanod ready')
358 print('====================')
tierno7edb6752016-03-21 17:37:52 +0100359 time.sleep(20)
360 sys.stdout.flush()
361
362 #TODO: Interactive console must be implemented here instead of join or sleep
363
364 #httpthread.join()
tierno42026a02017-02-10 15:13:40 +0100365 #if 'http_admin_port' in global_config:
tierno7edb6752016-03-21 17:37:52 +0100366 # httpthreadadmin.join()
367 while True:
368 time.sleep(86400)
tierno7edb6752016-03-21 17:37:52 +0100369
tierno72f35a52016-07-15 13:18:30 +0200370 except KeyboardInterrupt as e:
371 logger.info(str(e))
tierno809a7802016-07-08 13:31:24 +0200372 except SystemExit:
373 pass
tiernoae4a8d12016-07-08 12:30:39 +0200374 except getopt.GetoptError as e:
tierno72f35a52016-07-15 13:18:30 +0200375 logger.critical(str(e)) # will print something like "option -a not recognized"
tiernoae4a8d12016-07-08 12:30:39 +0200376 #usage()
377 exit(-1)
378 except LoadConfigurationException as e:
tierno72f35a52016-07-15 13:18:30 +0200379 logger.critical(str(e))
tiernoae4a8d12016-07-08 12:30:39 +0200380 exit(-1)
tierno44528e42016-10-11 12:06:25 +0000381 except db_base_Exception as e:
382 logger.critical(str(e))
383 exit(-1)
tierno46df9672017-05-26 13:12:21 +0200384 except nfvo.NfvoException as e:
385 logger.critical(str(e), exc_info=True)
386 exit(-1)
tierno42026a02017-02-10 15:13:40 +0100387 nfvo.stop_service()
388 if httpthread:
389 httpthread.join(1)
tierno7edb6752016-03-21 17:37:52 +0100390