1 # -*- coding: utf-8 -*-
4 # Copyright 2015 Telefónica Investigación 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$"
39 from jsonschema
import validate
as js_v
, exceptions
as js_e
40 from openmano_schemas
import vnfd_schema_v01
, vnfd_schema_v02
, \
41 nsd_schema_v01
, nsd_schema_v02
, nsd_schema_v03
, scenario_edit_schema
, \
42 scenario_action_schema
, instance_scenario_action_schema
, instance_scenario_create_schema_v01
, \
43 tenant_schema
, tenant_edit_schema
,\
44 datacenter_schema
, datacenter_edit_schema
, datacenter_action_schema
, datacenter_associate_schema
,\
45 object_schema
, netmap_new_schema
, netmap_edit_schema
, sdn_controller_schema
, sdn_controller_edit_schema
, \
46 sdn_port_mapping_schema
50 from db_base
import db_base_Exception
51 from functools
import wraps
59 HTTP_Bad_Request
= 400
60 HTTP_Unauthorized
= 401
63 HTTP_Method_Not_Allowed
= 405
64 HTTP_Not_Acceptable
= 406
65 HTTP_Service_Unavailable
= 503
66 HTTP_Internal_Server_Error
= 500
68 def delete_nulls(var
):
71 if var
[k
] is None: del var
[k
]
72 elif type(var
[k
]) is dict or type(var
[k
]) is list or type(var
[k
]) is tuple:
73 if delete_nulls(var
[k
]): del var
[k
]
74 if len(var
) == 0: return True
75 elif type(var
) is list or type(var
) is tuple:
77 if type(k
) is dict: delete_nulls(k
)
78 if len(var
) == 0: return True
81 def convert_datetime2str(var
):
82 '''Converts a datetime variable to a string with the format '%Y-%m-%dT%H:%i:%s'
83 It enters recursively in the dict var finding this kind of variables
86 for k
,v
in var
.items():
87 if type(v
) is float and k
in ("created_at", "modified_at"):
88 var
[k
] = time
.strftime("%Y-%m-%dT%H:%M:%S", time
.localtime(v
) )
89 elif type(v
) is dict or type(v
) is list or type(v
) is tuple:
90 convert_datetime2str(v
)
91 if len(var
) == 0: return True
92 elif type(var
) is list or type(var
) is tuple:
94 convert_datetime2str(v
)
96 def log_to_logger(fn
):
98 Wrap a Bottle request so that a log line is emitted after it's handled.
99 (This decorator can be extended to take the desired logger as a param.)
102 def _log_to_logger(*args
, **kwargs
):
103 actual_response
= fn(*args
, **kwargs
)
104 # modify this to log exactly what you need:
105 logger
.info('FROM %s %s %s %s' % (bottle
.request
.remote_addr
,
106 bottle
.request
.method
,
108 bottle
.response
.status
))
109 return actual_response
110 return _log_to_logger
112 class httpserver(threading
.Thread
):
113 def __init__(self
, db
, admin
=False, host
='localhost', port
=9090):
119 logger
= logging
.getLogger('openmano.http')
120 threading
.Thread
.__init
__(self
)
122 self
.port
= port
#Port where the listen service must be started
124 self
.name
= "http_admin"
127 #self.url_preffix = 'http://' + host + ':' + str(port) + url_base
129 #self.first_usable_connection_index = 10
130 #self.next_connection_index = self.first_usable_connection_index #The next connection index to be used
131 #Ensure that when the main program exits the thread will also exit
136 bottle
.install(log_to_logger
)
137 bottle
.run(host
=self
.host
, port
=self
.port
, debug
=False, quiet
=True)
139 def run_bottle(db
, host_
='localhost', port_
=9090):
140 '''used for launching in main thread, so that it can be debugged'''
143 bottle
.run(host
=host_
, port
=port_
, debug
=True) #quiet=True
146 @bottle.route(url_base
+ '/', method
='GET')
149 return 'works' #TODO: to be completed
155 def change_keys_http2db(data
, http_db
, reverse
=False):
156 '''Change keys of dictionary data acording to the key_dict values
157 This allow change from http interface names to database names.
158 When reverse is True, the change is otherwise
160 data: can be a dictionary or a list
161 http_db: is a dictionary with hhtp names as keys and database names as value
162 reverse: by default change is done from http api to database. If True change is done otherwise
163 Return: None, but data is modified'''
164 if type(data
) is tuple or type(data
) is list:
166 change_keys_http2db(d
, http_db
, reverse
)
167 elif type(data
) is dict or type(data
) is bottle
.FormsDict
:
169 for k
,v
in http_db
.items():
170 if v
in data
: data
[k
]=data
.pop(v
)
172 for k
,v
in http_db
.items():
173 if k
in data
: data
[v
]=data
.pop(k
)
175 def format_out(data
):
176 '''return string of dictionary data according to requested json, yaml, xml. By default json'''
177 logger
.debug("OUT: " + yaml
.safe_dump(data
, explicit_start
=True, indent
=4, default_flow_style
=False, tags
=False, encoding
='utf-8', allow_unicode
=True) )
178 if 'application/yaml' in bottle
.request
.headers
.get('Accept'):
179 bottle
.response
.content_type
='application/yaml'
180 return yaml
.safe_dump(data
, explicit_start
=True, indent
=4, default_flow_style
=False, tags
=False, encoding
='utf-8', allow_unicode
=True) #, canonical=True, default_style='"'
181 else: #by default json
182 bottle
.response
.content_type
='application/json'
183 #return data #json no style
184 return json
.dumps(data
, indent
=4) + "\n"
186 def format_in(default_schema
, version_fields
=None, version_dict_schema
=None):
187 ''' Parse the content of HTTP request against a json_schema
189 default_schema: The schema to be parsed by default if no version field is found in the client data
190 version_fields: If provided it contains a tuple or list with the fields to iterate across the client data to obtain the version
191 version_dict_schema: It contains a dictionary with the version as key, and json schema to apply as value
192 It can contain a None as key, and this is apply if the client data version does not match any key
194 user_data, used_schema: if the data is successfully decoded and matches the schema
195 launch a bottle abort if fails
197 #print "HEADERS :" + str(bottle.request.headers.items())
199 error_text
= "Invalid header format "
200 format_type
= bottle
.request
.headers
.get('Content-Type', 'application/json')
201 if 'application/json' in format_type
:
202 error_text
= "Invalid json format "
203 #Use the json decoder instead of bottle decoder because it informs about the location of error formats with a ValueError exception
204 client_data
= json
.load(bottle
.request
.body
)
205 #client_data = bottle.request.json()
206 elif 'application/yaml' in format_type
:
207 error_text
= "Invalid yaml format "
208 client_data
= yaml
.load(bottle
.request
.body
)
209 elif 'application/xml' in format_type
:
210 bottle
.abort(501, "Content-Type: application/xml not supported yet.")
212 logger
.warning('Content-Type ' + str(format_type
) + ' not supported.')
213 bottle
.abort(HTTP_Not_Acceptable
, 'Content-Type ' + str(format_type
) + ' not supported.')
215 #if client_data == None:
216 # bottle.abort(HTTP_Bad_Request, "Content error, empty")
219 logger
.debug('IN: %s', yaml
.safe_dump(client_data
, explicit_start
=True, indent
=4, default_flow_style
=False, tags
=False, encoding
='utf-8', allow_unicode
=True) )
220 #look for the client provider version
221 error_text
= "Invalid content "
222 client_version
= None
224 if version_fields
!= None:
225 client_version
= client_data
226 for field
in version_fields
:
227 if field
in client_version
:
228 client_version
= client_version
[field
]
232 if client_version
==None:
233 used_schema
=default_schema
234 elif version_dict_schema
!=None:
235 if client_version
in version_dict_schema
:
236 used_schema
= version_dict_schema
[client_version
]
237 elif None in version_dict_schema
:
238 used_schema
= version_dict_schema
[None]
239 if used_schema
==None:
240 bottle
.abort(HTTP_Bad_Request
, "Invalid schema version or missing version field")
242 js_v(client_data
, used_schema
)
243 return client_data
, used_schema
244 except (ValueError, yaml
.YAMLError
) as exc
:
245 error_text
+= str(exc
)
246 logger
.error(error_text
)
247 bottle
.abort(HTTP_Bad_Request
, error_text
)
248 except js_e
.ValidationError
as exc
:
249 logger
.error("validate_in error, jsonschema exception at '%s' '%s' ", str(exc
.path
), str(exc
.message
))
251 if len(exc
.path
)>0: error_pos
=" at " + ":".join(map(json
.dumps
, exc
.path
))
252 bottle
.abort(HTTP_Bad_Request
, error_text
+ exc
.message
+ error_pos
)
254 # bottle.abort(HTTP_Bad_Request, "Content error: Failed to parse Content-Type", error_pos)
257 def filter_query_string(qs
, http2db
, allowed
):
258 '''Process query string (qs) checking that contains only valid tokens for avoiding SQL injection
260 'qs': bottle.FormsDict variable to be processed. None or empty is considered valid
261 'http2db': dictionary with change from http API naming (dictionary key) to database naming(dictionary value)
262 'allowed': list of allowed string tokens (API http naming). All the keys of 'qs' must be one of 'allowed'
263 Return: A tuple with the (select,where,limit) to be use in a database query. All of then transformed to the database naming
264 select: list of items to retrieve, filtered by query string 'field=token'. If no 'field' is present, allowed list is returned
265 where: dictionary with key, value, taken from the query string token=value. Empty if nothing is provided
266 limit: limit dictated by user with the query string 'limit'. 100 by default
267 abort if not permited, using bottel.abort
272 #if type(qs) is not bottle.FormsDict:
273 # bottle.abort(HTTP_Internal_Server_Error, '!!!!!!!!!!!!!!invalid query string not a dictionary')
274 # #bottle.abort(HTTP_Internal_Server_Error, "call programmer")
277 select
+= qs
.getall(k
)
280 bottle
.abort(HTTP_Bad_Request
, "Invalid query string at 'field="+v
+"'")
285 bottle
.abort(HTTP_Bad_Request
, "Invalid query string at 'limit="+qs
[k
]+"'")
288 bottle
.abort(HTTP_Bad_Request
, "Invalid query string at '"+k
+"="+qs
[k
]+"'")
289 if qs
[k
]!="null": where
[k
]=qs
[k
]
291 if len(select
)==0: select
+= allowed
292 #change from http api to database naming
293 for i
in range(0,len(select
)):
295 if http2db
and k
in http2db
:
296 select
[i
] = http2db
[k
]
298 change_keys_http2db(where
, http2db
)
299 #print "filter_query_string", select,where,limit
301 return select
,where
,limit
303 @bottle.hook('after_request')
305 '''Don't know yet if really needed. Keep it just in case'''
306 bottle
.response
.headers
['Access-Control-Allow-Origin'] = '*'
312 @bottle.route(url_base
+ '/tenants', method
='GET')
313 def http_get_tenants():
314 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
315 select_
,where_
,limit_
= filter_query_string(bottle
.request
.query
, None,
316 ('uuid','name','description','created_at') )
318 tenants
= mydb
.get_rows(FROM
='nfvo_tenants', SELECT
=select_
,WHERE
=where_
,LIMIT
=limit_
)
319 #change_keys_http2db(content, http2db_tenant, reverse=True)
320 convert_datetime2str(tenants
)
321 data
={'tenants' : tenants
}
322 return format_out(data
)
323 except db_base_Exception
as e
:
324 logger
.error("http_get_tenants error {}: {}".format(e
.http_code
, str(e
)))
325 bottle
.abort(e
.http_code
, str(e
))
326 except Exception as e
:
327 logger
.error("Unexpected exception: ", exc_info
=True)
328 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
331 @bottle.route(url_base
+ '/tenants/<tenant_id>', method
='GET')
332 def http_get_tenant_id(tenant_id
):
333 '''get tenant details, can use both uuid or name'''
335 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
337 tenant
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
, "tenant")
338 #change_keys_http2db(content, http2db_tenant, reverse=True)
339 convert_datetime2str(tenant
)
340 data
={'tenant' : tenant
}
341 return format_out(data
)
342 except db_base_Exception
as e
:
343 logger
.error("http_get_tenant_id error {}: {}".format(e
.http_code
, str(e
)))
344 bottle
.abort(e
.http_code
, str(e
))
345 except Exception as e
:
346 logger
.error("Unexpected exception: ", exc_info
=True)
347 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
350 @bottle.route(url_base
+ '/tenants', method
='POST')
351 def http_post_tenants():
352 '''insert a tenant into the catalogue. '''
354 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
355 http_content
,_
= format_in( tenant_schema
)
356 r
= utils
.remove_extra_items(http_content
, tenant_schema
)
358 logger
.debug("Remove received extra items %s", str(r
))
360 data
= nfvo
.new_tenant(mydb
, http_content
['tenant'])
361 return http_get_tenant_id(data
)
362 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
363 logger
.error("http_post_tenants error {}: {}".format(e
.http_code
, str(e
)))
364 bottle
.abort(e
.http_code
, str(e
))
365 except Exception as e
:
366 logger
.error("Unexpected exception: ", exc_info
=True)
367 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
370 @bottle.route(url_base
+ '/tenants/<tenant_id>', method
='PUT')
371 def http_edit_tenant_id(tenant_id
):
372 '''edit tenant details, can use both uuid or name'''
374 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
375 http_content
,_
= format_in( tenant_edit_schema
)
376 r
= utils
.remove_extra_items(http_content
, tenant_edit_schema
)
378 logger
.debug("Remove received extra items %s", str(r
))
380 #obtain data, check that only one exist
382 tenant
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
)
384 tenant_id
= tenant
['uuid']
385 where
={'uuid': tenant
['uuid']}
386 mydb
.update_rows('nfvo_tenants', http_content
['tenant'], where
)
387 return http_get_tenant_id(tenant_id
)
388 except db_base_Exception
as e
:
389 logger
.error("http_edit_tenant_id error {}: {}".format(e
.http_code
, str(e
)))
390 bottle
.abort(e
.http_code
, str(e
))
391 except Exception as e
:
392 logger
.error("Unexpected exception: ", exc_info
=True)
393 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
396 @bottle.route(url_base
+ '/tenants/<tenant_id>', method
='DELETE')
397 def http_delete_tenant_id(tenant_id
):
398 '''delete a tenant from database, can use both uuid or name'''
399 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
401 data
= nfvo
.delete_tenant(mydb
, tenant_id
)
402 return format_out({"result":"tenant " + data
+ " deleted"})
403 except db_base_Exception
as e
:
404 logger
.error("http_delete_tenant_id error {}: {}".format(e
.http_code
, str(e
)))
405 bottle
.abort(e
.http_code
, str(e
))
406 except Exception as e
:
407 logger
.error("Unexpected exception: ", exc_info
=True)
408 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
411 @bottle.route(url_base
+ '/<tenant_id>/datacenters', method
='GET')
412 def http_get_datacenters(tenant_id
):
413 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
415 if tenant_id
!= 'any':
416 #check valid tenant_id
417 nfvo
.check_tenant(mydb
, tenant_id
)
418 select_
,where_
,limit_
= filter_query_string(bottle
.request
.query
, None,
419 ('uuid','name','vim_url','type','created_at') )
420 if tenant_id
!= 'any':
421 where_
['nfvo_tenant_id'] = tenant_id
422 if 'created_at' in select_
:
423 select_
[ select_
.index('created_at') ] = 'd.created_at as created_at'
424 if 'created_at' in where_
:
425 where_
['d.created_at'] = where_
.pop('created_at')
426 datacenters
= mydb
.get_rows(FROM
='datacenters as d join tenants_datacenters as td on d.uuid=td.datacenter_id',
427 SELECT
=select_
,WHERE
=where_
,LIMIT
=limit_
)
429 datacenters
= mydb
.get_rows(FROM
='datacenters',
430 SELECT
=select_
,WHERE
=where_
,LIMIT
=limit_
)
431 #change_keys_http2db(content, http2db_tenant, reverse=True)
432 convert_datetime2str(datacenters
)
433 data
={'datacenters' : datacenters
}
434 return format_out(data
)
435 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
436 logger
.error("http_get_datacenters error {}: {}".format(e
.http_code
, str(e
)))
437 bottle
.abort(e
.http_code
, str(e
))
438 except Exception as e
:
439 logger
.error("Unexpected exception: ", exc_info
=True)
440 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
443 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>', method
='GET')
444 def http_get_datacenter_id(tenant_id
, datacenter_id
):
445 '''get datacenter details, can use both uuid or name'''
446 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
448 if tenant_id
!= 'any':
449 #check valid tenant_id
450 nfvo
.check_tenant(mydb
, tenant_id
)
452 what
= 'uuid' if utils
.check_valid_uuid(datacenter_id
) else 'name'
454 where_
[what
] = datacenter_id
455 select_
=['uuid', 'name','vim_url', 'vim_url_admin', 'type', 'd.config as config', 'description', 'd.created_at as created_at']
456 if tenant_id
!= 'any':
457 select_
.append("datacenter_tenant_id")
458 where_
['td.nfvo_tenant_id']= tenant_id
459 from_
='datacenters as d join tenants_datacenters as td on d.uuid=td.datacenter_id'
461 from_
='datacenters as d'
462 datacenters
= mydb
.get_rows(
467 if len(datacenters
)==0:
468 bottle
.abort( HTTP_Not_Found
, "No datacenter found for tenant with {} '{}'".format(what
, datacenter_id
) )
469 elif len(datacenters
)>1:
470 bottle
.abort( HTTP_Bad_Request
, "More than one datacenter found for tenant with {} '{}'".format(what
, datacenter_id
) )
471 datacenter
= datacenters
[0]
472 if tenant_id
!= 'any':
474 vim_tenants
= mydb
.get_rows(
475 SELECT
=("vim_tenant_name", "vim_tenant_id", "user", "passwd", "config"),
476 FROM
="datacenter_tenants",
477 WHERE
={"uuid": datacenters
[0]["datacenter_tenant_id"]},
478 ORDER_BY
=("created", ) )
479 del datacenter
["datacenter_tenant_id"]
480 datacenter
["vim_tenants"] = vim_tenants
481 for vim_tenant
in vim_tenants
:
482 if vim_tenant
["passwd"]:
483 vim_tenant
["passwd"] = "******"
484 if vim_tenant
['config'] != None:
486 config_dict
= yaml
.load(vim_tenant
['config'])
487 vim_tenant
['config'] = config_dict
488 except Exception as e
:
489 logger
.error("Exception '%s' while trying to load config information", str(e
))
491 if datacenter
['config'] != None:
493 config_dict
= yaml
.load(datacenter
['config'])
494 datacenter
['config'] = config_dict
495 except Exception as e
:
496 logger
.error("Exception '%s' while trying to load config information", str(e
))
497 #change_keys_http2db(content, http2db_datacenter, reverse=True)
498 convert_datetime2str(datacenter
)
499 data
={'datacenter' : datacenter
}
500 return format_out(data
)
501 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
502 logger
.error("http_get_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
503 bottle
.abort(e
.http_code
, str(e
))
504 except Exception as e
:
505 logger
.error("Unexpected exception: ", exc_info
=True)
506 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
509 @bottle.route(url_base
+ '/datacenters', method
='POST')
510 def http_post_datacenters():
511 '''insert a datacenter into the catalogue. '''
513 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
514 http_content
,_
= format_in( datacenter_schema
)
515 r
= utils
.remove_extra_items(http_content
, datacenter_schema
)
517 logger
.debug("Remove received extra items %s", str(r
))
519 data
= nfvo
.new_datacenter(mydb
, http_content
['datacenter'])
520 return http_get_datacenter_id('any', data
)
521 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
522 logger
.error("http_post_datacenters error {}: {}".format(e
.http_code
, str(e
)))
523 bottle
.abort(e
.http_code
, str(e
))
524 except Exception as e
:
525 logger
.error("Unexpected exception: ", exc_info
=True)
526 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
529 @bottle.route(url_base
+ '/datacenters/<datacenter_id_name>', method
='PUT')
530 def http_edit_datacenter_id(datacenter_id_name
):
531 '''edit datacenter details, can use both uuid or name'''
532 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
534 http_content
,_
= format_in( datacenter_edit_schema
)
535 r
= utils
.remove_extra_items(http_content
, datacenter_edit_schema
)
537 logger
.debug("Remove received extra items %s", str(r
))
540 datacenter_id
= nfvo
.edit_datacenter(mydb
, datacenter_id_name
, http_content
['datacenter'])
541 return http_get_datacenter_id('any', datacenter_id
)
542 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
543 logger
.error("http_edit_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
544 bottle
.abort(e
.http_code
, str(e
))
545 except Exception as e
:
546 logger
.error("Unexpected exception: ", exc_info
=True)
547 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
549 @bottle.route(url_base
+ '/<tenant_id>/sdn_controllers', method
='POST')
550 def http_post_sdn_controller(tenant_id
):
551 '''insert a sdn controller into the catalogue. '''
553 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
554 http_content
,_
= format_in( sdn_controller_schema
)
556 logger
.debug("tenant_id: "+tenant_id
)
557 #logger.debug("content: {}".format(http_content['sdn_controller']))
559 data
= nfvo
.sdn_controller_create(mydb
, tenant_id
, http_content
['sdn_controller'])
560 return format_out({"sdn_controller": nfvo
.sdn_controller_list(mydb
, tenant_id
, data
)})
561 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
562 logger
.error("http_post_sdn_controller error {}: {}".format(e
.http_code
, str(e
)))
563 bottle
.abort(e
.http_code
, str(e
))
564 except Exception as e
:
565 logger
.error("Unexpected exception: ", exc_info
=True)
566 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
568 @bottle.route(url_base
+ '/<tenant_id>/sdn_controllers/<controller_id>', method
='PUT')
569 def http_put_sdn_controller_update(tenant_id
, controller_id
):
570 '''Update sdn controller'''
572 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
573 http_content
,_
= format_in( sdn_controller_edit_schema
)
574 # r = utils.remove_extra_items(http_content, datacenter_schema)
576 # logger.debug("Remove received extra items %s", str(r))
578 #logger.debug("tenant_id: "+tenant_id)
579 logger
.debug("content: {}".format(http_content
['sdn_controller']))
581 data
= nfvo
.sdn_controller_update(mydb
, tenant_id
, controller_id
, http_content
['sdn_controller'])
582 return format_out({"sdn_controller": nfvo
.sdn_controller_list(mydb
, tenant_id
, controller_id
)})
584 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
585 logger
.error("http_post_sdn_controller error {}: {}".format(e
.http_code
, str(e
)))
586 bottle
.abort(e
.http_code
, str(e
))
587 except Exception as e
:
588 logger
.error("Unexpected exception: ", exc_info
=True)
589 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
591 @bottle.route(url_base
+ '/<tenant_id>/sdn_controllers', method
='GET')
592 def http_get_sdn_controller(tenant_id
):
593 '''get sdn controllers list, can use both uuid or name'''
595 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
597 data
= {'sdn_controllers': nfvo
.sdn_controller_list(mydb
, tenant_id
)}
598 return format_out(data
)
599 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
600 logger
.error("http_get_sdn_controller error {}: {}".format(e
.http_code
, str(e
)))
601 bottle
.abort(e
.http_code
, str(e
))
602 except Exception as e
:
603 logger
.error("Unexpected exception: ", exc_info
=True)
604 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
606 @bottle.route(url_base
+ '/<tenant_id>/sdn_controllers/<controller_id>', method
='GET')
607 def http_get_sdn_controller_id(tenant_id
, controller_id
):
608 '''get sdn controller details, can use both uuid or name'''
610 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
611 data
= nfvo
.sdn_controller_list(mydb
, tenant_id
, controller_id
)
612 return format_out({"sdn_controllers": data
})
613 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
614 logger
.error("http_get_sdn_controller_id error {}: {}".format(e
.http_code
, str(e
)))
615 bottle
.abort(e
.http_code
, str(e
))
616 except Exception as e
:
617 logger
.error("Unexpected exception: ", exc_info
=True)
618 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
620 @bottle.route(url_base
+ '/<tenant_id>/sdn_controllers/<controller_id>', method
='DELETE')
621 def http_delete_sdn_controller_id(tenant_id
, controller_id
):
622 '''delete sdn controller, can use both uuid or name'''
624 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
625 data
= nfvo
.sdn_controller_delete(mydb
, tenant_id
, controller_id
)
626 return format_out(data
)
627 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
628 logger
.error("http_delete_sdn_controller_id error {}: {}".format(e
.http_code
, str(e
)))
629 bottle
.abort(e
.http_code
, str(e
))
630 except Exception as e
:
631 logger
.error("Unexpected exception: ", exc_info
=True)
632 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
634 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method
='POST')
635 def http_post_datacenter_sdn_port_mapping(tenant_id
, datacenter_id
):
636 '''Set the sdn port mapping for a datacenter. '''
638 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
639 http_content
, _
= format_in(sdn_port_mapping_schema
)
640 # r = utils.remove_extra_items(http_content, datacenter_schema)
642 # logger.debug("Remove received extra items %s", str(r))
644 data
= nfvo
.datacenter_sdn_port_mapping_set(mydb
, tenant_id
, datacenter_id
, http_content
['sdn_port_mapping'])
645 return format_out({"sdn_port_mapping": data
})
646 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
647 logger
.error("http_post_datacenter_sdn_port_mapping 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(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
653 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method
='GET')
654 def http_get_datacenter_sdn_port_mapping(tenant_id
, datacenter_id
):
655 '''get datacenter sdn mapping details, can use both uuid or name'''
657 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
659 data
= nfvo
.datacenter_sdn_port_mapping_list(mydb
, tenant_id
, datacenter_id
)
660 return format_out({"sdn_port_mapping": data
})
661 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
662 logger
.error("http_get_datacenter_sdn_port_mapping error {}: {}".format(e
.http_code
, str(e
)))
663 bottle
.abort(e
.http_code
, str(e
))
664 except Exception as e
:
665 logger
.error("Unexpected exception: ", exc_info
=True)
666 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
668 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method
='DELETE')
669 def http_delete_datacenter_sdn_port_mapping(tenant_id
, datacenter_id
):
670 '''clean datacenter sdn mapping, can use both uuid or name'''
672 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
673 data
= nfvo
.datacenter_sdn_port_mapping_delete(mydb
, tenant_id
, datacenter_id
)
674 return format_out({"result": data
})
675 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
676 logger
.error("http_delete_datacenter_sdn_port_mapping error {}: {}".format(e
.http_code
, str(e
)))
677 bottle
.abort(e
.http_code
, str(e
))
678 except Exception as e
:
679 logger
.error("Unexpected exception: ", exc_info
=True)
680 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
682 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/networks', method
='GET') #deprecated
683 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method
='GET')
684 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method
='GET')
685 def http_getnetmap_datacenter_id(tenant_id
, datacenter_id
, netmap_id
=None):
686 '''get datacenter networks, can use both uuid or name'''
687 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
690 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id
, "datacenter")
691 where_
= {"datacenter_id":datacenter_dict
['uuid']}
693 if utils
.check_valid_uuid(netmap_id
):
694 where_
["uuid"] = netmap_id
696 where_
["name"] = netmap_id
697 netmaps
=mydb
.get_rows(FROM
='datacenter_nets',
698 SELECT
=('name','vim_net_id as vim_id', 'uuid', 'type','multipoint','shared','description', 'created_at'),
700 convert_datetime2str(netmaps
)
701 utils
.convert_str2boolean(netmaps
, ('shared', 'multipoint') )
702 if netmap_id
and len(netmaps
)==1:
703 data
={'netmap' : netmaps
[0]}
704 elif netmap_id
and len(netmaps
)==0:
705 bottle
.abort(HTTP_Not_Found
, "No netmap found with " + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), where_
.iteritems())) )
708 data
={'netmaps' : netmaps
}
709 return format_out(data
)
710 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
711 logger
.error("http_getnetwork_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
712 bottle
.abort(e
.http_code
, str(e
))
713 except Exception as e
:
714 logger
.error("Unexpected exception: ", exc_info
=True)
715 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
718 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method
='DELETE')
719 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method
='DELETE')
720 def http_delnetmap_datacenter_id(tenant_id
, datacenter_id
, netmap_id
=None):
721 '''get datacenter networks, can use both uuid or name'''
722 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
725 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id
, "datacenter")
726 where_
= {"datacenter_id":datacenter_dict
['uuid']}
728 if utils
.check_valid_uuid(netmap_id
):
729 where_
["uuid"] = netmap_id
731 where_
["name"] = netmap_id
732 #change_keys_http2db(content, http2db_tenant, reverse=True)
733 deleted
= mydb
.delete_row(FROM
='datacenter_nets', WHERE
= where_
)
734 if deleted
== 0 and netmap_id
:
735 bottle
.abort(HTTP_Not_Found
, "No netmap found with " + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), where_
.iteritems())) )
737 return format_out({"result": "netmap %s deleted" % netmap_id
})
739 return format_out({"result": "%d netmap deleted" % deleted
})
740 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
741 logger
.error("http_delnetmap_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
742 bottle
.abort(e
.http_code
, str(e
))
743 except Exception as e
:
744 logger
.error("Unexpected exception: ", exc_info
=True)
745 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
748 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps/upload', method
='POST')
749 def http_uploadnetmap_datacenter_id(tenant_id
, datacenter_id
):
750 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
752 netmaps
= nfvo
.datacenter_new_netmap(mydb
, tenant_id
, datacenter_id
, None)
753 convert_datetime2str(netmaps
)
754 utils
.convert_str2boolean(netmaps
, ('shared', 'multipoint') )
755 data
={'netmaps' : netmaps
}
756 return format_out(data
)
757 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
758 logger
.error("http_uploadnetmap_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
759 bottle
.abort(e
.http_code
, str(e
))
760 except Exception as e
:
761 logger
.error("Unexpected exception: ", exc_info
=True)
762 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
765 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method
='POST')
766 def http_postnetmap_datacenter_id(tenant_id
, datacenter_id
):
767 '''creates a new netmap'''
768 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
770 http_content
,_
= format_in( netmap_new_schema
)
771 r
= utils
.remove_extra_items(http_content
, netmap_new_schema
)
773 logger
.debug("Remove received extra items %s", str(r
))
775 #obtain data, check that only one exist
776 netmaps
= nfvo
.datacenter_new_netmap(mydb
, tenant_id
, datacenter_id
, http_content
)
777 convert_datetime2str(netmaps
)
778 utils
.convert_str2boolean(netmaps
, ('shared', 'multipoint') )
779 data
={'netmaps' : netmaps
}
780 return format_out(data
)
781 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
782 logger
.error("http_postnetmap_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
783 bottle
.abort(e
.http_code
, str(e
))
784 except Exception as e
:
785 logger
.error("Unexpected exception: ", exc_info
=True)
786 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
789 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method
='PUT')
790 def http_putnettmap_datacenter_id(tenant_id
, datacenter_id
, netmap_id
):
792 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
794 http_content
,_
= format_in( netmap_edit_schema
)
795 r
= utils
.remove_extra_items(http_content
, netmap_edit_schema
)
797 logger
.debug("Remove received extra items %s", str(r
))
799 #obtain data, check that only one exist
801 nfvo
.datacenter_edit_netmap(mydb
, tenant_id
, datacenter_id
, netmap_id
, http_content
)
802 return http_getnetmap_datacenter_id(tenant_id
, datacenter_id
, netmap_id
)
803 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
804 logger
.error("http_putnettmap_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
805 bottle
.abort(e
.http_code
, str(e
))
806 except Exception as e
:
807 logger
.error("Unexpected exception: ", exc_info
=True)
808 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
811 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/action', method
='POST')
812 def http_action_datacenter_id(tenant_id
, datacenter_id
):
813 '''perform an action over datacenter, can use both uuid or name'''
814 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
816 http_content
,_
= format_in( datacenter_action_schema
)
817 r
= utils
.remove_extra_items(http_content
, datacenter_action_schema
)
819 logger
.debug("Remove received extra items %s", str(r
))
821 #obtain data, check that only one exist
822 result
= nfvo
.datacenter_action(mydb
, tenant_id
, datacenter_id
, http_content
)
823 if 'net-update' in http_content
:
824 return http_getnetmap_datacenter_id(datacenter_id
)
826 return format_out(result
)
827 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
828 logger
.error("http_action_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
829 bottle
.abort(e
.http_code
, str(e
))
830 except Exception as e
:
831 logger
.error("Unexpected exception: ", exc_info
=True)
832 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
835 @bottle.route(url_base
+ '/datacenters/<datacenter_id>', method
='DELETE')
836 def http_delete_datacenter_id( datacenter_id
):
837 '''delete a tenant from database, can use both uuid or name'''
839 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
841 data
= nfvo
.delete_datacenter(mydb
, datacenter_id
)
842 return format_out({"result":"datacenter '" + data
+ "' deleted"})
843 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
844 logger
.error("http_delete_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
845 bottle
.abort(e
.http_code
, str(e
))
846 except Exception as e
:
847 logger
.error("Unexpected exception: ", exc_info
=True)
848 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
851 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>', method
='POST')
852 def http_associate_datacenters(tenant_id
, datacenter_id
):
853 '''associate an existing datacenter to a this tenant. '''
854 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
856 http_content
,_
= format_in( datacenter_associate_schema
)
857 r
= utils
.remove_extra_items(http_content
, datacenter_associate_schema
)
859 logger
.debug("Remove received extra items %s", str(r
))
861 id_
= nfvo
.associate_datacenter_to_tenant(mydb
, tenant_id
, datacenter_id
,
862 http_content
['datacenter'].get('vim_tenant'),
863 http_content
['datacenter'].get('vim_tenant_name'),
864 http_content
['datacenter'].get('vim_username'),
865 http_content
['datacenter'].get('vim_password'),
866 http_content
['datacenter'].get('config')
868 return http_get_datacenter_id(tenant_id
, id_
)
869 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
870 logger
.error("http_associate_datacenters error {}: {}".format(e
.http_code
, str(e
)))
871 bottle
.abort(e
.http_code
, str(e
))
872 except Exception as e
:
873 logger
.error("Unexpected exception: ", exc_info
=True)
874 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
876 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>', method
='PUT')
877 def http_associate_datacenters_edit(tenant_id
, datacenter_id
):
878 '''associate an existing datacenter to a this tenant. '''
879 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
881 http_content
,_
= format_in( datacenter_associate_schema
)
882 r
= utils
.remove_extra_items(http_content
, datacenter_associate_schema
)
884 logger
.debug("Remove received extra items %s", str(r
))
886 id_
= nfvo
.edit_datacenter_to_tenant(mydb
, tenant_id
, datacenter_id
,
887 http_content
['datacenter'].get('vim_tenant'),
888 http_content
['datacenter'].get('vim_tenant_name'),
889 http_content
['datacenter'].get('vim_username'),
890 http_content
['datacenter'].get('vim_password'),
891 http_content
['datacenter'].get('config')
893 return http_get_datacenter_id(tenant_id
, id_
)
894 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
895 logger
.error("http_associate_datacenters_edit error {}: {}".format(e
.http_code
, str(e
)))
896 bottle
.abort(e
.http_code
, str(e
))
897 except Exception as e
:
898 logger
.error("Unexpected exception: ", exc_info
=True)
899 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
901 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>', method
='DELETE')
902 def http_deassociate_datacenters(tenant_id
, datacenter_id
):
903 '''deassociate an existing datacenter to a this tenant. '''
904 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
906 data
= nfvo
.deassociate_datacenter_to_tenant(mydb
, tenant_id
, datacenter_id
)
907 return format_out({"result": data
})
908 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
909 logger
.error("http_deassociate_datacenters error {}: {}".format(e
.http_code
, str(e
)))
910 bottle
.abort(e
.http_code
, str(e
))
911 except Exception as e
:
912 logger
.error("Unexpected exception: ", exc_info
=True)
913 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
916 @bottle.route(url_base
+ '/<tenant_id>/vim/<datacenter_id>/<item>', method
='GET')
917 @bottle.route(url_base
+ '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method
='GET')
918 def http_get_vim_items(tenant_id
, datacenter_id
, item
, name
=None):
919 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
921 data
= nfvo
.vim_action_get(mydb
, tenant_id
, datacenter_id
, item
, name
)
922 return format_out(data
)
923 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
924 logger
.error("http_get_vim_items error {}: {}".format(e
.http_code
, str(e
)))
925 bottle
.abort(e
.http_code
, str(e
))
926 except Exception as e
:
927 logger
.error("Unexpected exception: ", exc_info
=True)
928 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
931 @bottle.route(url_base
+ '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method
='DELETE')
932 def http_del_vim_items(tenant_id
, datacenter_id
, item
, name
):
933 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
935 data
= nfvo
.vim_action_delete(mydb
, tenant_id
, datacenter_id
, item
, name
)
936 return format_out({"result":data
})
937 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
938 logger
.error("http_del_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(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
945 @bottle.route(url_base
+ '/<tenant_id>/vim/<datacenter_id>/<item>', method
='POST')
946 def http_post_vim_items(tenant_id
, datacenter_id
, item
):
947 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
948 http_content
,_
= format_in( object_schema
)
950 data
= nfvo
.vim_action_create(mydb
, tenant_id
, datacenter_id
, item
, http_content
)
951 return format_out(data
)
952 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
953 logger
.error("http_post_vim_items error {}: {}".format(e
.http_code
, str(e
)))
954 bottle
.abort(e
.http_code
, str(e
))
955 except Exception as e
:
956 logger
.error("Unexpected exception: ", exc_info
=True)
957 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
960 @bottle.route(url_base
+ '/<tenant_id>/vnfs', method
='GET')
961 def http_get_vnfs(tenant_id
):
962 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
964 if tenant_id
!= 'any':
965 #check valid tenant_id
966 nfvo
.check_tenant(mydb
, tenant_id
)
967 select_
,where_
,limit_
= filter_query_string(bottle
.request
.query
, None,
968 ('uuid','name','description','public', "tenant_id", "created_at") )
970 if tenant_id
!= "any":
971 where_or
["tenant_id"] = tenant_id
972 where_or
["public"] = True
973 vnfs
= mydb
.get_rows(FROM
='vnfs', SELECT
=select_
,WHERE
=where_
,WHERE_OR
=where_or
, WHERE_AND_OR
="AND",LIMIT
=limit_
)
974 #change_keys_http2db(content, http2db_vnf, reverse=True)
975 utils
.convert_str2boolean(vnfs
, ('public',))
976 convert_datetime2str(vnfs
)
978 return format_out(data
)
979 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
980 logger
.error("http_get_vnfs error {}: {}".format(e
.http_code
, str(e
)))
981 bottle
.abort(e
.http_code
, str(e
))
982 except Exception as e
:
983 logger
.error("Unexpected exception: ", exc_info
=True)
984 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
987 @bottle.route(url_base
+ '/<tenant_id>/vnfs/<vnf_id>', method
='GET')
988 def http_get_vnf_id(tenant_id
,vnf_id
):
989 '''get vnf details, can use both uuid or name'''
990 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
992 vnf
= nfvo
.get_vnf_id(mydb
,tenant_id
,vnf_id
)
993 utils
.convert_str2boolean(vnf
, ('public',))
994 convert_datetime2str(vnf
)
995 return format_out(vnf
)
996 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
997 logger
.error("http_get_vnf_id error {}: {}".format(e
.http_code
, str(e
)))
998 bottle
.abort(e
.http_code
, str(e
))
999 except Exception as e
:
1000 logger
.error("Unexpected exception: ", exc_info
=True)
1001 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1004 @bottle.route(url_base
+ '/<tenant_id>/vnfs', method
='POST')
1005 def http_post_vnfs(tenant_id
):
1006 '''insert a vnf into the catalogue. Creates the flavor and images in the VIM, and creates the VNF and its internal structure in the OPENMANO DB'''
1007 #print "Parsing the YAML file of the VNF"
1009 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1010 http_content
, used_schema
= format_in( vnfd_schema_v01
, ("schema_version",), {"0.2": vnfd_schema_v02
})
1011 r
= utils
.remove_extra_items(http_content
, used_schema
)
1013 logger
.debug("Remove received extra items %s", str(r
))
1015 if used_schema
== vnfd_schema_v01
:
1016 vnf_id
= nfvo
.new_vnf(mydb
,tenant_id
,http_content
)
1017 elif used_schema
== vnfd_schema_v02
:
1018 vnf_id
= nfvo
.new_vnf_v02(mydb
,tenant_id
,http_content
)
1020 logger
.warning('Unexpected schema_version: %s', http_content
.get("schema_version"))
1021 bottle
.abort(HTTP_Bad_Request
, "Invalid schema version")
1022 return http_get_vnf_id(tenant_id
, vnf_id
)
1023 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1024 logger
.error("http_post_vnfs error {}: {}".format(e
.http_code
, str(e
)))
1025 bottle
.abort(e
.http_code
, str(e
))
1026 except Exception as e
:
1027 logger
.error("Unexpected exception: ", exc_info
=True)
1028 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1031 @bottle.route(url_base
+ '/<tenant_id>/vnfs/<vnf_id>', method
='DELETE')
1032 def http_delete_vnf_id(tenant_id
,vnf_id
):
1033 '''delete a vnf from database, and images and flavors in VIM when appropriate, can use both uuid or name'''
1034 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1035 #check valid tenant_id and deletes the vnf, including images,
1037 data
= nfvo
.delete_vnf(mydb
,tenant_id
,vnf_id
)
1038 #print json.dumps(data, indent=4)
1039 return format_out({"result":"VNF " + data
+ " deleted"})
1040 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1041 logger
.error("http_delete_vnf_id error {}: {}".format(e
.http_code
, str(e
)))
1042 bottle
.abort(e
.http_code
, str(e
))
1043 except Exception as e
:
1044 logger
.error("Unexpected exception: ", exc_info
=True)
1045 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1048 #@bottle.route(url_base + '/<tenant_id>/hosts/topology', method='GET')
1049 #@bottle.route(url_base + '/<tenant_id>/physicalview/Madrid-Alcantara', method='GET')
1050 @bottle.route(url_base
+ '/<tenant_id>/physicalview/<datacenter>', method
='GET')
1051 def http_get_hosts(tenant_id
, datacenter
):
1052 '''get the tidvim host hopology from the vim.'''
1053 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1054 #print "http_get_hosts received by tenant " + tenant_id + ' datacenter ' + datacenter
1056 if datacenter
== 'treeview':
1057 data
= nfvo
.get_hosts(mydb
, tenant_id
)
1059 #openmano-gui is using a hardcoded value for the datacenter
1060 result
, data
= nfvo
.get_hosts_info(mydb
, tenant_id
) #, datacenter)
1063 #print "http_get_hosts error %d %s" % (-result, data)
1064 bottle
.abort(-result
, data
)
1066 convert_datetime2str(data
)
1067 #print json.dumps(data, indent=4)
1068 return format_out(data
)
1069 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1070 logger
.error("http_get_hosts error {}: {}".format(e
.http_code
, str(e
)))
1071 bottle
.abort(e
.http_code
, str(e
))
1072 except Exception as e
:
1073 logger
.error("Unexpected exception: ", exc_info
=True)
1074 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1077 @bottle.route(url_base
+ '/<path:path>', method
='OPTIONS')
1078 def http_options_deploy(path
):
1079 '''For some reason GUI web ask for OPTIONS that must be responded'''
1080 #TODO: check correct path, and correct headers request
1081 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1082 bottle
.response
.set_header('Access-Control-Allow-Methods','POST, GET, PUT, DELETE, OPTIONS')
1083 bottle
.response
.set_header('Accept','application/yaml,application/json')
1084 bottle
.response
.set_header('Content-Type','application/yaml,application/json')
1085 bottle
.response
.set_header('Access-Control-Allow-Headers','content-type')
1086 bottle
.response
.set_header('Access-Control-Allow-Origin','*')
1089 @bottle.route(url_base
+ '/<tenant_id>/topology/deploy', method
='POST')
1090 def http_post_deploy(tenant_id
):
1091 '''post topology deploy.'''
1092 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1094 http_content
, used_schema
= format_in( nsd_schema_v01
, ("schema_version",), {2: nsd_schema_v02
})
1095 #r = utils.remove_extra_items(http_content, used_schema)
1096 #if r is not None: print "http_post_deploy: Warning: remove extra items ", r
1097 #print "http_post_deploy input: ", http_content
1100 scenario_id
= nfvo
.new_scenario(mydb
, tenant_id
, http_content
)
1101 instance
= nfvo
.start_scenario(mydb
, tenant_id
, scenario_id
, http_content
['name'], http_content
['name'])
1102 #print json.dumps(data, indent=4)
1103 return format_out(instance
)
1104 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1105 logger
.error("http_post_deploy error {}: {}".format(e
.http_code
, str(e
)))
1106 bottle
.abort(e
.http_code
, str(e
))
1107 except Exception as e
:
1108 logger
.error("Unexpected exception: ", exc_info
=True)
1109 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1112 @bottle.route(url_base
+ '/<tenant_id>/topology/verify', method
='POST')
1113 def http_post_verify(tenant_id
):
1115 # '''post topology verify'''
1116 # print "http_post_verify by tenant " + tenant_id + ' datacenter ' + datacenter
1117 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1124 @bottle.route(url_base
+ '/<tenant_id>/scenarios', method
='POST')
1125 def http_post_scenarios(tenant_id
):
1126 '''add a scenario into the catalogue. Creates the scenario and its internal structure in the OPENMANO DB'''
1127 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1128 http_content
, used_schema
= format_in( nsd_schema_v01
, ("schema_version",), {2: nsd_schema_v02
, "0.3": nsd_schema_v03
})
1129 #r = utils.remove_extra_items(http_content, used_schema)
1130 #if r is not None: print "http_post_scenarios: Warning: remove extra items ", r
1131 #print "http_post_scenarios input: ", http_content
1133 if used_schema
== nsd_schema_v01
:
1134 scenario_id
= nfvo
.new_scenario(mydb
, tenant_id
, http_content
)
1135 elif used_schema
== nsd_schema_v02
:
1136 scenario_id
= nfvo
.new_scenario_v02(mydb
, tenant_id
, http_content
, "0.2")
1137 elif used_schema
== nsd_schema_v03
:
1138 scenario_id
= nfvo
.new_scenario_v02(mydb
, tenant_id
, http_content
, "0.3")
1140 logger
.warning('Unexpected schema_version: %s', http_content
.get("schema_version"))
1141 bottle
.abort(HTTP_Bad_Request
, "Invalid schema version")
1142 #print json.dumps(data, indent=4)
1143 #return format_out(data)
1144 return http_get_scenario_id(tenant_id
, scenario_id
)
1145 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1146 logger
.error("http_post_scenarios error {}: {}".format(e
.http_code
, str(e
)))
1147 bottle
.abort(e
.http_code
, str(e
))
1148 except Exception as e
:
1149 logger
.error("Unexpected exception: ", exc_info
=True)
1150 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1153 @bottle.route(url_base
+ '/<tenant_id>/scenarios/<scenario_id>/action', method
='POST')
1154 def http_post_scenario_action(tenant_id
, scenario_id
):
1155 '''take an action over a scenario'''
1156 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1158 http_content
, _
= format_in(scenario_action_schema
)
1159 r
= utils
.remove_extra_items(http_content
, scenario_action_schema
)
1161 logger
.debug("Remove received extra items %s", str(r
))
1163 # check valid tenant_id
1164 nfvo
.check_tenant(mydb
, tenant_id
)
1165 if "start" in http_content
:
1166 data
= nfvo
.start_scenario(mydb
, tenant_id
, scenario_id
, http_content
['start']['instance_name'], \
1167 http_content
['start'].get('description',http_content
['start']['instance_name']),
1168 http_content
['start'].get('datacenter') )
1169 return format_out(data
)
1170 elif "deploy" in http_content
: #Equivalent to start
1171 data
= nfvo
.start_scenario(mydb
, tenant_id
, scenario_id
, http_content
['deploy']['instance_name'],
1172 http_content
['deploy'].get('description',http_content
['deploy']['instance_name']),
1173 http_content
['deploy'].get('datacenter') )
1174 return format_out(data
)
1175 elif "reserve" in http_content
: #Reserve resources
1176 data
= nfvo
.start_scenario(mydb
, tenant_id
, scenario_id
, http_content
['reserve']['instance_name'],
1177 http_content
['reserve'].get('description',http_content
['reserve']['instance_name']),
1178 http_content
['reserve'].get('datacenter'), startvms
=False )
1179 return format_out(data
)
1180 elif "verify" in http_content
: #Equivalent to start and then delete
1181 data
= nfvo
.start_scenario(mydb
, tenant_id
, scenario_id
, http_content
['verify']['instance_name'],
1182 http_content
['verify'].get('description',http_content
['verify']['instance_name']),
1183 http_content
['verify'].get('datacenter'), startvms
=False )
1184 instance_id
= data
['uuid']
1185 nfvo
.delete_instance(mydb
, tenant_id
,instance_id
)
1186 return format_out({"result":"Verify OK"})
1187 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1188 logger
.error("http_post_scenario_action error {}: {}".format(e
.http_code
, str(e
)))
1189 bottle
.abort(e
.http_code
, str(e
))
1190 except Exception as e
:
1191 logger
.error("Unexpected exception: ", exc_info
=True)
1192 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1195 @bottle.route(url_base
+ '/<tenant_id>/scenarios', method
='GET')
1196 def http_get_scenarios(tenant_id
):
1197 '''get scenarios list'''
1198 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1200 #check valid tenant_id
1201 if tenant_id
!= "any":
1202 nfvo
.check_tenant(mydb
, tenant_id
)
1204 s
,w
,l
=filter_query_string(bottle
.request
.query
, None, ('uuid', 'name', 'description', 'tenant_id', 'created_at', 'public'))
1206 if tenant_id
!= "any":
1207 where_or
["tenant_id"] = tenant_id
1208 where_or
["public"] = True
1209 scenarios
= mydb
.get_rows(SELECT
=s
, WHERE
=w
, WHERE_OR
=where_or
, WHERE_AND_OR
="AND", LIMIT
=l
, FROM
='scenarios')
1210 convert_datetime2str(scenarios
)
1211 utils
.convert_str2boolean(scenarios
, ('public',) )
1212 data
={'scenarios':scenarios
}
1213 #print json.dumps(scenarios, indent=4)
1214 return format_out(data
)
1215 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1216 logger
.error("http_get_scenarios error {}: {}".format(e
.http_code
, str(e
)))
1217 bottle
.abort(e
.http_code
, str(e
))
1218 except Exception as e
:
1219 logger
.error("Unexpected exception: ", exc_info
=True)
1220 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1223 @bottle.route(url_base
+ '/<tenant_id>/scenarios/<scenario_id>', method
='GET')
1224 def http_get_scenario_id(tenant_id
, scenario_id
):
1225 '''get scenario details, can use both uuid or name'''
1226 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1228 #check valid tenant_id
1229 if tenant_id
!= "any":
1230 nfvo
.check_tenant(mydb
, tenant_id
)
1232 scenario
= mydb
.get_scenario(scenario_id
, tenant_id
)
1233 convert_datetime2str(scenario
)
1234 data
={'scenario' : scenario
}
1235 return format_out(data
)
1236 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1237 logger
.error("http_get_scenarios error {}: {}".format(e
.http_code
, str(e
)))
1238 bottle
.abort(e
.http_code
, str(e
))
1239 except Exception as e
:
1240 logger
.error("Unexpected exception: ", exc_info
=True)
1241 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1244 @bottle.route(url_base
+ '/<tenant_id>/scenarios/<scenario_id>', method
='DELETE')
1245 def http_delete_scenario_id(tenant_id
, scenario_id
):
1246 '''delete a scenario from database, can use both uuid or name'''
1247 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1249 #check valid tenant_id
1250 if tenant_id
!= "any":
1251 nfvo
.check_tenant(mydb
, tenant_id
)
1253 data
= mydb
.delete_scenario(scenario_id
, tenant_id
)
1254 #print json.dumps(data, indent=4)
1255 return format_out({"result":"scenario " + data
+ " deleted"})
1256 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1257 logger
.error("http_delete_scenario_id error {}: {}".format(e
.http_code
, str(e
)))
1258 bottle
.abort(e
.http_code
, str(e
))
1259 except Exception as e
:
1260 logger
.error("Unexpected exception: ", exc_info
=True)
1261 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1264 @bottle.route(url_base
+ '/<tenant_id>/scenarios/<scenario_id>', method
='PUT')
1265 def http_put_scenario_id(tenant_id
, scenario_id
):
1266 '''edit an existing scenario id'''
1267 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1268 http_content
,_
= format_in( scenario_edit_schema
)
1269 #r = utils.remove_extra_items(http_content, scenario_edit_schema)
1270 #if r is not None: print "http_put_scenario_id: Warning: remove extra items ", r
1271 #print "http_put_scenario_id input: ", http_content
1273 nfvo
.edit_scenario(mydb
, tenant_id
, scenario_id
, http_content
)
1274 #print json.dumps(data, indent=4)
1275 #return format_out(data)
1276 return http_get_scenario_id(tenant_id
, scenario_id
)
1277 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1278 logger
.error("http_put_scenario_id error {}: {}".format(e
.http_code
, str(e
)))
1279 bottle
.abort(e
.http_code
, str(e
))
1280 except Exception as e
:
1281 logger
.error("Unexpected exception: ", exc_info
=True)
1282 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1284 @bottle.route(url_base
+ '/<tenant_id>/instances', method
='POST')
1285 def http_post_instances(tenant_id
):
1286 '''create an instance-scenario'''
1287 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1289 http_content
, used_schema
= format_in(instance_scenario_create_schema_v01
)
1290 r
= utils
.remove_extra_items(http_content
, used_schema
)
1292 logger
.warning("http_post_instances: Warning: remove extra items %s", str(r
))
1294 #check valid tenant_id
1295 if tenant_id
!= "any":
1296 nfvo
.check_tenant(mydb
, tenant_id
)
1297 data
= nfvo
.create_instance(mydb
, tenant_id
, http_content
["instance"])
1298 return format_out(data
)
1299 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1300 logger
.error("http_post_instances error {}: {}".format(e
.http_code
, str(e
)))
1301 bottle
.abort(e
.http_code
, str(e
))
1302 except Exception as e
:
1303 logger
.error("Unexpected exception: ", exc_info
=True)
1304 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1309 @bottle.route(url_base
+ '/<tenant_id>/instances', method
='GET')
1310 def http_get_instances(tenant_id
):
1311 '''get instance list'''
1313 #check valid tenant_id
1314 if tenant_id
!= "any":
1315 nfvo
.check_tenant(mydb
, tenant_id
)
1317 s
,w
,l
=filter_query_string(bottle
.request
.query
, None, ('uuid', 'name', 'scenario_id', 'tenant_id', 'description', 'created_at'))
1318 if tenant_id
!= "any":
1319 w
['tenant_id'] = tenant_id
1320 instances
= mydb
.get_rows(SELECT
=s
, WHERE
=w
, LIMIT
=l
, FROM
='instance_scenarios')
1321 convert_datetime2str(instances
)
1322 utils
.convert_str2boolean(instances
, ('public',) )
1323 data
={'instances':instances
}
1324 return format_out(data
)
1325 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1326 logger
.error("http_get_instances error {}: {}".format(e
.http_code
, str(e
)))
1327 bottle
.abort(e
.http_code
, str(e
))
1328 except Exception as e
:
1329 logger
.error("Unexpected exception: ", exc_info
=True)
1330 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1333 @bottle.route(url_base
+ '/<tenant_id>/instances/<instance_id>', method
='GET')
1334 def http_get_instance_id(tenant_id
, instance_id
):
1335 '''get instances details, can use both uuid or name'''
1336 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1338 #check valid tenant_id
1339 if tenant_id
!= "any":
1340 nfvo
.check_tenant(mydb
, tenant_id
)
1341 if tenant_id
== "any":
1343 #obtain data (first time is only to check that the instance exists)
1344 instance_dict
= mydb
.get_instance_scenario(instance_id
, tenant_id
, verbose
=True)
1346 nfvo
.refresh_instance(mydb
, tenant_id
, instance_dict
)
1347 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1348 logger
.warn("nfvo.refresh_instance couldn't refresh the status of the instance: %s" % str(e
))
1349 #obtain data with results upated
1350 instance
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
1351 convert_datetime2str(instance
)
1352 #print json.dumps(instance, indent=4)
1353 return format_out(instance
)
1354 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1355 logger
.error("http_get_instance_id error {}: {}".format(e
.http_code
, str(e
)))
1356 bottle
.abort(e
.http_code
, str(e
))
1357 except Exception as e
:
1358 logger
.error("Unexpected exception: ", exc_info
=True)
1359 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1362 @bottle.route(url_base
+ '/<tenant_id>/instances/<instance_id>', method
='DELETE')
1363 def http_delete_instance_id(tenant_id
, instance_id
):
1364 '''delete instance from VIM and from database, can use both uuid or name'''
1365 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1367 #check valid tenant_id
1368 if tenant_id
!= "any":
1369 nfvo
.check_tenant(mydb
, tenant_id
)
1370 if tenant_id
== "any":
1373 message
= nfvo
.delete_instance(mydb
, tenant_id
,instance_id
)
1374 return format_out({"result":message
})
1375 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1376 logger
.error("http_delete_instance_id error {}: {}".format(e
.http_code
, str(e
)))
1377 bottle
.abort(e
.http_code
, str(e
))
1378 except Exception as e
:
1379 logger
.error("Unexpected exception: ", exc_info
=True)
1380 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1383 @bottle.route(url_base
+ '/<tenant_id>/instances/<instance_id>/action', method
='POST')
1384 def http_post_instance_scenario_action(tenant_id
, instance_id
):
1385 '''take an action over a scenario instance'''
1386 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1388 http_content
, _
= format_in(instance_scenario_action_schema
)
1389 r
= utils
.remove_extra_items(http_content
, instance_scenario_action_schema
)
1391 logger
.debug("Remove received extra items %s", str(r
))
1393 #check valid tenant_id
1394 if tenant_id
!= "any":
1395 nfvo
.check_tenant(mydb
, tenant_id
)
1397 #print "http_post_instance_scenario_action input: ", http_content
1399 instance
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
1400 instance_id
= instance
["uuid"]
1402 data
= nfvo
.instance_action(mydb
, tenant_id
, instance_id
, http_content
)
1403 return format_out(data
)
1404 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1405 logger
.error("http_post_instance_scenario_action error {}: {}".format(e
.http_code
, str(e
)))
1406 bottle
.abort(e
.http_code
, str(e
))
1407 except Exception as e
:
1408 logger
.error("Unexpected exception: ", exc_info
=True)
1409 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1421 def error400(error
):
1422 e
={"error":{"code":error
.status_code
, "type":error
.status
, "description":error
.body
}}
1423 bottle
.response
.headers
['Access-Control-Allow-Origin'] = '*'
1424 return format_out(e
)