feature 8029 change RO to python3. Using vim plugins
[osm/RO.git] / RO / osm_ro / httpserver.py
1 # -*- coding: utf-8 -*-
2
3 ##
4 # Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
5 # This file is part of openmano
6 # All Rights Reserved.
7 #
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 # not use this file except in compliance with the License. You may obtain
10 # a copy of the License at
11 #
12 # http://www.apache.org/licenses/LICENSE-2.0
13 #
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 # License for the specific language governing permissions and limitations
18 # under the License.
19 #
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact with: nfvlabs@tid.es
22 ##
23
24 '''
25 HTTP server implementing the openmano API. It will answer to POST, PUT, GET methods in the appropriate URLs
26 and will use the nfvo.py module to run the appropriate method.
27 Every YAML/JSON file is checked against a schema in openmano_schemas.py module.
28 '''
29 __author__="Alfonso Tierno, Gerardo Garcia"
30 __date__ ="$17-sep-2014 09:07:15$"
31
32 import bottle
33 import yaml
34 import threading
35 import logging
36
37 from osm_ro.openmano_schemas import vnfd_schema_v01, vnfd_schema_v02, \
38 nsd_schema_v01, nsd_schema_v02, nsd_schema_v03, scenario_edit_schema, \
39 scenario_action_schema, instance_scenario_action_schema, instance_scenario_create_schema_v01, \
40 tenant_schema, tenant_edit_schema,\
41 datacenter_schema, datacenter_edit_schema, datacenter_action_schema, datacenter_associate_schema,\
42 object_schema, netmap_new_schema, netmap_edit_schema, sdn_controller_schema, sdn_controller_edit_schema, \
43 sdn_port_mapping_schema, sdn_external_port_schema
44
45 from .http_tools import errors as httperrors
46 from .http_tools.request_processing import (
47 format_out,
48 format_in,
49 filter_query_string
50 )
51 from .wim.http_handler import WimHandler
52
53 from . import nfvo
54 from . import utils
55 from .db_base import db_base_Exception
56 from functools import wraps
57
58 global mydb
59 global url_base
60 global logger
61 url_base="/openmano"
62 logger = None
63
64
65 def log_to_logger(fn):
66 '''
67 Wrap a Bottle request so that a log line is emitted after it's handled.
68 (This decorator can be extended to take the desired logger as a param.)
69 '''
70 @wraps(fn)
71 def _log_to_logger(*args, **kwargs):
72 actual_response = fn(*args, **kwargs)
73 # modify this to log exactly what you need:
74 logger.info('FROM %s %s %s %s', bottle.request.remote_addr,
75 bottle.request.method,
76 bottle.request.url,
77 bottle.response.status)
78 return actual_response
79 return _log_to_logger
80
81 class httpserver(threading.Thread):
82 def __init__(self, db, admin=False, host='localhost', port=9090,
83 wim_persistence=None, wim_engine=None):
84 #global url_base
85 global mydb
86 global logger
87 #initialization
88 if not logger:
89 logger = logging.getLogger('openmano.http')
90 threading.Thread.__init__(self)
91 self.host = host
92 self.port = port #Port where the listen service must be started
93 if admin==True:
94 self.name = "http_admin"
95 else:
96 self.name = "http"
97 #self.url_preffix = 'http://' + host + ':' + str(port) + url_base
98 mydb = db
99 #self.first_usable_connection_index = 10
100 #self.next_connection_index = self.first_usable_connection_index #The next connection index to be used
101 #Ensure that when the main program exits the thread will also exit
102
103 self.handlers = [
104 WimHandler(db, wim_persistence, wim_engine, url_base)
105 ]
106
107 self.daemon = True
108 self.setDaemon(True)
109
110 def run(self, debug=False, quiet=True):
111 bottle.install(log_to_logger)
112 default_app = bottle.app()
113
114 for handler in self.handlers:
115 default_app.merge(handler.wsgi_app)
116
117 bottle.run(host=self.host, port=self.port, debug=debug, quiet=quiet)
118
119
120 def run_bottle(db, host_='localhost', port_=9090):
121 '''Used for launching in main thread, so that it can be debugged'''
122 server = httpserver(db, host=host_, port=port_)
123 server.run(debug=True) # quiet=True
124
125
126 @bottle.route(url_base + '/', method='GET')
127 def http_get():
128 #print
129 return 'works' #TODO: to be completed
130
131 @bottle.hook('after_request')
132 def enable_cors():
133 '''Don't know yet if really needed. Keep it just in case'''
134 bottle.response.headers['Access-Control-Allow-Origin'] = '*'
135
136 @bottle.route(url_base + '/version', method='GET')
137 def http_get_version():
138 return nfvo.get_version()
139 #
140 # VNFs
141 #
142
143 @bottle.route(url_base + '/tenants', method='GET')
144 def http_get_tenants():
145 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
146 select_,where_,limit_ = filter_query_string(bottle.request.query, None,
147 ('uuid','name','description','created_at') )
148 try:
149 tenants = mydb.get_rows(FROM='nfvo_tenants', SELECT=select_,WHERE=where_,LIMIT=limit_)
150 #change_keys_http2db(content, http2db_tenant, reverse=True)
151 utils.convert_float_timestamp2str(tenants)
152 data={'tenants' : tenants}
153 return format_out(data)
154 except bottle.HTTPError:
155 raise
156 except db_base_Exception as e:
157 logger.error("http_get_tenants error {}: {}".format(e.http_code, str(e)))
158 bottle.abort(e.http_code, str(e))
159 except Exception as e:
160 logger.error("Unexpected exception: ", exc_info=True)
161 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
162
163
164 @bottle.route(url_base + '/tenants/<tenant_id>', method='GET')
165 def http_get_tenant_id(tenant_id):
166 '''get tenant details, can use both uuid or name'''
167 #obtain data
168 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
169 try:
170 from_ = 'nfvo_tenants'
171 select_, where_, limit_ = filter_query_string(bottle.request.query, None,
172 ('uuid', 'name', 'description', 'created_at'))
173 what = 'uuid' if utils.check_valid_uuid(tenant_id) else 'name'
174 where_[what] = tenant_id
175 tenants = mydb.get_rows(FROM=from_, SELECT=select_,WHERE=where_)
176 #change_keys_http2db(content, http2db_tenant, reverse=True)
177 if len(tenants) == 0:
178 bottle.abort(httperrors.Not_Found, "No tenant found with {}='{}'".format(what, tenant_id))
179 elif len(tenants) > 1:
180 bottle.abort(httperrors.Bad_Request, "More than one tenant found with {}='{}'".format(what, tenant_id))
181 utils.convert_float_timestamp2str(tenants[0])
182 data = {'tenant': tenants[0]}
183 return format_out(data)
184 except bottle.HTTPError:
185 raise
186 except db_base_Exception as e:
187 logger.error("http_get_tenant_id error {}: {}".format(e.http_code, str(e)))
188 bottle.abort(e.http_code, str(e))
189 except Exception as e:
190 logger.error("Unexpected exception: ", exc_info=True)
191 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
192
193
194 @bottle.route(url_base + '/tenants', method='POST')
195 def http_post_tenants():
196 '''insert a tenant into the catalogue. '''
197 #parse input data
198 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
199 http_content,_ = format_in( tenant_schema )
200 r = utils.remove_extra_items(http_content, tenant_schema)
201 if r:
202 logger.debug("Remove received extra items %s", str(r))
203 try:
204 data = nfvo.new_tenant(mydb, http_content['tenant'])
205 return http_get_tenant_id(data)
206 except bottle.HTTPError:
207 raise
208 except (nfvo.NfvoException, db_base_Exception) as e:
209 logger.error("http_post_tenants error {}: {}".format(e.http_code, str(e)))
210 bottle.abort(e.http_code, str(e))
211 except Exception as e:
212 logger.error("Unexpected exception: ", exc_info=True)
213 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
214
215
216 @bottle.route(url_base + '/tenants/<tenant_id>', method='PUT')
217 def http_edit_tenant_id(tenant_id):
218 '''edit tenant details, can use both uuid or name'''
219 #parse input data
220 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
221 http_content,_ = format_in( tenant_edit_schema )
222 r = utils.remove_extra_items(http_content, tenant_edit_schema)
223 if r:
224 logger.debug("Remove received extra items %s", str(r))
225
226 #obtain data, check that only one exist
227 try:
228 tenant = mydb.get_table_by_uuid_name('nfvo_tenants', tenant_id)
229 #edit data
230 tenant_id = tenant['uuid']
231 where={'uuid': tenant['uuid']}
232 mydb.update_rows('nfvo_tenants', http_content['tenant'], where)
233 return http_get_tenant_id(tenant_id)
234 except bottle.HTTPError:
235 raise
236 except db_base_Exception as e:
237 logger.error("http_edit_tenant_id error {}: {}".format(e.http_code, str(e)))
238 bottle.abort(e.http_code, str(e))
239 except Exception as e:
240 logger.error("Unexpected exception: ", exc_info=True)
241 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
242
243
244 @bottle.route(url_base + '/tenants/<tenant_id>', method='DELETE')
245 def http_delete_tenant_id(tenant_id):
246 '''delete a tenant from database, can use both uuid or name'''
247 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
248 try:
249 data = nfvo.delete_tenant(mydb, tenant_id)
250 return format_out({"result":"tenant " + data + " deleted"})
251 except bottle.HTTPError:
252 raise
253 except db_base_Exception as e:
254 logger.error("http_delete_tenant_id error {}: {}".format(e.http_code, str(e)))
255 bottle.abort(e.http_code, str(e))
256 except Exception as e:
257 logger.error("Unexpected exception: ", exc_info=True)
258 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
259
260
261 @bottle.route(url_base + '/<tenant_id>/datacenters', method='GET')
262 def http_get_datacenters(tenant_id):
263 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
264 try:
265 if tenant_id != 'any':
266 #check valid tenant_id
267 nfvo.check_tenant(mydb, tenant_id)
268 select_,where_,limit_ = filter_query_string(bottle.request.query, None,
269 ('uuid','name','vim_url','type','created_at') )
270 if tenant_id != 'any':
271 where_['nfvo_tenant_id'] = tenant_id
272 if 'created_at' in select_:
273 select_[ select_.index('created_at') ] = 'd.created_at as created_at'
274 if 'created_at' in where_:
275 where_['d.created_at'] = where_.pop('created_at')
276 datacenters = mydb.get_rows(FROM='datacenters as d join tenants_datacenters as td on d.uuid=td.datacenter_id',
277 SELECT=select_,WHERE=where_,LIMIT=limit_)
278 else:
279 datacenters = mydb.get_rows(FROM='datacenters',
280 SELECT=select_,WHERE=where_,LIMIT=limit_)
281 #change_keys_http2db(content, http2db_tenant, reverse=True)
282 utils.convert_float_timestamp2str(datacenters)
283 data={'datacenters' : datacenters}
284 return format_out(data)
285 except bottle.HTTPError:
286 raise
287 except (nfvo.NfvoException, db_base_Exception) as e:
288 logger.error("http_get_datacenters error {}: {}".format(e.http_code, str(e)))
289 bottle.abort(e.http_code, str(e))
290 except Exception as e:
291 logger.error("Unexpected exception: ", exc_info=True)
292 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
293
294
295 @bottle.route(url_base + '/<tenant_id>/vim_accounts', method='GET')
296 @bottle.route(url_base + '/<tenant_id>/vim_accounts/<vim_account_id>', method='GET')
297 def http_get_vim_account(tenant_id, vim_account_id=None):
298 '''get vim_account list/details, '''
299 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
300 try:
301 select_ = ('uuid', 'name', 'dt.datacenter_id as vim_id', 'vim_tenant_name', 'vim_tenant_id', 'user', 'config',
302 'dt.created_at as created_at', 'passwd')
303 where_ = {'nfvo_tenant_id': tenant_id}
304 if vim_account_id:
305 where_['dt.uuid'] = vim_account_id
306 from_ = 'tenants_datacenters as td join datacenter_tenants as dt on dt.uuid=td.datacenter_tenant_id'
307 vim_accounts = mydb.get_rows(SELECT=select_, FROM=from_, WHERE=where_)
308
309 if len(vim_accounts) == 0 and vim_account_id:
310 bottle.abort(HTTP_Not_Found, "No vim_account found for tenant {} and id '{}'".format(tenant_id,
311 vim_account_id))
312 for vim_account in vim_accounts:
313 if vim_account["passwd"]:
314 vim_account["passwd"] = "******"
315 if vim_account['config'] != None:
316 try:
317 config_dict = yaml.load(vim_account['config'], Loader=yaml.Loader)
318 vim_account['config'] = config_dict
319 if vim_account['config'].get('admin_password'):
320 vim_account['config']['admin_password'] = "******"
321 if vim_account['config'].get('vcenter_password'):
322 vim_account['config']['vcenter_password'] = "******"
323 if vim_account['config'].get('nsx_password'):
324 vim_account['config']['nsx_password'] = "******"
325 except Exception as e:
326 logger.error("Exception '%s' while trying to load config information", str(e))
327 # change_keys_http2db(content, http2db_datacenter, reverse=True)
328 #convert_datetime2str(vim_account)
329 if vim_account_id:
330 return format_out({"datacenter": vim_accounts[0]})
331 else:
332 return format_out({"datacenters": vim_accounts})
333 except bottle.HTTPError:
334 raise
335 except (nfvo.NfvoException, db_base_Exception) as e:
336 logger.error("http_get_datacenter_id error {}: {}".format(e.http_code, str(e)))
337 bottle.abort(e.http_code, str(e))
338 except Exception as e:
339 logger.error("Unexpected exception: ", exc_info=True)
340 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
341
342
343 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='GET')
344 def http_get_datacenter_id(tenant_id, datacenter_id):
345 '''get datacenter details, can use both uuid or name'''
346 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
347 try:
348 if tenant_id != 'any':
349 #check valid tenant_id
350 nfvo.check_tenant(mydb, tenant_id)
351 #obtain data
352 what = 'uuid' if utils.check_valid_uuid(datacenter_id) else 'name'
353 where_={}
354 where_[what] = datacenter_id
355 select_=['uuid', 'name','vim_url', 'vim_url_admin', 'type', 'd.config as config', 'description', 'd.created_at as created_at']
356 if tenant_id != 'any':
357 select_.append("datacenter_tenant_id")
358 where_['td.nfvo_tenant_id']= tenant_id
359 from_='datacenters as d join tenants_datacenters as td on d.uuid=td.datacenter_id'
360 else:
361 from_='datacenters as d'
362 datacenters = mydb.get_rows(
363 SELECT=select_,
364 FROM=from_,
365 WHERE=where_)
366
367 if len(datacenters)==0:
368 bottle.abort( httperrors.Not_Found, "No datacenter found for tenant with {} '{}'".format(what, datacenter_id) )
369 elif len(datacenters)>1:
370 bottle.abort( httperrors.Bad_Request, "More than one datacenter found for tenant with {} '{}'".format(what, datacenter_id) )
371 datacenter = datacenters[0]
372 if tenant_id != 'any':
373 #get vim tenant info
374 vim_tenants = mydb.get_rows(
375 SELECT=("vim_tenant_name", "vim_tenant_id", "user", "passwd", "config"),
376 FROM="datacenter_tenants",
377 WHERE={"uuid": datacenters[0]["datacenter_tenant_id"]},
378 ORDER_BY=("created", ) )
379 del datacenter["datacenter_tenant_id"]
380 datacenter["vim_tenants"] = vim_tenants
381 for vim_tenant in vim_tenants:
382 if vim_tenant["passwd"]:
383 vim_tenant["passwd"] = "******"
384 if vim_tenant['config'] != None:
385 try:
386 config_dict = yaml.load(vim_tenant['config'], Loader=yaml.Loader)
387 vim_tenant['config'] = config_dict
388 if vim_tenant['config'].get('admin_password'):
389 vim_tenant['config']['admin_password'] = "******"
390 if vim_tenant['config'].get('vcenter_password'):
391 vim_tenant['config']['vcenter_password'] = "******"
392 if vim_tenant['config'].get('nsx_password'):
393 vim_tenant['config']['nsx_password'] = "******"
394 except Exception as e:
395 logger.error("Exception '%s' while trying to load config information", str(e))
396
397 if datacenter['config'] != None:
398 try:
399 config_dict = yaml.load(datacenter['config'], Loader=yaml.Loader)
400 datacenter['config'] = config_dict
401 if datacenter['config'].get('admin_password'):
402 datacenter['config']['admin_password'] = "******"
403 if datacenter['config'].get('vcenter_password'):
404 datacenter['config']['vcenter_password'] = "******"
405 if datacenter['config'].get('nsx_password'):
406 datacenter['config']['nsx_password'] = "******"
407 except Exception as e:
408 logger.error("Exception '%s' while trying to load config information", str(e))
409 #change_keys_http2db(content, http2db_datacenter, reverse=True)
410 utils.convert_float_timestamp2str(datacenter)
411 data={'datacenter' : datacenter}
412 return format_out(data)
413 except bottle.HTTPError:
414 raise
415 except (nfvo.NfvoException, db_base_Exception) as e:
416 logger.error("http_get_datacenter_id error {}: {}".format(e.http_code, str(e)))
417 bottle.abort(e.http_code, str(e))
418 except Exception as e:
419 logger.error("Unexpected exception: ", exc_info=True)
420 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
421
422
423 @bottle.route(url_base + '/datacenters', method='POST')
424 def http_post_datacenters():
425 '''insert a datacenter into the catalogue. '''
426 #parse input data
427 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
428 http_content,_ = format_in(datacenter_schema, confidential_data=True)
429 r = utils.remove_extra_items(http_content, datacenter_schema)
430 if r:
431 logger.debug("Remove received extra items %s", str(r))
432 try:
433 data = nfvo.new_datacenter(mydb, http_content['datacenter'])
434 return http_get_datacenter_id('any', data)
435 except bottle.HTTPError:
436 raise
437 except (nfvo.NfvoException, db_base_Exception) as e:
438 logger.error("http_post_datacenters error {}: {}".format(e.http_code, str(e)))
439 bottle.abort(e.http_code, str(e))
440 except Exception as e:
441 logger.error("Unexpected exception: ", exc_info=True)
442 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
443
444
445 @bottle.route(url_base + '/datacenters/<datacenter_id_name>', method='PUT')
446 def http_edit_datacenter_id(datacenter_id_name):
447 '''edit datacenter details, can use both uuid or name'''
448 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
449 #parse input data
450 http_content,_ = format_in( datacenter_edit_schema )
451 r = utils.remove_extra_items(http_content, datacenter_edit_schema)
452 if r:
453 logger.debug("Remove received extra items %s", str(r))
454
455 try:
456 datacenter_id = nfvo.edit_datacenter(mydb, datacenter_id_name, http_content['datacenter'])
457 return http_get_datacenter_id('any', datacenter_id)
458 except bottle.HTTPError:
459 raise
460 except (nfvo.NfvoException, db_base_Exception) as e:
461 logger.error("http_edit_datacenter_id error {}: {}".format(e.http_code, str(e)))
462 bottle.abort(e.http_code, str(e))
463 except Exception as e:
464 logger.error("Unexpected exception: ", exc_info=True)
465 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
466
467 @bottle.route(url_base + '/<tenant_id>/sdn_controllers', method='POST')
468 def http_post_sdn_controller(tenant_id):
469 '''insert a sdn controller into the catalogue. '''
470 #parse input data
471 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
472 http_content,_ = format_in( sdn_controller_schema )
473 try:
474 logger.debug("tenant_id: "+tenant_id)
475 #logger.debug("content: {}".format(http_content['sdn_controller']))
476
477 data = nfvo.sdn_controller_create(mydb, tenant_id, http_content['sdn_controller'])
478 return format_out({"sdn_controller": nfvo.sdn_controller_list(mydb, tenant_id, data)})
479 except bottle.HTTPError:
480 raise
481 except (nfvo.NfvoException, db_base_Exception) as e:
482 logger.error("http_post_sdn_controller error {}: {}".format(e.http_code, str(e)))
483 bottle.abort(e.http_code, str(e))
484 except Exception as e:
485 logger.error("Unexpected exception: ", exc_info=True)
486 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
487
488 @bottle.route(url_base + '/<tenant_id>/sdn_controllers/<controller_id>', method='PUT')
489 def http_put_sdn_controller_update(tenant_id, controller_id):
490 '''Update sdn controller'''
491 #parse input data
492 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
493 http_content,_ = format_in( sdn_controller_edit_schema )
494 # r = utils.remove_extra_items(http_content, datacenter_schema)
495 # if r:
496 # logger.debug("Remove received extra items %s", str(r))
497 try:
498 #logger.debug("tenant_id: "+tenant_id)
499 logger.debug("content: {}".format(http_content['sdn_controller']))
500
501 data = nfvo.sdn_controller_update(mydb, tenant_id, controller_id, http_content['sdn_controller'])
502 return format_out({"sdn_controller": nfvo.sdn_controller_list(mydb, tenant_id, controller_id)})
503
504 except bottle.HTTPError:
505 raise
506 except (nfvo.NfvoException, db_base_Exception) as e:
507 logger.error("http_post_sdn_controller error {}: {}".format(e.http_code, str(e)))
508 bottle.abort(e.http_code, str(e))
509 except Exception as e:
510 logger.error("Unexpected exception: ", exc_info=True)
511 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
512
513 @bottle.route(url_base + '/<tenant_id>/sdn_controllers', method='GET')
514 def http_get_sdn_controller(tenant_id):
515 '''get sdn controllers list, can use both uuid or name'''
516 try:
517 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
518
519 data = {'sdn_controllers': nfvo.sdn_controller_list(mydb, tenant_id)}
520 return format_out(data)
521 except bottle.HTTPError:
522 raise
523 except (nfvo.NfvoException, db_base_Exception) as e:
524 logger.error("http_get_sdn_controller error {}: {}".format(e.http_code, str(e)))
525 bottle.abort(e.http_code, str(e))
526 except Exception as e:
527 logger.error("Unexpected exception: ", exc_info=True)
528 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
529
530 @bottle.route(url_base + '/<tenant_id>/sdn_controllers/<controller_id>', method='GET')
531 def http_get_sdn_controller_id(tenant_id, controller_id):
532 '''get sdn controller details, can use both uuid or name'''
533 try:
534 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
535 data = nfvo.sdn_controller_list(mydb, tenant_id, controller_id)
536 return format_out({"sdn_controllers": data})
537 except bottle.HTTPError:
538 raise
539 except (nfvo.NfvoException, db_base_Exception) as e:
540 logger.error("http_get_sdn_controller_id error {}: {}".format(e.http_code, str(e)))
541 bottle.abort(e.http_code, str(e))
542 except Exception as e:
543 logger.error("Unexpected exception: ", exc_info=True)
544 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
545
546 @bottle.route(url_base + '/<tenant_id>/sdn_controllers/<controller_id>', method='DELETE')
547 def http_delete_sdn_controller_id(tenant_id, controller_id):
548 '''delete sdn controller, can use both uuid or name'''
549 try:
550 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
551 data = nfvo.sdn_controller_delete(mydb, tenant_id, controller_id)
552 return format_out(data)
553 except bottle.HTTPError:
554 raise
555 except (nfvo.NfvoException, db_base_Exception) as e:
556 logger.error("http_delete_sdn_controller_id error {}: {}".format(e.http_code, str(e)))
557 bottle.abort(e.http_code, str(e))
558 except Exception as e:
559 logger.error("Unexpected exception: ", exc_info=True)
560 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
561
562 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method='POST')
563 def http_post_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
564 '''Set the sdn port mapping for a datacenter. '''
565 #parse input data
566 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
567 http_content, _ = format_in(sdn_port_mapping_schema)
568 # r = utils.remove_extra_items(http_content, datacenter_schema)
569 # if r:
570 # logger.debug("Remove received extra items %s", str(r))
571 try:
572 data = nfvo.datacenter_sdn_port_mapping_set(mydb, tenant_id, datacenter_id, http_content['sdn_port_mapping'])
573 return format_out({"sdn_port_mapping": data})
574 except bottle.HTTPError:
575 raise
576 except (nfvo.NfvoException, db_base_Exception) as e:
577 logger.error("http_post_datacenter_sdn_port_mapping error {}: {}".format(e.http_code, str(e)))
578 bottle.abort(e.http_code, str(e))
579 except Exception as e:
580 logger.error("Unexpected exception: ", exc_info=True)
581 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
582
583 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method='GET')
584 def http_get_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
585 '''get datacenter sdn mapping details, can use both uuid or name'''
586 try:
587 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
588
589 data = nfvo.datacenter_sdn_port_mapping_list(mydb, tenant_id, datacenter_id)
590 return format_out({"sdn_port_mapping": data})
591 except bottle.HTTPError:
592 raise
593 except (nfvo.NfvoException, db_base_Exception) as e:
594 logger.error("http_get_datacenter_sdn_port_mapping error {}: {}".format(e.http_code, str(e)))
595 bottle.abort(e.http_code, str(e))
596 except Exception as e:
597 logger.error("Unexpected exception: ", exc_info=True)
598 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
599
600 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method='DELETE')
601 def http_delete_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
602 '''clean datacenter sdn mapping, can use both uuid or name'''
603 try:
604 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
605 data = nfvo.datacenter_sdn_port_mapping_delete(mydb, tenant_id, datacenter_id)
606 return format_out({"result": data})
607 except bottle.HTTPError:
608 raise
609 except (nfvo.NfvoException, db_base_Exception) as e:
610 logger.error("http_delete_datacenter_sdn_port_mapping error {}: {}".format(e.http_code, str(e)))
611 bottle.abort(e.http_code, str(e))
612 except Exception as e:
613 logger.error("Unexpected exception: ", exc_info=True)
614 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
615
616 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/networks', method='GET') #deprecated
617 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='GET')
618 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method='GET')
619 def http_getnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
620 '''get datacenter networks, can use both uuid or name'''
621 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
622 #obtain data
623 try:
624 datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter_id, "datacenter")
625 where_= {"datacenter_id":datacenter_dict['uuid']}
626 if netmap_id:
627 if utils.check_valid_uuid(netmap_id):
628 where_["uuid"] = netmap_id
629 else:
630 where_["name"] = netmap_id
631 netmaps =mydb.get_rows(FROM='datacenter_nets',
632 SELECT=('name','vim_net_id as vim_id', 'uuid', 'type','multipoint','shared','description', 'created_at'),
633 WHERE=where_ )
634 utils.convert_float_timestamp2str(netmaps)
635 utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
636 if netmap_id and len(netmaps)==1:
637 data={'netmap' : netmaps[0]}
638 elif netmap_id and len(netmaps)==0:
639 bottle.abort(httperrors.Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.items())) )
640 return
641 else:
642 data={'netmaps' : netmaps}
643 return format_out(data)
644 except bottle.HTTPError:
645 raise
646 except (nfvo.NfvoException, db_base_Exception) as e:
647 logger.error("http_getnetwork_datacenter_id error {}: {}".format(e.http_code, str(e)))
648 bottle.abort(e.http_code, str(e))
649 except Exception as e:
650 logger.error("Unexpected exception: ", exc_info=True)
651 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
652
653
654 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='DELETE')
655 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method='DELETE')
656 def http_delnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
657 '''get datacenter networks, can use both uuid or name'''
658 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
659 #obtain data
660 try:
661 datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter_id, "datacenter")
662 where_= {"datacenter_id":datacenter_dict['uuid']}
663 if netmap_id:
664 if utils.check_valid_uuid(netmap_id):
665 where_["uuid"] = netmap_id
666 else:
667 where_["name"] = netmap_id
668 #change_keys_http2db(content, http2db_tenant, reverse=True)
669 deleted = mydb.delete_row(FROM='datacenter_nets', WHERE= where_)
670 if deleted == 0 and netmap_id:
671 bottle.abort(httperrors.Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.items())) )
672 if netmap_id:
673 return format_out({"result": "netmap {} deleted".format(netmap_id)})
674 else:
675 return format_out({"result": "{} netmap deleted".format(deleted)})
676 except bottle.HTTPError:
677 raise
678 except (nfvo.NfvoException, db_base_Exception) as e:
679 logger.error("http_delnetmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
680 bottle.abort(e.http_code, str(e))
681 except Exception as e:
682 logger.error("Unexpected exception: ", exc_info=True)
683 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
684
685
686 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/upload', method='POST')
687 def http_uploadnetmap_datacenter_id(tenant_id, datacenter_id):
688 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
689 try:
690 netmaps = nfvo.datacenter_new_netmap(mydb, tenant_id, datacenter_id, None)
691 utils.convert_float_timestamp2str(netmaps)
692 utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
693 data={'netmaps' : netmaps}
694 return format_out(data)
695 except bottle.HTTPError:
696 raise
697 except (nfvo.NfvoException, db_base_Exception) as e:
698 logger.error("http_uploadnetmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
699 bottle.abort(e.http_code, str(e))
700 except Exception as e:
701 logger.error("Unexpected exception: ", exc_info=True)
702 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
703
704
705 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='POST')
706 def http_postnetmap_datacenter_id(tenant_id, datacenter_id):
707 '''creates a new netmap'''
708 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
709 #parse input data
710 http_content,_ = format_in( netmap_new_schema )
711 r = utils.remove_extra_items(http_content, netmap_new_schema)
712 if r:
713 logger.debug("Remove received extra items %s", str(r))
714 try:
715 #obtain data, check that only one exist
716 netmaps = nfvo.datacenter_new_netmap(mydb, tenant_id, datacenter_id, http_content)
717 utils.convert_float_timestamp2str(netmaps)
718 utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
719 data={'netmaps' : netmaps}
720 return format_out(data)
721 except bottle.HTTPError:
722 raise
723 except (nfvo.NfvoException, db_base_Exception) as e:
724 logger.error("http_postnetmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
725 bottle.abort(e.http_code, str(e))
726 except Exception as e:
727 logger.error("Unexpected exception: ", exc_info=True)
728 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
729
730
731 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method='PUT')
732 def http_putnettmap_datacenter_id(tenant_id, datacenter_id, netmap_id):
733 '''edit a netmap'''
734 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
735 #parse input data
736 http_content,_ = format_in( netmap_edit_schema )
737 r = utils.remove_extra_items(http_content, netmap_edit_schema)
738 if r:
739 logger.debug("Remove received extra items %s", str(r))
740
741 #obtain data, check that only one exist
742 try:
743 nfvo.datacenter_edit_netmap(mydb, tenant_id, datacenter_id, netmap_id, http_content)
744 return http_getnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id)
745 except bottle.HTTPError:
746 raise
747 except (nfvo.NfvoException, db_base_Exception) as e:
748 logger.error("http_putnettmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
749 bottle.abort(e.http_code, str(e))
750 except Exception as e:
751 logger.error("Unexpected exception: ", exc_info=True)
752 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
753
754
755 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/action', method='POST')
756 def http_action_datacenter_id(tenant_id, datacenter_id):
757 '''perform an action over datacenter, can use both uuid or name'''
758 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
759 #parse input data
760 http_content,_ = format_in( datacenter_action_schema )
761 r = utils.remove_extra_items(http_content, datacenter_action_schema)
762 if r:
763 logger.debug("Remove received extra items %s", str(r))
764 try:
765 #obtain data, check that only one exist
766 result = nfvo.datacenter_action(mydb, tenant_id, datacenter_id, http_content)
767 if 'net-update' in http_content:
768 return http_getnetmap_datacenter_id(datacenter_id)
769 else:
770 return format_out(result)
771 except bottle.HTTPError:
772 raise
773 except (nfvo.NfvoException, db_base_Exception) as e:
774 logger.error("http_action_datacenter_id error {}: {}".format(e.http_code, str(e)))
775 bottle.abort(e.http_code, str(e))
776 except Exception as e:
777 logger.error("Unexpected exception: ", exc_info=True)
778 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
779
780
781 @bottle.route(url_base + '/datacenters/<datacenter_id>', method='DELETE')
782 def http_delete_datacenter_id( datacenter_id):
783 '''delete a tenant from database, can use both uuid or name'''
784
785 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
786 try:
787 data = nfvo.delete_datacenter(mydb, datacenter_id)
788 return format_out({"result":"datacenter '" + data + "' deleted"})
789 except bottle.HTTPError:
790 raise
791 except (nfvo.NfvoException, db_base_Exception) as e:
792 logger.error("http_delete_datacenter_id error {}: {}".format(e.http_code, str(e)))
793 bottle.abort(e.http_code, str(e))
794 except Exception as e:
795 logger.error("Unexpected exception: ", exc_info=True)
796 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
797
798
799 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='POST')
800 @bottle.route(url_base + '/<tenant_id>/vim_accounts', method='POST')
801 def http_associate_datacenters(tenant_id, datacenter_id=None):
802 '''associate an existing datacenter to a this tenant. '''
803 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
804 #parse input data
805 http_content,_ = format_in(datacenter_associate_schema, confidential_data=True)
806 r = utils.remove_extra_items(http_content, datacenter_associate_schema)
807 if r:
808 logger.debug("Remove received extra items %s", str(r))
809 try:
810 vim_account_id = nfvo.create_vim_account(mydb, tenant_id, datacenter_id,
811 **http_content['datacenter'])
812 return http_get_vim_account(tenant_id, vim_account_id)
813 except bottle.HTTPError:
814 raise
815 except (nfvo.NfvoException, db_base_Exception) as e:
816 logger.error("http_associate_datacenters error {}: {}".format(e.http_code, str(e)))
817 bottle.abort(e.http_code, str(e))
818 except Exception as e:
819 logger.error("Unexpected exception: ", exc_info=True)
820 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
821
822 @bottle.route(url_base + '/<tenant_id>/vim_accounts/<vim_account_id>', method='PUT')
823 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='PUT')
824 def http_vim_account_edit(tenant_id, vim_account_id=None, datacenter_id=None):
825 '''associate an existing datacenter to a this tenant. '''
826 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
827 #parse input data
828 http_content,_ = format_in(datacenter_associate_schema)
829 r = utils.remove_extra_items(http_content, datacenter_associate_schema)
830 if r:
831 logger.debug("Remove received extra items %s", str(r))
832 try:
833 vim_account_id = nfvo.edit_vim_account(mydb, tenant_id, vim_account_id, datacenter_id=datacenter_id,
834 **http_content['datacenter'])
835 return http_get_vim_account(tenant_id, vim_account_id)
836 except bottle.HTTPError:
837 raise
838 except (nfvo.NfvoException, db_base_Exception) as e:
839 logger.error("http_vim_account_edit error {}: {}".format(e.http_code, str(e)))
840 bottle.abort(e.http_code, str(e))
841 except Exception as e:
842 logger.error("Unexpected exception: ", exc_info=True)
843 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
844
845
846 @bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='DELETE')
847 @bottle.route(url_base + '/<tenant_id>/vim_accounts/<vim_account_id>', method='DELETE')
848 def http_deassociate_datacenters(tenant_id, datacenter_id=None, vim_account_id=None):
849 '''deassociate an existing datacenter to a this tenant. '''
850 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
851 try:
852 data = nfvo.delete_vim_account(mydb, tenant_id, vim_account_id, datacenter_id)
853 return format_out({"result": data})
854 except bottle.HTTPError:
855 raise
856 except (nfvo.NfvoException, db_base_Exception) as e:
857 logger.error("http_deassociate_datacenters error {}: {}".format(e.http_code, str(e)))
858 bottle.abort(e.http_code, str(e))
859 except Exception as e:
860 logger.error("Unexpected exception: ", exc_info=True)
861 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
862
863 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/network/<network_id>/attach', method='POST')
864 def http_post_vim_net_sdn_attach(tenant_id, datacenter_id, network_id):
865 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
866 http_content, _ = format_in(sdn_external_port_schema)
867 try:
868 data = nfvo.vim_net_sdn_attach(mydb, tenant_id, datacenter_id, network_id, http_content)
869 return format_out(data)
870 except bottle.HTTPError:
871 raise
872 except (nfvo.NfvoException, db_base_Exception) as e:
873 logger.error("http_post_vim_net_sdn_attach error {}: {}".format(e.http_code, str(e)))
874 bottle.abort(e.http_code, str(e))
875 except Exception as e:
876 logger.error("Unexpected exception: ", exc_info=True)
877 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
878
879 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/network/<network_id>/detach', method='DELETE')
880 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/network/<network_id>/detach/<port_id>', method='DELETE')
881 def http_delete_vim_net_sdn_detach(tenant_id, datacenter_id, network_id, port_id=None):
882 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
883 try:
884 data = nfvo.vim_net_sdn_detach(mydb, tenant_id, datacenter_id, network_id, port_id)
885 return format_out(data)
886 except bottle.HTTPError:
887 raise
888 except (nfvo.NfvoException, db_base_Exception) as e:
889 logger.error("http_delete_vim_net_sdn_detach error {}: {}".format(e.http_code, str(e)))
890 bottle.abort(e.http_code, str(e))
891 except Exception as e:
892 logger.error("Unexpected exception: ", exc_info=True)
893 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
894
895 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>', method='GET')
896 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method='GET')
897 def http_get_vim_items(tenant_id, datacenter_id, item, name=None):
898 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
899 try:
900 data = nfvo.vim_action_get(mydb, tenant_id, datacenter_id, item, name)
901 return format_out(data)
902 except bottle.HTTPError:
903 raise
904 except (nfvo.NfvoException, db_base_Exception) as e:
905 logger.error("http_get_vim_items error {}: {}".format(e.http_code, str(e)))
906 bottle.abort(e.http_code, str(e))
907 except Exception as e:
908 logger.error("Unexpected exception: ", exc_info=True)
909 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
910
911
912 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method='DELETE')
913 def http_del_vim_items(tenant_id, datacenter_id, item, name):
914 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
915 try:
916 data = nfvo.vim_action_delete(mydb, tenant_id, datacenter_id, item, name)
917 return format_out({"result":data})
918 except bottle.HTTPError:
919 raise
920 except (nfvo.NfvoException, db_base_Exception) as e:
921 logger.error("http_del_vim_items error {}: {}".format(e.http_code, str(e)))
922 bottle.abort(e.http_code, str(e))
923 except Exception as e:
924 logger.error("Unexpected exception: ", exc_info=True)
925 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
926
927
928 @bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>', method='POST')
929 def http_post_vim_items(tenant_id, datacenter_id, item):
930 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
931 http_content,_ = format_in( object_schema )
932 try:
933 data = nfvo.vim_action_create(mydb, tenant_id, datacenter_id, item, http_content)
934 return format_out(data)
935 except bottle.HTTPError:
936 raise
937 except (nfvo.NfvoException, db_base_Exception) as e:
938 logger.error("http_post_vim_items error {}: {}".format(e.http_code, str(e)))
939 bottle.abort(e.http_code, str(e))
940 except Exception as e:
941 logger.error("Unexpected exception: ", exc_info=True)
942 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
943
944
945 @bottle.route(url_base + '/<tenant_id>/vnfs', method='GET')
946 def http_get_vnfs(tenant_id):
947 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
948 try:
949 if tenant_id != 'any':
950 #check valid tenant_id
951 nfvo.check_tenant(mydb, tenant_id)
952 select_,where_,limit_ = filter_query_string(bottle.request.query, None,
953 ('uuid', 'name', 'osm_id', 'description', 'public', "tenant_id", "created_at") )
954 if tenant_id != "any":
955 where_["OR"]={"tenant_id": tenant_id, "public": True}
956 vnfs = mydb.get_rows(FROM='vnfs', SELECT=select_, WHERE=where_, LIMIT=limit_)
957 # change_keys_http2db(content, http2db_vnf, reverse=True)
958 utils.convert_str2boolean(vnfs, ('public',))
959 utils.convert_float_timestamp2str(vnfs)
960 data={'vnfs': vnfs}
961 return format_out(data)
962 except bottle.HTTPError:
963 raise
964 except (nfvo.NfvoException, db_base_Exception) as e:
965 logger.error("http_get_vnfs error {}: {}".format(e.http_code, str(e)))
966 bottle.abort(e.http_code, str(e))
967 except Exception as e:
968 logger.error("Unexpected exception: ", exc_info=True)
969 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
970
971
972 @bottle.route(url_base + '/<tenant_id>/vnfs/<vnf_id>', method='GET')
973 def http_get_vnf_id(tenant_id,vnf_id):
974 '''get vnf details, can use both uuid or name'''
975 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
976 try:
977 vnf = nfvo.get_vnf_id(mydb,tenant_id,vnf_id)
978 utils.convert_str2boolean(vnf, ('public',))
979 utils.convert_float_timestamp2str(vnf)
980 return format_out(vnf)
981 except bottle.HTTPError:
982 raise
983 except (nfvo.NfvoException, db_base_Exception) as e:
984 logger.error("http_get_vnf_id error {}: {}".format(e.http_code, str(e)))
985 bottle.abort(e.http_code, str(e))
986 except Exception as e:
987 logger.error("Unexpected exception: ", exc_info=True)
988 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
989
990
991 @bottle.route(url_base + '/<tenant_id>/vnfs', method='POST')
992 def http_post_vnfs(tenant_id):
993 """ Insert a vnf into the catalogue. Creates the flavor and images, and fill the tables at database
994 :param tenant_id: tenant that this vnf belongs to
995 :return:
996 """
997 # print "Parsing the YAML file of the VNF"
998 # parse input data
999 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1000 http_content, used_schema = format_in( vnfd_schema_v01, ("schema_version",), {"0.2": vnfd_schema_v02})
1001 r = utils.remove_extra_items(http_content, used_schema)
1002 if r:
1003 logger.debug("Remove received extra items %s", str(r))
1004 try:
1005 if used_schema == vnfd_schema_v01:
1006 vnf_id = nfvo.new_vnf(mydb,tenant_id,http_content)
1007 elif used_schema == vnfd_schema_v02:
1008 vnf_id = nfvo.new_vnf_v02(mydb,tenant_id,http_content)
1009 else:
1010 logger.warning('Unexpected schema_version: %s', http_content.get("schema_version"))
1011 bottle.abort(httperrors.Bad_Request, "Invalid schema version")
1012 return http_get_vnf_id(tenant_id, vnf_id)
1013 except bottle.HTTPError:
1014 raise
1015 except (nfvo.NfvoException, db_base_Exception) as e:
1016 logger.error("http_post_vnfs error {}: {}".format(e.http_code, str(e)))
1017 bottle.abort(e.http_code, str(e))
1018 except Exception as e:
1019 logger.error("Unexpected exception: ", exc_info=True)
1020 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1021
1022
1023 @bottle.route(url_base + '/v3/<tenant_id>/vnfd', method='POST')
1024 def http_post_vnfs_v3(tenant_id):
1025 """
1026 Insert one or several VNFs in the catalog, following OSM IM
1027 :param tenant_id: tenant owner of the VNF
1028 :return: The detailed list of inserted VNFs, following the old format
1029 """
1030 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1031 http_content, _ = format_in(None)
1032 try:
1033 vnfd_uuid_list = nfvo.new_vnfd_v3(mydb, tenant_id, http_content)
1034 vnfd_list = []
1035 for vnfd_uuid in vnfd_uuid_list:
1036 vnf = nfvo.get_vnf_id(mydb, tenant_id, vnfd_uuid)
1037 utils.convert_str2boolean(vnf, ('public',))
1038 utils.convert_float_timestamp2str(vnf)
1039 vnfd_list.append(vnf["vnf"])
1040 return format_out({"vnfd": vnfd_list})
1041 except bottle.HTTPError:
1042 raise
1043 except (nfvo.NfvoException, db_base_Exception) as e:
1044 logger.error("http_post_vnfs error {}: {}".format(e.http_code, str(e)))
1045 bottle.abort(e.http_code, str(e))
1046 except Exception as e:
1047 logger.error("Unexpected exception: ", exc_info=True)
1048 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1049
1050 @bottle.route(url_base + '/<tenant_id>/vnfs/<vnf_id>', method='DELETE')
1051 def http_delete_vnf_id(tenant_id, vnf_id):
1052 '''delete a vnf from database, and images and flavors in VIM when appropriate, can use both uuid or name'''
1053 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1054 #check valid tenant_id and deletes the vnf, including images,
1055 try:
1056 data = nfvo.delete_vnf(mydb,tenant_id,vnf_id)
1057 #print json.dumps(data, indent=4)
1058 return format_out({"result":"VNF " + data + " deleted"})
1059 except bottle.HTTPError:
1060 raise
1061 except (nfvo.NfvoException, db_base_Exception) as e:
1062 logger.error("http_delete_vnf_id error {}: {}".format(e.http_code, str(e)))
1063 bottle.abort(e.http_code, str(e))
1064 except Exception as e:
1065 logger.error("Unexpected exception: ", exc_info=True)
1066 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1067
1068
1069 #@bottle.route(url_base + '/<tenant_id>/hosts/topology', method='GET')
1070 #@bottle.route(url_base + '/<tenant_id>/physicalview/Madrid-Alcantara', method='GET')
1071 @bottle.route(url_base + '/<tenant_id>/physicalview/<datacenter>', method='GET')
1072 def http_get_hosts(tenant_id, datacenter):
1073 '''get the tidvim host hopology from the vim.'''
1074 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1075 #print "http_get_hosts received by tenant " + tenant_id + ' datacenter ' + datacenter
1076 try:
1077 if datacenter == 'treeview':
1078 data = nfvo.get_hosts(mydb, tenant_id)
1079 else:
1080 #openmano-gui is using a hardcoded value for the datacenter
1081 result, data = nfvo.get_hosts_info(mydb, tenant_id) #, datacenter)
1082
1083 if result < 0:
1084 #print("http_get_hosts error {} {}".format((-result, data))
1085 bottle.abort(-result, data)
1086 else:
1087 utils.convert_float_timestamp2str(data)
1088 #print json.dumps(data, indent=4)
1089 return format_out(data)
1090 except bottle.HTTPError:
1091 raise
1092 except (nfvo.NfvoException, db_base_Exception) as e:
1093 logger.error("http_get_hosts error {}: {}".format(e.http_code, str(e)))
1094 bottle.abort(e.http_code, str(e))
1095 except Exception as e:
1096 logger.error("Unexpected exception: ", exc_info=True)
1097 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1098
1099
1100 @bottle.route(url_base + '/<path:path>', method='OPTIONS')
1101 def http_options_deploy(path):
1102 '''For some reason GUI web ask for OPTIONS that must be responded'''
1103 #TODO: check correct path, and correct headers request
1104 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1105 bottle.response.set_header('Access-Control-Allow-Methods','POST, GET, PUT, DELETE, OPTIONS')
1106 bottle.response.set_header('Accept','application/yaml,application/json')
1107 bottle.response.set_header('Content-Type','application/yaml,application/json')
1108 bottle.response.set_header('Access-Control-Allow-Headers','content-type')
1109 bottle.response.set_header('Access-Control-Allow-Origin','*')
1110 return
1111
1112 @bottle.route(url_base + '/<tenant_id>/topology/deploy', method='POST')
1113 def http_post_deploy(tenant_id):
1114 '''post topology deploy.'''
1115 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1116
1117 http_content, used_schema = format_in( nsd_schema_v01, ("schema_version",), {2: nsd_schema_v02})
1118 #r = utils.remove_extra_items(http_content, used_schema)
1119 #if r is not None: print "http_post_deploy: Warning: remove extra items ", r
1120 #print "http_post_deploy input: ", http_content
1121
1122 try:
1123 scenario_id = nfvo.new_scenario(mydb, tenant_id, http_content)
1124 instance = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['name'], http_content['name'])
1125 #print json.dumps(data, indent=4)
1126 return format_out(instance)
1127 except bottle.HTTPError:
1128 raise
1129 except (nfvo.NfvoException, db_base_Exception) as e:
1130 logger.error("http_post_deploy error {}: {}".format(e.http_code, str(e)))
1131 bottle.abort(e.http_code, str(e))
1132 except Exception as e:
1133 logger.error("Unexpected exception: ", exc_info=True)
1134 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1135
1136
1137 @bottle.route(url_base + '/<tenant_id>/topology/verify', method='POST')
1138 def http_post_verify(tenant_id):
1139 #TODO:
1140 # '''post topology verify'''
1141 # print "http_post_verify by tenant " + tenant_id + ' datacenter ' + datacenter
1142 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1143 return
1144
1145 #
1146 # SCENARIOS
1147 #
1148
1149 @bottle.route(url_base + '/<tenant_id>/scenarios', method='POST')
1150 def http_post_scenarios(tenant_id):
1151 '''add a scenario into the catalogue. Creates the scenario and its internal structure in the OPENMANO DB'''
1152 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1153 http_content, used_schema = format_in( nsd_schema_v01, ("schema_version",), {2: nsd_schema_v02, "0.3": nsd_schema_v03})
1154 #r = utils.remove_extra_items(http_content, used_schema)
1155 #if r is not None: print "http_post_scenarios: Warning: remove extra items ", r
1156 #print "http_post_scenarios input: ", http_content
1157 try:
1158 if used_schema == nsd_schema_v01:
1159 scenario_id = nfvo.new_scenario(mydb, tenant_id, http_content)
1160 elif used_schema == nsd_schema_v02:
1161 scenario_id = nfvo.new_scenario_v02(mydb, tenant_id, http_content, "0.2")
1162 elif used_schema == nsd_schema_v03:
1163 scenario_id = nfvo.new_scenario_v02(mydb, tenant_id, http_content, "0.3")
1164 else:
1165 logger.warning('Unexpected schema_version: %s', http_content.get("schema_version"))
1166 bottle.abort(httperrors.Bad_Request, "Invalid schema version")
1167 #print json.dumps(data, indent=4)
1168 #return format_out(data)
1169 return http_get_scenario_id(tenant_id, scenario_id)
1170 except bottle.HTTPError:
1171 raise
1172 except (nfvo.NfvoException, db_base_Exception) as e:
1173 logger.error("http_post_scenarios error {}: {}".format(e.http_code, str(e)))
1174 bottle.abort(e.http_code, str(e))
1175 except Exception as e:
1176 logger.error("Unexpected exception: ", exc_info=True)
1177 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1178
1179 @bottle.route(url_base + '/v3/<tenant_id>/nsd', method='POST')
1180 def http_post_nsds_v3(tenant_id):
1181 """
1182 Insert one or several NSDs in the catalog, following OSM IM
1183 :param tenant_id: tenant owner of the NSD
1184 :return: The detailed list of inserted NSDs, following the old format
1185 """
1186 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1187 http_content, _ = format_in(None)
1188 try:
1189 nsd_uuid_list = nfvo.new_nsd_v3(mydb, tenant_id, http_content)
1190 nsd_list = []
1191 for nsd_uuid in nsd_uuid_list:
1192 scenario = mydb.get_scenario(nsd_uuid, tenant_id)
1193 utils.convert_float_timestamp2str(scenario)
1194 nsd_list.append(scenario)
1195 data = {'nsd': nsd_list}
1196 return format_out(data)
1197 except bottle.HTTPError:
1198 raise
1199 except (nfvo.NfvoException, db_base_Exception) as e:
1200 logger.error("http_post_nsds_v3 error {}: {}".format(e.http_code, str(e)))
1201 bottle.abort(e.http_code, str(e))
1202 except Exception as e:
1203 logger.error("Unexpected exception: ", exc_info=True)
1204 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1205
1206
1207 @bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>/action', method='POST')
1208 def http_post_scenario_action(tenant_id, scenario_id):
1209 '''take an action over a scenario'''
1210 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1211 # parse input data
1212 http_content, _ = format_in(scenario_action_schema)
1213 r = utils.remove_extra_items(http_content, scenario_action_schema)
1214 if r:
1215 logger.debug("Remove received extra items %s", str(r))
1216 try:
1217 # check valid tenant_id
1218 nfvo.check_tenant(mydb, tenant_id)
1219 if "start" in http_content:
1220 data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['start']['instance_name'], \
1221 http_content['start'].get('description',http_content['start']['instance_name']),
1222 http_content['start'].get('datacenter') )
1223 return format_out(data)
1224 elif "deploy" in http_content: #Equivalent to start
1225 data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['deploy']['instance_name'],
1226 http_content['deploy'].get('description',http_content['deploy']['instance_name']),
1227 http_content['deploy'].get('datacenter') )
1228 return format_out(data)
1229 elif "reserve" in http_content: #Reserve resources
1230 data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['reserve']['instance_name'],
1231 http_content['reserve'].get('description',http_content['reserve']['instance_name']),
1232 http_content['reserve'].get('datacenter'), startvms=False )
1233 return format_out(data)
1234 elif "verify" in http_content: #Equivalent to start and then delete
1235 data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['verify']['instance_name'],
1236 http_content['verify'].get('description',http_content['verify']['instance_name']),
1237 http_content['verify'].get('datacenter'), startvms=False )
1238 instance_id = data['uuid']
1239 nfvo.delete_instance(mydb, tenant_id,instance_id)
1240 return format_out({"result":"Verify OK"})
1241 except bottle.HTTPError:
1242 raise
1243 except (nfvo.NfvoException, db_base_Exception) as e:
1244 logger.error("http_post_scenario_action error {}: {}".format(e.http_code, str(e)))
1245 bottle.abort(e.http_code, str(e))
1246 except Exception as e:
1247 logger.error("Unexpected exception: ", exc_info=True)
1248 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1249
1250
1251 @bottle.route(url_base + '/<tenant_id>/scenarios', method='GET')
1252 def http_get_scenarios(tenant_id):
1253 '''get scenarios list'''
1254 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1255 try:
1256 #check valid tenant_id
1257 if tenant_id != "any":
1258 nfvo.check_tenant(mydb, tenant_id)
1259 #obtain data
1260 s,w,l=filter_query_string(bottle.request.query, None,
1261 ('uuid', 'name', 'osm_id', 'description', 'tenant_id', 'created_at', 'public'))
1262 if tenant_id != "any":
1263 w["OR"] = {"tenant_id": tenant_id, "public": True}
1264 scenarios = mydb.get_rows(SELECT=s, WHERE=w, LIMIT=l, FROM='scenarios')
1265 utils.convert_float_timestamp2str(scenarios)
1266 utils.convert_str2boolean(scenarios, ('public',) )
1267 data={'scenarios':scenarios}
1268 #print json.dumps(scenarios, indent=4)
1269 return format_out(data)
1270 except bottle.HTTPError:
1271 raise
1272 except (nfvo.NfvoException, db_base_Exception) as e:
1273 logger.error("http_get_scenarios error {}: {}".format(e.http_code, str(e)))
1274 bottle.abort(e.http_code, str(e))
1275 except Exception as e:
1276 logger.error("Unexpected exception: ", exc_info=True)
1277 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1278
1279
1280 @bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='GET')
1281 def http_get_scenario_id(tenant_id, scenario_id):
1282 '''get scenario details, can use both uuid or name'''
1283 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1284 try:
1285 #check valid tenant_id
1286 if tenant_id != "any":
1287 nfvo.check_tenant(mydb, tenant_id)
1288 #obtain data
1289 scenario = mydb.get_scenario(scenario_id, tenant_id)
1290 utils.convert_float_timestamp2str(scenario)
1291 data={'scenario' : scenario}
1292 return format_out(data)
1293 except bottle.HTTPError:
1294 raise
1295 except (nfvo.NfvoException, db_base_Exception) as e:
1296 logger.error("http_get_scenarios error {}: {}".format(e.http_code, str(e)))
1297 bottle.abort(e.http_code, str(e))
1298 except Exception as e:
1299 logger.error("Unexpected exception: ", exc_info=True)
1300 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1301
1302
1303 @bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='DELETE')
1304 def http_delete_scenario_id(tenant_id, scenario_id):
1305 '''delete a scenario from database, can use both uuid or name'''
1306 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1307 try:
1308 #check valid tenant_id
1309 if tenant_id != "any":
1310 nfvo.check_tenant(mydb, tenant_id)
1311 #obtain data
1312 data = mydb.delete_scenario(scenario_id, tenant_id)
1313 #print json.dumps(data, indent=4)
1314 return format_out({"result":"scenario " + data + " deleted"})
1315 except bottle.HTTPError:
1316 raise
1317 except (nfvo.NfvoException, db_base_Exception) as e:
1318 logger.error("http_delete_scenario_id error {}: {}".format(e.http_code, str(e)))
1319 bottle.abort(e.http_code, str(e))
1320 except Exception as e:
1321 logger.error("Unexpected exception: ", exc_info=True)
1322 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1323
1324
1325 @bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='PUT')
1326 def http_put_scenario_id(tenant_id, scenario_id):
1327 '''edit an existing scenario id'''
1328 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1329 http_content,_ = format_in( scenario_edit_schema )
1330 #r = utils.remove_extra_items(http_content, scenario_edit_schema)
1331 #if r is not None: print "http_put_scenario_id: Warning: remove extra items ", r
1332 #print "http_put_scenario_id input: ", http_content
1333 try:
1334 nfvo.edit_scenario(mydb, tenant_id, scenario_id, http_content)
1335 #print json.dumps(data, indent=4)
1336 #return format_out(data)
1337 return http_get_scenario_id(tenant_id, scenario_id)
1338 except bottle.HTTPError:
1339 raise
1340 except (nfvo.NfvoException, db_base_Exception) as e:
1341 logger.error("http_put_scenario_id error {}: {}".format(e.http_code, str(e)))
1342 bottle.abort(e.http_code, str(e))
1343 except Exception as e:
1344 logger.error("Unexpected exception: ", exc_info=True)
1345 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1346
1347 @bottle.route(url_base + '/<tenant_id>/instances', method='POST')
1348 def http_post_instances(tenant_id):
1349 '''create an instance-scenario'''
1350 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1351 # parse input data
1352 http_content, used_schema = format_in(instance_scenario_create_schema_v01)
1353 r = utils.remove_extra_items(http_content, used_schema)
1354 if r is not None:
1355 logger.warning("http_post_instances: Warning: remove extra items %s", str(r))
1356 try:
1357 #check valid tenant_id
1358 if tenant_id != "any":
1359 nfvo.check_tenant(mydb, tenant_id)
1360 data = nfvo.create_instance(mydb, tenant_id, http_content["instance"])
1361 return format_out(data)
1362 except bottle.HTTPError:
1363 raise
1364 except (nfvo.NfvoException, db_base_Exception) as e:
1365 logger.error("http_post_instances error {}: {}".format(e.http_code, str(e)), exc_info=True)
1366 bottle.abort(e.http_code, str(e))
1367 except Exception as e:
1368 logger.error("Unexpected exception: ", exc_info=True)
1369 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1370
1371 #
1372 # INSTANCES
1373 #
1374 @bottle.route(url_base + '/<tenant_id>/instances', method='GET')
1375 def http_get_instances(tenant_id):
1376 '''get instance list'''
1377 try:
1378 #check valid tenant_id
1379 if tenant_id != "any":
1380 nfvo.check_tenant(mydb, tenant_id)
1381 #obtain data
1382 s,w,l=filter_query_string(bottle.request.query, None, ('uuid', 'name', 'scenario_id', 'tenant_id', 'description', 'created_at'))
1383 if tenant_id != "any":
1384 w['tenant_id'] = tenant_id
1385 instances = mydb.get_rows(SELECT=s, WHERE=w, LIMIT=l, FROM='instance_scenarios')
1386 utils.convert_float_timestamp2str(instances)
1387 utils.convert_str2boolean(instances, ('public',) )
1388 data={'instances':instances}
1389 return format_out(data)
1390 except bottle.HTTPError:
1391 raise
1392 except (nfvo.NfvoException, db_base_Exception) as e:
1393 logger.error("http_get_instances error {}: {}".format(e.http_code, str(e)))
1394 bottle.abort(e.http_code, str(e))
1395 except Exception as e:
1396 logger.error("Unexpected exception: ", exc_info=True)
1397 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1398
1399
1400 @bottle.route(url_base + '/<tenant_id>/instances/<instance_id>', method='GET')
1401 def http_get_instance_id(tenant_id, instance_id):
1402 '''get instances details, can use both uuid or name'''
1403 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1404 try:
1405
1406 #check valid tenant_id
1407 if tenant_id != "any":
1408 nfvo.check_tenant(mydb, tenant_id)
1409 if tenant_id == "any":
1410 tenant_id = None
1411
1412 instance = nfvo.get_instance_id(mydb, tenant_id, instance_id)
1413
1414 # Workaround to SO, convert vnfs:vms:interfaces:ip_address from ";" separated list to report the first value
1415 for vnf in instance.get("vnfs", ()):
1416 for vm in vnf.get("vms", ()):
1417 for iface in vm.get("interfaces", ()):
1418 if iface.get("ip_address"):
1419 index = iface["ip_address"].find(";")
1420 if index >= 0:
1421 iface["ip_address"] = iface["ip_address"][:index]
1422 utils.convert_float_timestamp2str(instance)
1423 # print json.dumps(instance, indent=4)
1424 return format_out(instance)
1425 except bottle.HTTPError:
1426 raise
1427 except (nfvo.NfvoException, db_base_Exception) as e:
1428 logger.error("http_get_instance_id error {}: {}".format(e.http_code, str(e)))
1429 bottle.abort(e.http_code, str(e))
1430 except Exception as e:
1431 logger.error("Unexpected exception: ", exc_info=True)
1432 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1433
1434
1435 @bottle.route(url_base + '/<tenant_id>/instances/<instance_id>', method='DELETE')
1436 def http_delete_instance_id(tenant_id, instance_id):
1437 '''delete instance from VIM and from database, can use both uuid or name'''
1438 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1439 try:
1440 #check valid tenant_id
1441 if tenant_id != "any":
1442 nfvo.check_tenant(mydb, tenant_id)
1443 if tenant_id == "any":
1444 tenant_id = None
1445 #obtain data
1446 message = nfvo.delete_instance(mydb, tenant_id,instance_id)
1447 return format_out({"result":message})
1448 except bottle.HTTPError:
1449 raise
1450 except (nfvo.NfvoException, db_base_Exception) as e:
1451 logger.error("http_delete_instance_id error {}: {}".format(e.http_code, str(e)))
1452 bottle.abort(e.http_code, str(e))
1453 except Exception as e:
1454 logger.error("Unexpected exception: ", exc_info=True)
1455 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1456
1457
1458 @bottle.route(url_base + '/<tenant_id>/instances/<instance_id>/action', method='POST')
1459 def http_post_instance_scenario_action(tenant_id, instance_id):
1460 """
1461 take an action over a scenario instance
1462 :param tenant_id: tenant where user belongs to
1463 :param instance_id: instance indentity
1464 :return:
1465 """
1466 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1467 # parse input data
1468 http_content, _ = format_in(instance_scenario_action_schema)
1469 r = utils.remove_extra_items(http_content, instance_scenario_action_schema)
1470 if r:
1471 logger.debug("Remove received extra items %s", str(r))
1472 try:
1473 #check valid tenant_id
1474 if tenant_id != "any":
1475 nfvo.check_tenant(mydb, tenant_id)
1476
1477 #print "http_post_instance_scenario_action input: ", http_content
1478 #obtain data
1479 instance = mydb.get_instance_scenario(instance_id, tenant_id)
1480 instance_id = instance["uuid"]
1481
1482 data = nfvo.instance_action(mydb, tenant_id, instance_id, http_content)
1483 return format_out(data)
1484 except bottle.HTTPError:
1485 raise
1486 except (nfvo.NfvoException, db_base_Exception) as e:
1487 logger.error("http_post_instance_scenario_action error {}: {}".format(e.http_code, str(e)))
1488 bottle.abort(e.http_code, str(e))
1489 except Exception as e:
1490 logger.error("Unexpected exception: ", exc_info=True)
1491 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1492
1493
1494 @bottle.route(url_base + '/<tenant_id>/instances/<instance_id>/action', method='GET')
1495 @bottle.route(url_base + '/<tenant_id>/instances/<instance_id>/action/<action_id>', method='GET')
1496 def http_get_instance_scenario_action(tenant_id, instance_id, action_id=None):
1497 """
1498 List the actions done over an instance, or the action details
1499 :param tenant_id: tenant where user belongs to. Can be "any" to ignore
1500 :param instance_id: instance id, can be "any" to get actions of all instances
1501 :return:
1502 """
1503 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1504 try:
1505 # check valid tenant_id
1506 if tenant_id != "any":
1507 nfvo.check_tenant(mydb, tenant_id)
1508 data = nfvo.instance_action_get(mydb, tenant_id, instance_id, action_id)
1509 return format_out(data)
1510 except bottle.HTTPError:
1511 raise
1512 except (nfvo.NfvoException, db_base_Exception) as e:
1513 logger.error("http_get_instance_scenario_action error {}: {}".format(e.http_code, str(e)))
1514 bottle.abort(e.http_code, str(e))
1515 except Exception as e:
1516 logger.error("Unexpected exception: ", exc_info=True)
1517 bottle.abort(httperrors.Internal_Server_Error, type(e).__name__ + ": " + str(e))
1518
1519
1520 @bottle.error(400)
1521 @bottle.error(401)
1522 @bottle.error(404)
1523 @bottle.error(403)
1524 @bottle.error(405)
1525 @bottle.error(406)
1526 @bottle.error(409)
1527 @bottle.error(503)
1528 @bottle.error(500)
1529 def error400(error):
1530 e={"error":{"code":error.status_code, "type":error.status, "description":error.body}}
1531 bottle.response.headers['Access-Control-Allow-Origin'] = '*'
1532 return format_out(e)
1533