1 # -*- coding: utf-8 -*-
4 # Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
5 # This file is part of openmano
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
12 # http://www.apache.org/licenses/LICENSE-2.0
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
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact with: nfvlabs@tid.es
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.
29 __author__
="Alfonso Tierno, Gerardo Garcia"
30 __date__
="$17-sep-2014 09:07:15$"
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
45 from .http_tools
import errors
as httperrors
46 from .http_tools
.request_processing
import (
51 from .wim
.http_handler
import WimHandler
55 from .db_base
import db_base_Exception
56 from functools
import wraps
65 def log_to_logger(fn
):
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.)
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
,
77 bottle
.response
.status
)
78 return actual_response
81 class httpserver(threading
.Thread
):
82 def __init__(self
, db
, admin
=False, host
='localhost', port
=9090,
83 wim_persistence
=None, wim_engine
=None):
89 logger
= logging
.getLogger('openmano.http')
90 threading
.Thread
.__init
__(self
)
92 self
.port
= port
#Port where the listen service must be started
94 self
.name
= "http_admin"
97 #self.url_preffix = 'http://' + host + ':' + str(port) + url_base
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
104 WimHandler(db
, wim_persistence
, wim_engine
, url_base
)
110 def run(self
, debug
=False, quiet
=True):
111 bottle
.install(log_to_logger
)
112 default_app
= bottle
.app()
114 for handler
in self
.handlers
:
115 default_app
.merge(handler
.wsgi_app
)
117 bottle
.run(host
=self
.host
, port
=self
.port
, debug
=debug
, quiet
=quiet
)
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
126 @bottle.route(url_base
+ '/', method
='GET')
129 return 'works' #TODO: to be completed
131 @bottle.hook('after_request')
133 '''Don't know yet if really needed. Keep it just in case'''
134 bottle
.response
.headers
['Access-Control-Allow-Origin'] = '*'
136 @bottle.route(url_base
+ '/version', method
='GET')
137 def http_get_version():
138 return nfvo
.get_version()
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') )
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
:
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
))
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'''
168 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
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
:
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
))
194 @bottle.route(url_base
+ '/tenants', method
='POST')
195 def http_post_tenants():
196 '''insert a tenant into the catalogue. '''
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
)
202 logger
.debug("Remove received extra items %s", str(r
))
204 data
= nfvo
.new_tenant(mydb
, http_content
['tenant'])
205 return http_get_tenant_id(data
)
206 except bottle
.HTTPError
:
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
))
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'''
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
)
224 logger
.debug("Remove received extra items %s", str(r
))
226 #obtain data, check that only one exist
228 tenant
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
)
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
:
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
))
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
)
249 data
= nfvo
.delete_tenant(mydb
, tenant_id
)
250 return format_out({"result":"tenant " + data
+ " deleted"})
251 except bottle
.HTTPError
:
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
))
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
)
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_
)
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
:
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
))
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
)
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
}
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_
)
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
,
312 for vim_account
in vim_accounts
:
313 if vim_account
["passwd"]:
314 vim_account
["passwd"] = "******"
315 if vim_account
['config'] != None:
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)
330 return format_out({"datacenter": vim_accounts
[0]})
332 return format_out({"datacenters": vim_accounts
})
333 except bottle
.HTTPError
:
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
))
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
)
348 if tenant_id
!= 'any':
349 #check valid tenant_id
350 nfvo
.check_tenant(mydb
, tenant_id
)
352 what
= 'uuid' if utils
.check_valid_uuid(datacenter_id
) else 'name'
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'
361 from_
='datacenters as d'
362 datacenters
= mydb
.get_rows(
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':
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:
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
))
397 if datacenter
['config'] != None:
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
:
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
))
423 @bottle.route(url_base
+ '/datacenters', method
='POST')
424 def http_post_datacenters():
425 '''insert a datacenter into the catalogue. '''
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
)
431 logger
.debug("Remove received extra items %s", str(r
))
433 data
= nfvo
.new_datacenter(mydb
, http_content
['datacenter'])
434 return http_get_datacenter_id('any', data
)
435 except bottle
.HTTPError
:
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
))
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
)
450 http_content
,_
= format_in( datacenter_edit_schema
)
451 r
= utils
.remove_extra_items(http_content
, datacenter_edit_schema
)
453 logger
.debug("Remove received extra items %s", str(r
))
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
:
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
))
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. '''
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
)
474 logger
.debug("tenant_id: "+tenant_id
)
475 #logger.debug("content: {}".format(http_content['sdn_controller']))
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
:
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
))
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'''
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)
496 # logger.debug("Remove received extra items %s", str(r))
498 #logger.debug("tenant_id: "+tenant_id)
499 logger
.debug("content: {}".format(http_content
['sdn_controller']))
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
)})
504 except bottle
.HTTPError
:
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
))
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'''
517 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
519 data
= {'sdn_controllers': nfvo
.sdn_controller_list(mydb
, tenant_id
)}
520 return format_out(data
)
521 except bottle
.HTTPError
:
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
))
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'''
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
:
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
))
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'''
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
:
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
))
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. '''
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)
570 # logger.debug("Remove received extra items %s", str(r))
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
:
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
))
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'''
587 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
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
:
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
))
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'''
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
:
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
))
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
)
624 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id
, "datacenter")
625 where_
= {"datacenter_id":datacenter_dict
['uuid']}
627 if utils
.check_valid_uuid(netmap_id
):
628 where_
["uuid"] = netmap_id
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'),
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())) )
642 data
={'netmaps' : netmaps
}
643 return format_out(data
)
644 except bottle
.HTTPError
:
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
))
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
)
661 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id
, "datacenter")
662 where_
= {"datacenter_id":datacenter_dict
['uuid']}
664 if utils
.check_valid_uuid(netmap_id
):
665 where_
["uuid"] = netmap_id
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())) )
673 return format_out({"result": "netmap {} deleted".format(netmap_id
)})
675 return format_out({"result": "{} netmap deleted".format(deleted
)})
676 except bottle
.HTTPError
:
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
))
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
)
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
:
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
))
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
)
710 http_content
,_
= format_in( netmap_new_schema
)
711 r
= utils
.remove_extra_items(http_content
, netmap_new_schema
)
713 logger
.debug("Remove received extra items %s", str(r
))
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
:
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
))
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
):
734 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
736 http_content
,_
= format_in( netmap_edit_schema
)
737 r
= utils
.remove_extra_items(http_content
, netmap_edit_schema
)
739 logger
.debug("Remove received extra items %s", str(r
))
741 #obtain data, check that only one exist
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
:
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
))
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
)
760 http_content
,_
= format_in( datacenter_action_schema
)
761 r
= utils
.remove_extra_items(http_content
, datacenter_action_schema
)
763 logger
.debug("Remove received extra items %s", str(r
))
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
)
770 return format_out(result
)
771 except bottle
.HTTPError
:
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
))
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'''
785 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
787 data
= nfvo
.delete_datacenter(mydb
, datacenter_id
)
788 return format_out({"result":"datacenter '" + data
+ "' deleted"})
789 except bottle
.HTTPError
:
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
))
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
)
805 http_content
,_
= format_in(datacenter_associate_schema
, confidential_data
=True)
806 r
= utils
.remove_extra_items(http_content
, datacenter_associate_schema
)
808 logger
.debug("Remove received extra items %s", str(r
))
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
:
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
))
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
)
828 http_content
,_
= format_in(datacenter_associate_schema
)
829 r
= utils
.remove_extra_items(http_content
, datacenter_associate_schema
)
831 logger
.debug("Remove received extra items %s", str(r
))
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
:
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
))
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
)
852 data
= nfvo
.delete_vim_account(mydb
, tenant_id
, vim_account_id
, datacenter_id
)
853 return format_out({"result": data
})
854 except bottle
.HTTPError
:
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
))
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
)
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
:
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
))
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
)
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
:
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
))
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
)
900 data
= nfvo
.vim_action_get(mydb
, tenant_id
, datacenter_id
, item
, name
)
901 return format_out(data
)
902 except bottle
.HTTPError
:
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
))
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
)
916 data
= nfvo
.vim_action_delete(mydb
, tenant_id
, datacenter_id
, item
, name
)
917 return format_out({"result":data
})
918 except bottle
.HTTPError
:
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
))
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
)
933 data
= nfvo
.vim_action_create(mydb
, tenant_id
, datacenter_id
, item
, http_content
)
934 return format_out(data
)
935 except bottle
.HTTPError
:
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
))
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
)
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
)
961 return format_out(data
)
962 except bottle
.HTTPError
:
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
))
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
)
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
:
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
))
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
997 # print "Parsing the YAML file of the VNF"
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
)
1003 logger
.debug("Remove received extra items %s", str(r
))
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
)
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
:
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
))
1023 @bottle.route(url_base
+ '/v3/<tenant_id>/vnfd', method
='POST')
1024 def http_post_vnfs_v3(tenant_id
):
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
1030 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1031 http_content
, _
= format_in(None)
1033 vnfd_uuid_list
= nfvo
.new_vnfd_v3(mydb
, tenant_id
, http_content
)
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
:
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
))
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,
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
:
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
))
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
1077 if datacenter
== 'treeview':
1078 data
= nfvo
.get_hosts(mydb
, tenant_id
)
1080 #openmano-gui is using a hardcoded value for the datacenter
1081 result
, data
= nfvo
.get_hosts_info(mydb
, tenant_id
) #, datacenter)
1084 #print("http_get_hosts error {} {}".format((-result, data))
1085 bottle
.abort(-result
, data
)
1087 utils
.convert_float_timestamp2str(data
)
1088 #print json.dumps(data, indent=4)
1089 return format_out(data
)
1090 except bottle
.HTTPError
:
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
))
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','*')
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
)
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
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
:
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
))
1137 @bottle.route(url_base
+ '/<tenant_id>/topology/verify', method
='POST')
1138 def http_post_verify(tenant_id
):
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
)
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
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")
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
:
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
))
1179 @bottle.route(url_base
+ '/v3/<tenant_id>/nsd', method
='POST')
1180 def http_post_nsds_v3(tenant_id
):
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
1186 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1187 http_content
, _
= format_in(None)
1189 nsd_uuid_list
= nfvo
.new_nsd_v3(mydb
, tenant_id
, http_content
)
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
:
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
))
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
)
1212 http_content
, _
= format_in(scenario_action_schema
)
1213 r
= utils
.remove_extra_items(http_content
, scenario_action_schema
)
1215 logger
.debug("Remove received extra items %s", str(r
))
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
:
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
))
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
)
1256 #check valid tenant_id
1257 if tenant_id
!= "any":
1258 nfvo
.check_tenant(mydb
, tenant_id
)
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
:
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
))
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
)
1285 #check valid tenant_id
1286 if tenant_id
!= "any":
1287 nfvo
.check_tenant(mydb
, tenant_id
)
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
:
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
))
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
)
1308 #check valid tenant_id
1309 if tenant_id
!= "any":
1310 nfvo
.check_tenant(mydb
, tenant_id
)
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
:
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
))
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
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
:
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
))
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
)
1352 http_content
, used_schema
= format_in(instance_scenario_create_schema_v01
)
1353 r
= utils
.remove_extra_items(http_content
, used_schema
)
1355 logger
.warning("http_post_instances: Warning: remove extra items %s", str(r
))
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
:
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
))
1374 @bottle.route(url_base
+ '/<tenant_id>/instances', method
='GET')
1375 def http_get_instances(tenant_id
):
1376 '''get instance list'''
1378 #check valid tenant_id
1379 if tenant_id
!= "any":
1380 nfvo
.check_tenant(mydb
, tenant_id
)
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
:
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
))
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
)
1406 #check valid tenant_id
1407 if tenant_id
!= "any":
1408 nfvo
.check_tenant(mydb
, tenant_id
)
1409 if tenant_id
== "any":
1412 instance
= nfvo
.get_instance_id(mydb
, tenant_id
, instance_id
)
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(";")
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
:
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
))
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
)
1440 #check valid tenant_id
1441 if tenant_id
!= "any":
1442 nfvo
.check_tenant(mydb
, tenant_id
)
1443 if tenant_id
== "any":
1446 message
= nfvo
.delete_instance(mydb
, tenant_id
,instance_id
)
1447 return format_out({"result":message
})
1448 except bottle
.HTTPError
:
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
))
1458 @bottle.route(url_base
+ '/<tenant_id>/instances/<instance_id>/action', method
='POST')
1459 def http_post_instance_scenario_action(tenant_id
, instance_id
):
1461 take an action over a scenario instance
1462 :param tenant_id: tenant where user belongs to
1463 :param instance_id: instance indentity
1466 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1468 http_content
, _
= format_in(instance_scenario_action_schema
)
1469 r
= utils
.remove_extra_items(http_content
, instance_scenario_action_schema
)
1471 logger
.debug("Remove received extra items %s", str(r
))
1473 #check valid tenant_id
1474 if tenant_id
!= "any":
1475 nfvo
.check_tenant(mydb
, tenant_id
)
1477 #print "http_post_instance_scenario_action input: ", http_content
1479 instance
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
1480 instance_id
= instance
["uuid"]
1482 data
= nfvo
.instance_action(mydb
, tenant_id
, instance_id
, http_content
)
1483 return format_out(data
)
1484 except bottle
.HTTPError
:
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
))
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):
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
1503 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
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
:
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
))
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
)