2 # -*- coding: utf-8 -*-
5 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
6 # This file is part of openmano
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
13 # http://www.apache.org/licenses/LICENSE-2.0
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
21 # For those usages not covered by the Apache License, Version 2.0 please
22 # contact with: nfvlabs@tid.es
27 Main program that implements a reference NFVO (Network Functions Virtualisation Orchestrator).
28 It interfaces with an NFV VIM through its API and offers a northbound interface, based on REST (openmano API),
29 where NFV services are offered including the creation and deletion of VNF templates, VNF instances,
30 network service templates and network service instances.
32 It loads the configuration file and launches the http_server thread that will listen requests using openmano API.
34 __author__
="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
35 __date__
="$26-aug-2014 11:09:29$"
36 __version__
="0.4.41-r478"
37 version_date
="Jul 2016"
38 database_version
="0.10" #expected database schema version
47 from jsonschema
import validate
as js_v
, exceptions
as js_e
49 from openmano_schemas
import config_schema
52 import logging
.handlers
as log_handlers
56 logger
= logging
.getLogger('openmano')
58 class LoadConfigurationException(Exception):
61 def load_configuration(configuration_file
):
62 default_tokens
={'http_port':9090,
63 'http_host':'localhost',
65 'log_level_db': 'ERROR',
66 'log_level_vimconn': 'DEBUG',
67 'log_level_nfvo': 'DEBUG',
70 #Check config file exists
71 if not os
.path
.isfile(configuration_file
):
72 raise LoadConfigurationException("Error: Configuration file '"+configuration_file
+"' does not exist.")
75 (return_status
, code
) = utils
.read_file(configuration_file
)
77 raise LoadConfigurationException("Error loading configuration file '"+configuration_file
+"': "+code
)
78 #Parse configuration file
80 config
= yaml
.load(code
)
81 except yaml
.YAMLError
, exc
:
83 if hasattr(exc
, 'problem_mark'):
84 mark
= exc
.problem_mark
85 error_pos
= " at position: (%s:%s)" % (mark
.line
+1, mark
.column
+1)
86 raise LoadConfigurationException("Error loading configuration file '"+configuration_file
+"'"+error_pos
+": content format error: Failed to parse yaml format")
88 #Validate configuration file with the config_schema
90 js_v(config
, config_schema
)
91 except js_e
.ValidationError
, exc
:
93 if len(exc
.path
)>0: error_pos
=" at '" + ":".join(map(str, exc
.path
))+"'"
94 raise LoadConfigurationException("Error loading configuration file '"+configuration_file
+"'"+error_pos
+": "+exc
.message
)
96 #Check default values tokens
97 for k
,v
in default_tokens
.items():
98 if k
not in config
: config
[k
]=v
101 raise LoadConfigurationException("Error loading configuration file '"+configuration_file
+"': "+str(e
))
105 def console_port_iterator():
106 '''this iterator deals with the http_console_ports
107 returning the ports one by one
110 while index
< len(global_config
["http_console_ports"]):
111 port
= global_config
["http_console_ports"][index
]
112 #print("ports -> ", port)
113 if type(port
) is int:
115 else: #this is dictionary with from to keys
117 #print("ports -> ", port, port2)
118 while port2
<= port
["to"]:
119 #print("ports -> ", port, port2)
126 print("Usage: ", sys
.argv
[0], "[options]")
127 print( " -v|--version: prints current version")
128 print( " -c|--config [configuration_file]: loads the configuration file (default: openmanod.cfg)")
129 print( " -h|--help: shows this help")
130 print( " -p|--port [port_number]: changes port number and overrides the port number in the configuration file (default: 9090)")
131 print( " -P|--adminport [port_number]: changes admin port number and overrides the port number in the configuration file (default: 9095)")
132 print( " -V|--vnf-repository: changes the path of the vnf-repository and overrides the path in the configuration file")
135 if __name__
=="__main__":
136 #streamformat = "%(levelname)s (%(module)s:%(lineno)d) %(message)s"
137 logging_local_format
= "%(asctime)s %(name)s %(levelname)s: %(message)s"
138 logging_complete_format
= "%(asctime)s %(name)s %(levelname)s %(filename)s:%(lineno)d %(funcName)s %(process)d: %(message)s"
139 logging
.basicConfig(format
=logging_local_format
, level
= logging
.DEBUG
)
140 logger
.setLevel(logging
.DEBUG
)
142 # Read parameters and configuration file
144 opts
, args
= getopt
.getopt(sys
.argv
[1:], "hvc:V:p:P:", ["config", "help", "version", "port", "vnf-repository", "adminport"])
148 config_file
= 'openmanod.cfg'
149 vnf_repository
= None
152 if o
in ("-v", "--version"):
153 print "openmanod version", __version__
, version_date
154 print "(c) Copyright Telefonica"
156 elif o
in ("-h", "--help"):
159 elif o
in ("-V", "--vnf-repository"):
161 elif o
in ("-c", "--config"):
163 elif o
in ("-p", "--port"):
165 elif o
in ("-P", "--adminport"):
168 assert False, "Unhandled option"
170 global_config
= load_configuration(config_file
)
172 logging
.basicConfig(level
= getattr(logging
, global_config
.get('log_level',"debug")))
173 logger
.setLevel(getattr(logging
, global_config
['log_level']))
174 if "log_host" in global_config
:
175 socket_handler
= log_handlers
.SocketHandler(global_config
["log_host"], global_config
["log_port"])
176 logger
.addHandler(socket_handler
)
177 logger
.addHandler(log_handlers
.SysLogHandler())
178 if "log_file" in global_config
:
180 file_handler
= logging
.handlers
.RotatingFileHandler(global_config
["log_file"], maxBytes
=100e6
, backupCount
=9, delay
=0)
181 file_handler
.setFormatter(logging
.Formatter(fmt
=logging_complete_format
))
182 logger
.addHandler(file_handler
)
184 print "Error opening logging file '{}': {}. Check folder exist and permissions".fomat(global_config
["log_file"], str(e
))
185 # Override parameters obtained by command line
186 print logger
.handlers
187 if port
is not None: global_config
['http_port'] = port
188 if port_admin
is not None: global_config
['http_admin_port'] = port_admin
189 if vnf_repository
is not None:
190 global_config
['vnf_repository'] = vnf_repository
192 if not 'vnf_repository' in global_config
:
193 logger
.error( os
.getcwd() )
194 global_config
['vnf_repository'] = os
.getcwd()+'/vnfrepo'
197 if not os
.path
.exists(global_config
['vnf_repository']):
198 logger
.error( "Creating folder vnf_repository folder: '%s'.", global_config
['vnf_repository'])
200 os
.makedirs(global_config
['vnf_repository'])
201 except Exception as e
:
202 logger
.error( "Error '%s'. Ensure the path 'vnf_repository' is properly set at %s",e
.args
[1], config_file
)
205 global_config
["console_port_iterator"] = console_port_iterator
206 global_config
["console_thread"]={}
207 global_config
["console_ports"]={}
208 # Initialize DB connection
209 mydb
= nfvo_db
.nfvo_db(log_level
=global_config
["log_level_db"]);
210 if mydb
.connect(global_config
['db_host'], global_config
['db_user'], global_config
['db_passwd'], global_config
['db_name']) == -1:
211 logger
.error("Error connecting to database %s at %s@%s", global_config
['db_name'], global_config
['db_user'], global_config
['db_host'])
213 r
= mydb
.get_db_version()
215 logger
.error("Error DATABASE is not a MANO one or it is a '0.0' version. Try to upgrade to version '%s' with './database_utils/migrate_mano_db.sh'", database_version
)
217 elif r
[1]!=database_version
:
218 logger
.error("Error DATABASE wrong version '%s'. Try to upgrade/downgrade to version '%s' with './database_utils/migrate_mano_db.sh'", r
[1], database_version
)
221 nfvo
.global_config
=global_config
223 httpthread
= httpserver
.httpserver(mydb
, False, global_config
['http_host'], global_config
['http_port'])
226 if 'http_admin_port' in global_config
:
227 httpthreadadmin
= httpserver
.httpserver(mydb
, True, global_config
['http_host'], global_config
['http_admin_port'])
228 httpthreadadmin
.start()
230 logger
.info('Waiting for http clients')
231 print('openmanod ready')
232 print('====================')
236 #TODO: Interactive console must be implemented here instead of join or sleep
239 #if 'http_admin_port' in global_config:
240 # httpthreadadmin.join()
243 for thread
in global_config
["console_thread"]:
244 thread
.terminate
= True
246 except KeyboardInterrupt:
247 logger
.info('KyboardInterrupt')
250 except getopt
.GetoptError
as e
:
251 logger
.error("Error: %s", str(e
)) # will print something like "option -a not recognized"
254 except LoadConfigurationException
as e
:
255 logger
.error("Error: %s", str(e
))