openmano first code upload
[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.36-r467"
37 version_date="Mar 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 from utils import auxiliary_functions as af
49 from openmano_schemas import config_schema
50 import nfvo
51
52 global global_config
53
54 def load_configuration(configuration_file):
55 default_tokens ={'http_port':9090, 'http_host':'localhost'}
56 try:
57 #Check config file exists
58 if not os.path.isfile(configuration_file):
59 return (False, "Error: Configuration file '"+configuration_file+"' does not exists.")
60
61 #Read file
62 (return_status, code) = af.read_file(configuration_file)
63 if not return_status:
64 return (return_status, "Error loading configuration file '"+configuration_file+"': "+code)
65 #Parse configuration file
66 try:
67 config = yaml.load(code)
68 except yaml.YAMLError, exc:
69 error_pos = ""
70 if hasattr(exc, 'problem_mark'):
71 mark = exc.problem_mark
72 error_pos = " at position: (%s:%s)" % (mark.line+1, mark.column+1)
73 return (False, "Error loading configuration file '"+configuration_file+"'"+error_pos+": content format error: Failed to parse yaml format")
74
75 #Validate configuration file with the config_schema
76 try:
77 js_v(config, config_schema)
78 except js_e.ValidationError, exc:
79 error_pos = ""
80 if len(exc.path)>0: error_pos=" at '" + ":".join(map(str, exc.path))+"'"
81 return False, "Error loading configuration file '"+configuration_file+"'"+error_pos+": "+exc.message
82
83 #Check default values tokens
84 for k,v in default_tokens.items():
85 if k not in config: config[k]=v
86
87 except Exception,e:
88 return (False, "Error loading configuration file '"+configuration_file+"': "+str(e))
89
90 return (True, config)
91
92 def console_port_iterator():
93 '''this iterator deals with the http_console_ports
94 returning the ports one by one
95 '''
96 index = 0
97 while index < len(global_config["http_console_ports"]):
98 port = global_config["http_console_ports"][index]
99 #print "ports -> ", port
100 if type(port) is int:
101 yield port
102 else: #this is dictionary with from to keys
103 port2 = port["from"]
104 #print "ports -> ", port, port2
105 while port2 <= port["to"]:
106 print "ports -> ", port, port2
107 yield port2
108 port2 += 1
109 index += 1
110
111
112 def usage():
113 print "Usage: ", sys.argv[0], "[options]"
114 print " -v|--version: prints current version"
115 print " -c|--config [configuration_file]: loads the configuration file (default: openmanod.cfg)"
116 print " -h|--help: shows this help"
117 print " -p|--port [port_number]: changes port number and overrides the port number in the configuration file (default: 9090)"
118 print " -P|--adminport [port_number]: changes admin port number and overrides the port number in the configuration file (default: 9095)"
119 print " -V|--vnf-repository: changes the path of the vnf-repository and overrides the path in the configuration file"
120 return
121
122 if __name__=="__main__":
123 # Read parameters and configuration file
124 try:
125 opts, args = getopt.getopt(sys.argv[1:], "hvc:V:p:P:", ["config", "help", "version", "port", "vnf-repository", "adminport"])
126 except getopt.GetoptError, err:
127 # print help information and exit:
128 print "Error:", err # will print something like "option -a not recognized"
129 usage()
130 sys.exit(2)
131
132 port=None
133 port_admin = None
134 config_file = 'openmanod.cfg'
135 vnf_repository = None
136
137 for o, a in opts:
138 if o in ("-v", "--version"):
139 print "openmanod version", __version__, version_date
140 print "(c) Copyright Telefonica"
141 sys.exit()
142 elif o in ("-h", "--help"):
143 usage()
144 sys.exit()
145 elif o in ("-V", "--vnf-repository"):
146 vnf_repository = a
147 elif o in ("-c", "--config"):
148 config_file = a
149 elif o in ("-p", "--port"):
150 port = a
151 elif o in ("-P", "--adminport"):
152 port_admin = a
153 else:
154 assert False, "Unhandled option"
155
156 try:
157 r, global_config = load_configuration(config_file)
158 #print global_config
159 if not r:
160 print global_config
161 exit(-1)
162 # Override parameters obtained by command line
163 if port is not None: global_config['http_port'] = port
164 if port_admin is not None: global_config['http_admin_port'] = port_admin
165 if vnf_repository is not None:
166 global_config['vnf_repository'] = vnf_repository
167 else:
168 if not 'vnf_repository' in global_config:
169 print os.getcwd()
170 global_config['vnf_repository'] = os.getcwd()+'/vnfrepo'
171 #print global_config
172
173 if not os.path.exists(global_config['vnf_repository']):
174 print "Creating folder vnf_repository folder: '%s'." % global_config['vnf_repository']
175 try:
176 os.makedirs(global_config['vnf_repository'])
177 except Exception,e:
178 print "Error '%s'. Ensure the path 'vnf_repository' is properly set at %s" %(e.args[1], config_file)
179 exit(-1)
180
181 global_config["console_port_iterator"] = console_port_iterator
182 global_config["console_thread"]={}
183 global_config["console_ports"]={}
184 # Initialize DB connection
185 mydb = nfvo_db.nfvo_db();
186 if mydb.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name']) == -1:
187 print "Error connecting to database", global_config['db_name'], "at", global_config['db_user'], "@", global_config['db_host']
188 exit(-1)
189 r = mydb.get_db_version()
190 if r[0]<0:
191 print "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
192 exit(-1)
193 elif r[1]!=database_version:
194 print "Error DATABASE wrong version '%s'. Try to upgrade/downgrade to version '%s' with './database_utils/migrate_mano_db.sh'" % (r[1], database_version)
195 exit(-1)
196
197 nfvo.global_config=global_config
198
199 httpthread = httpserver.httpserver(mydb, False, global_config['http_host'], global_config['http_port'])
200
201 httpthread.start()
202 if 'http_admin_port' in global_config:
203 httpthreadadmin = httpserver.httpserver(mydb, True, global_config['http_host'], global_config['http_admin_port'])
204 httpthreadadmin.start()
205 time.sleep(1)
206 print 'Waiting for http clients'
207 print 'openmanod ready'
208 print '===================='
209 time.sleep(20)
210 sys.stdout.flush()
211
212 #TODO: Interactive console must be implemented here instead of join or sleep
213
214 #httpthread.join()
215 #if 'http_admin_port' in global_config:
216 # httpthreadadmin.join()
217 while True:
218 time.sleep(86400)
219 for thread in global_config["console_thread"]:
220 thread.terminate = True
221
222 except (KeyboardInterrupt, SystemExit):
223 print 'Exiting openmanod'
224 exit()
225
226