openmano v0.4.40 change from test_os to test_vimconn that is more general. Some minor...
[osm/RO.git] / openmanod.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 ##
5 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
6 # 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
25 '''
26 openmano server.
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.
31
32 It loads the configuration file and launches the http_server thread that will listen requests using openmano API.
33 '''
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
39
40 import httpserver
41 import time
42 import os
43 import sys
44 import getopt
45 import yaml
46 import nfvo_db
47 from jsonschema import validate as js_v, exceptions as js_e
48 import utils
49 from openmano_schemas import config_schema
50 import nfvo
51 import logging
52
53 global global_config
54 logger = logging.getLogger('mano')
55
56 class LoadConfigurationException(Exception):
57 pass
58
59 def load_configuration(configuration_file):
60 default_tokens ={'http_port':9090,
61 'http_host':'localhost',
62 'log_level': 'DEBUG',
63 'log_level_db': 'ERROR',
64 'log_level_vimconn': 'DEBUG',
65 }
66 try:
67 #Check config file exists
68 if not os.path.isfile(configuration_file):
69 raise LoadConfigurationException("Error: Configuration file '"+configuration_file+"' does not exist.")
70
71 #Read file
72 (return_status, code) = utils.read_file(configuration_file)
73 if not return_status:
74 raise LoadConfigurationException("Error loading configuration file '"+configuration_file+"': "+code)
75 #Parse configuration file
76 try:
77 config = yaml.load(code)
78 except yaml.YAMLError, exc:
79 error_pos = ""
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")
84
85 #Validate configuration file with the config_schema
86 try:
87 js_v(config, config_schema)
88 except js_e.ValidationError, exc:
89 error_pos = ""
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)
92
93 #Check default values tokens
94 for k,v in default_tokens.items():
95 if k not in config: config[k]=v
96
97 except Exception,e:
98 raise LoadConfigurationException("Error loading configuration file '"+configuration_file+"': "+str(e))
99
100 return config
101
102 def console_port_iterator():
103 '''this iterator deals with the http_console_ports
104 returning the ports one by one
105 '''
106 index = 0
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:
111 yield port
112 else: #this is dictionary with from to keys
113 port2 = port["from"]
114 #print("ports -> ", port, port2)
115 while port2 <= port["to"]:
116 #print("ports -> ", port, port2)
117 yield port2
118 port2 += 1
119 index += 1
120
121
122 def usage():
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")
130 return
131
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
138 try:
139 opts, args = getopt.getopt(sys.argv[1:], "hvc:V:p:P:", ["config", "help", "version", "port", "vnf-repository", "adminport"])
140
141 port=None
142 port_admin = None
143 config_file = 'openmanod.cfg'
144 vnf_repository = None
145
146 for o, a in opts:
147 if o in ("-v", "--version"):
148 print "openmanod version", __version__, version_date
149 print "(c) Copyright Telefonica"
150 sys.exit()
151 elif o in ("-h", "--help"):
152 usage()
153 sys.exit()
154 elif o in ("-V", "--vnf-repository"):
155 vnf_repository = a
156 elif o in ("-c", "--config"):
157 config_file = a
158 elif o in ("-p", "--port"):
159 port = a
160 elif o in ("-P", "--adminport"):
161 port_admin = a
162 else:
163 assert False, "Unhandled option"
164
165 global_config = load_configuration(config_file)
166 #print global_config
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
174 else:
175 if not 'vnf_repository' in global_config:
176 logger.error( os.getcwd() )
177 global_config['vnf_repository'] = os.getcwd()+'/vnfrepo'
178 #print global_config
179
180 if not os.path.exists(global_config['vnf_repository']):
181 logger.error( "Creating folder vnf_repository folder: '%s'.", global_config['vnf_repository'])
182 try:
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)
186 exit(-1)
187
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'])
195 exit(-1)
196 r = mydb.get_db_version()
197 if r[0]<0:
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)
199 exit(-1)
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)
202 exit(-1)
203
204 nfvo.global_config=global_config
205
206 httpthread = httpserver.httpserver(mydb, False, global_config['http_host'], global_config['http_port'])
207
208 httpthread.start()
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()
212 time.sleep(1)
213 logger.info('Waiting for http clients')
214 print('openmanod ready')
215 print('====================')
216 time.sleep(20)
217 sys.stdout.flush()
218
219 #TODO: Interactive console must be implemented here instead of join or sleep
220
221 #httpthread.join()
222 #if 'http_admin_port' in global_config:
223 # httpthreadadmin.join()
224 while True:
225 time.sleep(86400)
226 for thread in global_config["console_thread"]:
227 thread.terminate = True
228
229 except KeyboardInterrupt:
230 logger.info('KyboardInterrupt')
231 except SystemExit:
232 pass
233 except getopt.GetoptError as e:
234 logger.error("Error: %s", str(e)) # will print something like "option -a not recognized"
235 #usage()
236 exit(-1)
237 except LoadConfigurationException as e:
238 logger.error("Error: %s", str(e))
239 exit(-1)
240