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.40-r476"
37 version_date
="Jun 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
54 logger
= logging
.getLogger('mano')
56 class LoadConfigurationException(Exception):
59 def load_configuration(configuration_file
):
60 default_tokens
={'http_port':9090,
61 'http_host':'localhost',
63 'log_level_db': 'ERROR',
64 'log_level_vimconn': 'DEBUG',
67 #Check config file exists
68 if not os
.path
.isfile(configuration_file
):
69 raise LoadConfigurationException("Error: Configuration file '"+configuration_file
+"' does not exist.")
72 (return_status
, code
) = utils
.read_file(configuration_file
)
74 raise LoadConfigurationException("Error loading configuration file '"+configuration_file
+"': "+code
)
75 #Parse configuration file
77 config
= yaml
.load(code
)
78 except yaml
.YAMLError
, exc
:
80 if hasattr(exc
, 'problem_mark'):
81 mark
= exc
.problem_mark
82 error_pos
= " at position: (%s:%s)" % (mark
.line
+1, mark
.column
+1)
83 raise LoadConfigurationException("Error loading configuration file '"+configuration_file
+"'"+error_pos
+": content format error: Failed to parse yaml format")
85 #Validate configuration file with the config_schema
87 js_v(config
, config_schema
)
88 except js_e
.ValidationError
, exc
:
90 if len(exc
.path
)>0: error_pos
=" at '" + ":".join(map(str, exc
.path
))+"'"
91 raise LoadConfigurationException("Error loading configuration file '"+configuration_file
+"'"+error_pos
+": "+exc
.message
)
93 #Check default values tokens
94 for k
,v
in default_tokens
.items():
95 if k
not in config
: config
[k
]=v
98 raise LoadConfigurationException("Error loading configuration file '"+configuration_file
+"': "+str(e
))
102 def console_port_iterator():
103 '''this iterator deals with the http_console_ports
104 returning the ports one by one
107 while index
< len(global_config
["http_console_ports"]):
108 port
= global_config
["http_console_ports"][index
]
109 #print("ports -> ", port)
110 if type(port
) is int:
112 else: #this is dictionary with from to keys
114 #print("ports -> ", port, port2)
115 while port2
<= port
["to"]:
116 #print("ports -> ", port, port2)
123 print("Usage: ", sys
.argv
[0], "[options]")
124 print( " -v|--version: prints current version")
125 print( " -c|--config [configuration_file]: loads the configuration file (default: openmanod.cfg)")
126 print( " -h|--help: shows this help")
127 print( " -p|--port [port_number]: changes port number and overrides the port number in the configuration file (default: 9090)")
128 print( " -P|--adminport [port_number]: changes admin port number and overrides the port number in the configuration file (default: 9095)")
129 print( " -V|--vnf-repository: changes the path of the vnf-repository and overrides the path in the configuration file")
132 if __name__
=="__main__":
133 #streamformat = "%(levelname)s (%(module)s:%(lineno)d) %(message)s"
134 streamformat
= "%(asctime)s %(name)s %(levelname)s: %(message)s"
135 logging
.basicConfig(format
=streamformat
, level
= logging
.DEBUG
)
136 logger
.setLevel(logging
.DEBUG
)
137 # Read parameters and configuration file
139 opts
, args
= getopt
.getopt(sys
.argv
[1:], "hvc:V:p:P:", ["config", "help", "version", "port", "vnf-repository", "adminport"])
143 config_file
= 'openmanod.cfg'
144 vnf_repository
= None
147 if o
in ("-v", "--version"):
148 print "openmanod version", __version__
, version_date
149 print "(c) Copyright Telefonica"
151 elif o
in ("-h", "--help"):
154 elif o
in ("-V", "--vnf-repository"):
156 elif o
in ("-c", "--config"):
158 elif o
in ("-p", "--port"):
160 elif o
in ("-P", "--adminport"):
163 assert False, "Unhandled option"
165 global_config
= load_configuration(config_file
)
167 logging
.basicConfig(level
= getattr(logging
, global_config
.get('log_level',"debug")))
168 logger
.setLevel(getattr(logging
, global_config
['log_level']))
169 # Override parameters obtained by command line
170 if port
is not None: global_config
['http_port'] = port
171 if port_admin
is not None: global_config
['http_admin_port'] = port_admin
172 if vnf_repository
is not None:
173 global_config
['vnf_repository'] = vnf_repository
175 if not 'vnf_repository' in global_config
:
176 logger
.error( os
.getcwd() )
177 global_config
['vnf_repository'] = os
.getcwd()+'/vnfrepo'
180 if not os
.path
.exists(global_config
['vnf_repository']):
181 logger
.error( "Creating folder vnf_repository folder: '%s'.", global_config
['vnf_repository'])
183 os
.makedirs(global_config
['vnf_repository'])
184 except Exception as e
:
185 logger
.error( "Error '%s'. Ensure the path 'vnf_repository' is properly set at %s",e
.args
[1], config_file
)
188 global_config
["console_port_iterator"] = console_port_iterator
189 global_config
["console_thread"]={}
190 global_config
["console_ports"]={}
191 # Initialize DB connection
192 mydb
= nfvo_db
.nfvo_db();
193 if mydb
.connect(global_config
['db_host'], global_config
['db_user'], global_config
['db_passwd'], global_config
['db_name']) == -1:
194 logger
.error("Error connecting to database %s at %s@%s", global_config
['db_name'], global_config
['db_user'], global_config
['db_host'])
196 r
= mydb
.get_db_version()
198 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
)
200 elif r
[1]!=database_version
:
201 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
)
204 nfvo
.global_config
=global_config
206 httpthread
= httpserver
.httpserver(mydb
, False, global_config
['http_host'], global_config
['http_port'])
209 if 'http_admin_port' in global_config
:
210 httpthreadadmin
= httpserver
.httpserver(mydb
, True, global_config
['http_host'], global_config
['http_admin_port'])
211 httpthreadadmin
.start()
213 logger
.info('Waiting for http clients')
214 print('openmanod ready')
215 print('====================')
219 #TODO: Interactive console must be implemented here instead of join or sleep
222 #if 'http_admin_port' in global_config:
223 # httpthreadadmin.join()
226 for thread
in global_config
["console_thread"]:
227 thread
.terminate
= True
229 except KeyboardInterrupt:
230 logger
.info('KyboardInterrupt')
233 except getopt
.GetoptError
as e
:
234 logger
.error("Error: %s", str(e
)) # will print something like "option -a not recognized"
237 except LoadConfigurationException
as e
:
238 logger
.error("Error: %s", str(e
))