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
, sdn_external_port_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'] = '*'
308 @bottle.route(url_base
+ '/version', method
='GET')
309 def http_get_version():
310 return nfvo
.get_version()
315 @bottle.route(url_base
+ '/tenants', method
='GET')
316 def http_get_tenants():
317 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
318 select_
,where_
,limit_
= filter_query_string(bottle
.request
.query
, None,
319 ('uuid','name','description','created_at') )
321 tenants
= mydb
.get_rows(FROM
='nfvo_tenants', SELECT
=select_
,WHERE
=where_
,LIMIT
=limit_
)
322 #change_keys_http2db(content, http2db_tenant, reverse=True)
323 convert_datetime2str(tenants
)
324 data
={'tenants' : tenants
}
325 return format_out(data
)
326 except db_base_Exception
as e
:
327 logger
.error("http_get_tenants error {}: {}".format(e
.http_code
, str(e
)))
328 bottle
.abort(e
.http_code
, str(e
))
329 except Exception as e
:
330 logger
.error("Unexpected exception: ", exc_info
=True)
331 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
334 @bottle.route(url_base
+ '/tenants/<tenant_id>', method
='GET')
335 def http_get_tenant_id(tenant_id
):
336 '''get tenant details, can use both uuid or name'''
338 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
340 tenant
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
, "tenant")
341 #change_keys_http2db(content, http2db_tenant, reverse=True)
342 convert_datetime2str(tenant
)
343 data
={'tenant' : tenant
}
344 return format_out(data
)
345 except db_base_Exception
as e
:
346 logger
.error("http_get_tenant_id error {}: {}".format(e
.http_code
, str(e
)))
347 bottle
.abort(e
.http_code
, str(e
))
348 except Exception as e
:
349 logger
.error("Unexpected exception: ", exc_info
=True)
350 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
353 @bottle.route(url_base
+ '/tenants', method
='POST')
354 def http_post_tenants():
355 '''insert a tenant into the catalogue. '''
357 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
358 http_content
,_
= format_in( tenant_schema
)
359 r
= utils
.remove_extra_items(http_content
, tenant_schema
)
361 logger
.debug("Remove received extra items %s", str(r
))
363 data
= nfvo
.new_tenant(mydb
, http_content
['tenant'])
364 return http_get_tenant_id(data
)
365 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
366 logger
.error("http_post_tenants error {}: {}".format(e
.http_code
, str(e
)))
367 bottle
.abort(e
.http_code
, str(e
))
368 except Exception as e
:
369 logger
.error("Unexpected exception: ", exc_info
=True)
370 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
373 @bottle.route(url_base
+ '/tenants/<tenant_id>', method
='PUT')
374 def http_edit_tenant_id(tenant_id
):
375 '''edit tenant details, can use both uuid or name'''
377 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
378 http_content
,_
= format_in( tenant_edit_schema
)
379 r
= utils
.remove_extra_items(http_content
, tenant_edit_schema
)
381 logger
.debug("Remove received extra items %s", str(r
))
383 #obtain data, check that only one exist
385 tenant
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
)
387 tenant_id
= tenant
['uuid']
388 where
={'uuid': tenant
['uuid']}
389 mydb
.update_rows('nfvo_tenants', http_content
['tenant'], where
)
390 return http_get_tenant_id(tenant_id
)
391 except db_base_Exception
as e
:
392 logger
.error("http_edit_tenant_id error {}: {}".format(e
.http_code
, str(e
)))
393 bottle
.abort(e
.http_code
, str(e
))
394 except Exception as e
:
395 logger
.error("Unexpected exception: ", exc_info
=True)
396 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
399 @bottle.route(url_base
+ '/tenants/<tenant_id>', method
='DELETE')
400 def http_delete_tenant_id(tenant_id
):
401 '''delete a tenant from database, can use both uuid or name'''
402 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
404 data
= nfvo
.delete_tenant(mydb
, tenant_id
)
405 return format_out({"result":"tenant " + data
+ " deleted"})
406 except db_base_Exception
as e
:
407 logger
.error("http_delete_tenant_id error {}: {}".format(e
.http_code
, str(e
)))
408 bottle
.abort(e
.http_code
, str(e
))
409 except Exception as e
:
410 logger
.error("Unexpected exception: ", exc_info
=True)
411 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
414 @bottle.route(url_base
+ '/<tenant_id>/datacenters', method
='GET')
415 def http_get_datacenters(tenant_id
):
416 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
418 if tenant_id
!= 'any':
419 #check valid tenant_id
420 nfvo
.check_tenant(mydb
, tenant_id
)
421 select_
,where_
,limit_
= filter_query_string(bottle
.request
.query
, None,
422 ('uuid','name','vim_url','type','created_at') )
423 if tenant_id
!= 'any':
424 where_
['nfvo_tenant_id'] = tenant_id
425 if 'created_at' in select_
:
426 select_
[ select_
.index('created_at') ] = 'd.created_at as created_at'
427 if 'created_at' in where_
:
428 where_
['d.created_at'] = where_
.pop('created_at')
429 datacenters
= mydb
.get_rows(FROM
='datacenters as d join tenants_datacenters as td on d.uuid=td.datacenter_id',
430 SELECT
=select_
,WHERE
=where_
,LIMIT
=limit_
)
432 datacenters
= mydb
.get_rows(FROM
='datacenters',
433 SELECT
=select_
,WHERE
=where_
,LIMIT
=limit_
)
434 #change_keys_http2db(content, http2db_tenant, reverse=True)
435 convert_datetime2str(datacenters
)
436 data
={'datacenters' : datacenters
}
437 return format_out(data
)
438 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
439 logger
.error("http_get_datacenters error {}: {}".format(e
.http_code
, str(e
)))
440 bottle
.abort(e
.http_code
, str(e
))
441 except Exception as e
:
442 logger
.error("Unexpected exception: ", exc_info
=True)
443 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
446 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>', method
='GET')
447 def http_get_datacenter_id(tenant_id
, datacenter_id
):
448 '''get datacenter details, can use both uuid or name'''
449 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
451 if tenant_id
!= 'any':
452 #check valid tenant_id
453 nfvo
.check_tenant(mydb
, tenant_id
)
455 what
= 'uuid' if utils
.check_valid_uuid(datacenter_id
) else 'name'
457 where_
[what
] = datacenter_id
458 select_
=['uuid', 'name','vim_url', 'vim_url_admin', 'type', 'd.config as config', 'description', 'd.created_at as created_at']
459 if tenant_id
!= 'any':
460 select_
.append("datacenter_tenant_id")
461 where_
['td.nfvo_tenant_id']= tenant_id
462 from_
='datacenters as d join tenants_datacenters as td on d.uuid=td.datacenter_id'
464 from_
='datacenters as d'
465 datacenters
= mydb
.get_rows(
470 if len(datacenters
)==0:
471 bottle
.abort( HTTP_Not_Found
, "No datacenter found for tenant with {} '{}'".format(what
, datacenter_id
) )
472 elif len(datacenters
)>1:
473 bottle
.abort( HTTP_Bad_Request
, "More than one datacenter found for tenant with {} '{}'".format(what
, datacenter_id
) )
474 datacenter
= datacenters
[0]
475 if tenant_id
!= 'any':
477 vim_tenants
= mydb
.get_rows(
478 SELECT
=("vim_tenant_name", "vim_tenant_id", "user", "passwd", "config"),
479 FROM
="datacenter_tenants",
480 WHERE
={"uuid": datacenters
[0]["datacenter_tenant_id"]},
481 ORDER_BY
=("created", ) )
482 del datacenter
["datacenter_tenant_id"]
483 datacenter
["vim_tenants"] = vim_tenants
484 for vim_tenant
in vim_tenants
:
485 if vim_tenant
["passwd"]:
486 vim_tenant
["passwd"] = "******"
487 if vim_tenant
['config'] != None:
489 config_dict
= yaml
.load(vim_tenant
['config'])
490 vim_tenant
['config'] = config_dict
491 except Exception as e
:
492 logger
.error("Exception '%s' while trying to load config information", str(e
))
494 if datacenter
['config'] != None:
496 config_dict
= yaml
.load(datacenter
['config'])
497 datacenter
['config'] = config_dict
498 except Exception as e
:
499 logger
.error("Exception '%s' while trying to load config information", str(e
))
500 #change_keys_http2db(content, http2db_datacenter, reverse=True)
501 convert_datetime2str(datacenter
)
502 data
={'datacenter' : datacenter
}
503 return format_out(data
)
504 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
505 logger
.error("http_get_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
506 bottle
.abort(e
.http_code
, str(e
))
507 except Exception as e
:
508 logger
.error("Unexpected exception: ", exc_info
=True)
509 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
512 @bottle.route(url_base
+ '/datacenters', method
='POST')
513 def http_post_datacenters():
514 '''insert a datacenter into the catalogue. '''
516 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
517 http_content
,_
= format_in( datacenter_schema
)
518 r
= utils
.remove_extra_items(http_content
, datacenter_schema
)
520 logger
.debug("Remove received extra items %s", str(r
))
522 data
= nfvo
.new_datacenter(mydb
, http_content
['datacenter'])
523 return http_get_datacenter_id('any', data
)
524 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
525 logger
.error("http_post_datacenters error {}: {}".format(e
.http_code
, str(e
)))
526 bottle
.abort(e
.http_code
, str(e
))
527 except Exception as e
:
528 logger
.error("Unexpected exception: ", exc_info
=True)
529 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
532 @bottle.route(url_base
+ '/datacenters/<datacenter_id_name>', method
='PUT')
533 def http_edit_datacenter_id(datacenter_id_name
):
534 '''edit datacenter details, can use both uuid or name'''
535 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
537 http_content
,_
= format_in( datacenter_edit_schema
)
538 r
= utils
.remove_extra_items(http_content
, datacenter_edit_schema
)
540 logger
.debug("Remove received extra items %s", str(r
))
543 datacenter_id
= nfvo
.edit_datacenter(mydb
, datacenter_id_name
, http_content
['datacenter'])
544 return http_get_datacenter_id('any', datacenter_id
)
545 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
546 logger
.error("http_edit_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
547 bottle
.abort(e
.http_code
, str(e
))
548 except Exception as e
:
549 logger
.error("Unexpected exception: ", exc_info
=True)
550 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
552 @bottle.route(url_base
+ '/<tenant_id>/sdn_controllers', method
='POST')
553 def http_post_sdn_controller(tenant_id
):
554 '''insert a sdn controller into the catalogue. '''
556 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
557 http_content
,_
= format_in( sdn_controller_schema
)
559 logger
.debug("tenant_id: "+tenant_id
)
560 #logger.debug("content: {}".format(http_content['sdn_controller']))
562 data
= nfvo
.sdn_controller_create(mydb
, tenant_id
, http_content
['sdn_controller'])
563 return format_out({"sdn_controller": nfvo
.sdn_controller_list(mydb
, tenant_id
, data
)})
564 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
565 logger
.error("http_post_sdn_controller error {}: {}".format(e
.http_code
, str(e
)))
566 bottle
.abort(e
.http_code
, str(e
))
567 except Exception as e
:
568 logger
.error("Unexpected exception: ", exc_info
=True)
569 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
571 @bottle.route(url_base
+ '/<tenant_id>/sdn_controllers/<controller_id>', method
='PUT')
572 def http_put_sdn_controller_update(tenant_id
, controller_id
):
573 '''Update sdn controller'''
575 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
576 http_content
,_
= format_in( sdn_controller_edit_schema
)
577 # r = utils.remove_extra_items(http_content, datacenter_schema)
579 # logger.debug("Remove received extra items %s", str(r))
581 #logger.debug("tenant_id: "+tenant_id)
582 logger
.debug("content: {}".format(http_content
['sdn_controller']))
584 data
= nfvo
.sdn_controller_update(mydb
, tenant_id
, controller_id
, http_content
['sdn_controller'])
585 return format_out({"sdn_controller": nfvo
.sdn_controller_list(mydb
, tenant_id
, controller_id
)})
587 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
588 logger
.error("http_post_sdn_controller error {}: {}".format(e
.http_code
, str(e
)))
589 bottle
.abort(e
.http_code
, str(e
))
590 except Exception as e
:
591 logger
.error("Unexpected exception: ", exc_info
=True)
592 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
594 @bottle.route(url_base
+ '/<tenant_id>/sdn_controllers', method
='GET')
595 def http_get_sdn_controller(tenant_id
):
596 '''get sdn controllers list, can use both uuid or name'''
598 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
600 data
= {'sdn_controllers': nfvo
.sdn_controller_list(mydb
, tenant_id
)}
601 return format_out(data
)
602 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
603 logger
.error("http_get_sdn_controller error {}: {}".format(e
.http_code
, str(e
)))
604 bottle
.abort(e
.http_code
, str(e
))
605 except Exception as e
:
606 logger
.error("Unexpected exception: ", exc_info
=True)
607 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
609 @bottle.route(url_base
+ '/<tenant_id>/sdn_controllers/<controller_id>', method
='GET')
610 def http_get_sdn_controller_id(tenant_id
, controller_id
):
611 '''get sdn controller details, can use both uuid or name'''
613 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
614 data
= nfvo
.sdn_controller_list(mydb
, tenant_id
, controller_id
)
615 return format_out({"sdn_controllers": data
})
616 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
617 logger
.error("http_get_sdn_controller_id error {}: {}".format(e
.http_code
, str(e
)))
618 bottle
.abort(e
.http_code
, str(e
))
619 except Exception as e
:
620 logger
.error("Unexpected exception: ", exc_info
=True)
621 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
623 @bottle.route(url_base
+ '/<tenant_id>/sdn_controllers/<controller_id>', method
='DELETE')
624 def http_delete_sdn_controller_id(tenant_id
, controller_id
):
625 '''delete sdn controller, can use both uuid or name'''
627 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
628 data
= nfvo
.sdn_controller_delete(mydb
, tenant_id
, controller_id
)
629 return format_out(data
)
630 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
631 logger
.error("http_delete_sdn_controller_id error {}: {}".format(e
.http_code
, str(e
)))
632 bottle
.abort(e
.http_code
, str(e
))
633 except Exception as e
:
634 logger
.error("Unexpected exception: ", exc_info
=True)
635 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
637 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method
='POST')
638 def http_post_datacenter_sdn_port_mapping(tenant_id
, datacenter_id
):
639 '''Set the sdn port mapping for a datacenter. '''
641 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
642 http_content
, _
= format_in(sdn_port_mapping_schema
)
643 # r = utils.remove_extra_items(http_content, datacenter_schema)
645 # logger.debug("Remove received extra items %s", str(r))
647 data
= nfvo
.datacenter_sdn_port_mapping_set(mydb
, tenant_id
, datacenter_id
, http_content
['sdn_port_mapping'])
648 return format_out({"sdn_port_mapping": data
})
649 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
650 logger
.error("http_post_datacenter_sdn_port_mapping error {}: {}".format(e
.http_code
, str(e
)))
651 bottle
.abort(e
.http_code
, str(e
))
652 except Exception as e
:
653 logger
.error("Unexpected exception: ", exc_info
=True)
654 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
656 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method
='GET')
657 def http_get_datacenter_sdn_port_mapping(tenant_id
, datacenter_id
):
658 '''get datacenter sdn mapping details, can use both uuid or name'''
660 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
662 data
= nfvo
.datacenter_sdn_port_mapping_list(mydb
, tenant_id
, datacenter_id
)
663 return format_out({"sdn_port_mapping": data
})
664 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
665 logger
.error("http_get_datacenter_sdn_port_mapping error {}: {}".format(e
.http_code
, str(e
)))
666 bottle
.abort(e
.http_code
, str(e
))
667 except Exception as e
:
668 logger
.error("Unexpected exception: ", exc_info
=True)
669 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
671 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method
='DELETE')
672 def http_delete_datacenter_sdn_port_mapping(tenant_id
, datacenter_id
):
673 '''clean datacenter sdn mapping, can use both uuid or name'''
675 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
676 data
= nfvo
.datacenter_sdn_port_mapping_delete(mydb
, tenant_id
, datacenter_id
)
677 return format_out({"result": data
})
678 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
679 logger
.error("http_delete_datacenter_sdn_port_mapping 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(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
685 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/networks', method
='GET') #deprecated
686 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method
='GET')
687 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method
='GET')
688 def http_getnetmap_datacenter_id(tenant_id
, datacenter_id
, netmap_id
=None):
689 '''get datacenter networks, can use both uuid or name'''
690 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
693 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id
, "datacenter")
694 where_
= {"datacenter_id":datacenter_dict
['uuid']}
696 if utils
.check_valid_uuid(netmap_id
):
697 where_
["uuid"] = netmap_id
699 where_
["name"] = netmap_id
700 netmaps
=mydb
.get_rows(FROM
='datacenter_nets',
701 SELECT
=('name','vim_net_id as vim_id', 'uuid', 'type','multipoint','shared','description', 'created_at'),
703 convert_datetime2str(netmaps
)
704 utils
.convert_str2boolean(netmaps
, ('shared', 'multipoint') )
705 if netmap_id
and len(netmaps
)==1:
706 data
={'netmap' : netmaps
[0]}
707 elif netmap_id
and len(netmaps
)==0:
708 bottle
.abort(HTTP_Not_Found
, "No netmap found with " + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), where_
.iteritems())) )
711 data
={'netmaps' : netmaps
}
712 return format_out(data
)
713 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
714 logger
.error("http_getnetwork_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
715 bottle
.abort(e
.http_code
, str(e
))
716 except Exception as e
:
717 logger
.error("Unexpected exception: ", exc_info
=True)
718 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
721 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method
='DELETE')
722 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method
='DELETE')
723 def http_delnetmap_datacenter_id(tenant_id
, datacenter_id
, netmap_id
=None):
724 '''get datacenter networks, can use both uuid or name'''
725 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
728 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id
, "datacenter")
729 where_
= {"datacenter_id":datacenter_dict
['uuid']}
731 if utils
.check_valid_uuid(netmap_id
):
732 where_
["uuid"] = netmap_id
734 where_
["name"] = netmap_id
735 #change_keys_http2db(content, http2db_tenant, reverse=True)
736 deleted
= mydb
.delete_row(FROM
='datacenter_nets', WHERE
= where_
)
737 if deleted
== 0 and netmap_id
:
738 bottle
.abort(HTTP_Not_Found
, "No netmap found with " + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), where_
.iteritems())) )
740 return format_out({"result": "netmap %s deleted" % netmap_id
})
742 return format_out({"result": "%d netmap deleted" % deleted
})
743 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
744 logger
.error("http_delnetmap_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
745 bottle
.abort(e
.http_code
, str(e
))
746 except Exception as e
:
747 logger
.error("Unexpected exception: ", exc_info
=True)
748 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
751 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps/upload', method
='POST')
752 def http_uploadnetmap_datacenter_id(tenant_id
, datacenter_id
):
753 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
755 netmaps
= nfvo
.datacenter_new_netmap(mydb
, tenant_id
, datacenter_id
, None)
756 convert_datetime2str(netmaps
)
757 utils
.convert_str2boolean(netmaps
, ('shared', 'multipoint') )
758 data
={'netmaps' : netmaps
}
759 return format_out(data
)
760 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
761 logger
.error("http_uploadnetmap_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
762 bottle
.abort(e
.http_code
, str(e
))
763 except Exception as e
:
764 logger
.error("Unexpected exception: ", exc_info
=True)
765 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
768 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method
='POST')
769 def http_postnetmap_datacenter_id(tenant_id
, datacenter_id
):
770 '''creates a new netmap'''
771 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
773 http_content
,_
= format_in( netmap_new_schema
)
774 r
= utils
.remove_extra_items(http_content
, netmap_new_schema
)
776 logger
.debug("Remove received extra items %s", str(r
))
778 #obtain data, check that only one exist
779 netmaps
= nfvo
.datacenter_new_netmap(mydb
, tenant_id
, datacenter_id
, http_content
)
780 convert_datetime2str(netmaps
)
781 utils
.convert_str2boolean(netmaps
, ('shared', 'multipoint') )
782 data
={'netmaps' : netmaps
}
783 return format_out(data
)
784 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
785 logger
.error("http_postnetmap_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
786 bottle
.abort(e
.http_code
, str(e
))
787 except Exception as e
:
788 logger
.error("Unexpected exception: ", exc_info
=True)
789 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
792 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method
='PUT')
793 def http_putnettmap_datacenter_id(tenant_id
, datacenter_id
, netmap_id
):
795 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
797 http_content
,_
= format_in( netmap_edit_schema
)
798 r
= utils
.remove_extra_items(http_content
, netmap_edit_schema
)
800 logger
.debug("Remove received extra items %s", str(r
))
802 #obtain data, check that only one exist
804 nfvo
.datacenter_edit_netmap(mydb
, tenant_id
, datacenter_id
, netmap_id
, http_content
)
805 return http_getnetmap_datacenter_id(tenant_id
, datacenter_id
, netmap_id
)
806 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
807 logger
.error("http_putnettmap_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
808 bottle
.abort(e
.http_code
, str(e
))
809 except Exception as e
:
810 logger
.error("Unexpected exception: ", exc_info
=True)
811 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
814 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>/action', method
='POST')
815 def http_action_datacenter_id(tenant_id
, datacenter_id
):
816 '''perform an action over datacenter, can use both uuid or name'''
817 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
819 http_content
,_
= format_in( datacenter_action_schema
)
820 r
= utils
.remove_extra_items(http_content
, datacenter_action_schema
)
822 logger
.debug("Remove received extra items %s", str(r
))
824 #obtain data, check that only one exist
825 result
= nfvo
.datacenter_action(mydb
, tenant_id
, datacenter_id
, http_content
)
826 if 'net-update' in http_content
:
827 return http_getnetmap_datacenter_id(datacenter_id
)
829 return format_out(result
)
830 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
831 logger
.error("http_action_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
832 bottle
.abort(e
.http_code
, str(e
))
833 except Exception as e
:
834 logger
.error("Unexpected exception: ", exc_info
=True)
835 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
838 @bottle.route(url_base
+ '/datacenters/<datacenter_id>', method
='DELETE')
839 def http_delete_datacenter_id( datacenter_id
):
840 '''delete a tenant from database, can use both uuid or name'''
842 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
844 data
= nfvo
.delete_datacenter(mydb
, datacenter_id
)
845 return format_out({"result":"datacenter '" + data
+ "' deleted"})
846 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
847 logger
.error("http_delete_datacenter_id error {}: {}".format(e
.http_code
, str(e
)))
848 bottle
.abort(e
.http_code
, str(e
))
849 except Exception as e
:
850 logger
.error("Unexpected exception: ", exc_info
=True)
851 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
854 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>', method
='POST')
855 def http_associate_datacenters(tenant_id
, datacenter_id
):
856 '''associate an existing datacenter to a this tenant. '''
857 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
859 http_content
,_
= format_in( datacenter_associate_schema
)
860 r
= utils
.remove_extra_items(http_content
, datacenter_associate_schema
)
862 logger
.debug("Remove received extra items %s", str(r
))
864 id_
= nfvo
.associate_datacenter_to_tenant(mydb
, tenant_id
, datacenter_id
,
865 http_content
['datacenter'].get('vim_tenant'),
866 http_content
['datacenter'].get('vim_tenant_name'),
867 http_content
['datacenter'].get('vim_username'),
868 http_content
['datacenter'].get('vim_password'),
869 http_content
['datacenter'].get('config')
871 return http_get_datacenter_id(tenant_id
, id_
)
872 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
873 logger
.error("http_associate_datacenters 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(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
879 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>', method
='PUT')
880 def http_associate_datacenters_edit(tenant_id
, datacenter_id
):
881 '''associate an existing datacenter to a this tenant. '''
882 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
884 http_content
,_
= format_in( datacenter_associate_schema
)
885 r
= utils
.remove_extra_items(http_content
, datacenter_associate_schema
)
887 logger
.debug("Remove received extra items %s", str(r
))
889 id_
= nfvo
.edit_datacenter_to_tenant(mydb
, tenant_id
, datacenter_id
,
890 http_content
['datacenter'].get('vim_tenant'),
891 http_content
['datacenter'].get('vim_tenant_name'),
892 http_content
['datacenter'].get('vim_username'),
893 http_content
['datacenter'].get('vim_password'),
894 http_content
['datacenter'].get('config')
896 return http_get_datacenter_id(tenant_id
, id_
)
897 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
898 logger
.error("http_associate_datacenters_edit error {}: {}".format(e
.http_code
, str(e
)))
899 bottle
.abort(e
.http_code
, str(e
))
900 except Exception as e
:
901 logger
.error("Unexpected exception: ", exc_info
=True)
902 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
904 @bottle.route(url_base
+ '/<tenant_id>/datacenters/<datacenter_id>', method
='DELETE')
905 def http_deassociate_datacenters(tenant_id
, datacenter_id
):
906 '''deassociate an existing datacenter to a this tenant. '''
907 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
909 data
= nfvo
.deassociate_datacenter_to_tenant(mydb
, tenant_id
, datacenter_id
)
910 return format_out({"result": data
})
911 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
912 logger
.error("http_deassociate_datacenters error {}: {}".format(e
.http_code
, str(e
)))
913 bottle
.abort(e
.http_code
, str(e
))
914 except Exception as e
:
915 logger
.error("Unexpected exception: ", exc_info
=True)
916 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
918 @bottle.route(url_base
+ '/<tenant_id>/vim/<datacenter_id>/network/<network_id>/attach', method
='POST')
919 def http_post_vim_net_sdn_attach(tenant_id
, datacenter_id
, network_id
):
920 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
921 http_content
, _
= format_in(sdn_external_port_schema
)
923 data
= nfvo
.vim_net_sdn_attach(mydb
, tenant_id
, datacenter_id
, network_id
, http_content
)
924 return format_out(data
)
925 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
926 logger
.error("http_post_vim_net_sdn_attach error {}: {}".format(e
.http_code
, str(e
)))
927 bottle
.abort(e
.http_code
, str(e
))
928 except Exception as e
:
929 logger
.error("Unexpected exception: ", exc_info
=True)
930 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
932 @bottle.route(url_base
+ '/<tenant_id>/vim/<datacenter_id>/network/<network_id>/detach', method
='DELETE')
933 @bottle.route(url_base
+ '/<tenant_id>/vim/<datacenter_id>/network/<network_id>/detach/<port_id>', method
='DELETE')
934 def http_delete_vim_net_sdn_detach(tenant_id
, datacenter_id
, network_id
, port_id
=None):
935 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
937 data
= nfvo
.vim_net_sdn_detach(mydb
, tenant_id
, datacenter_id
, network_id
, port_id
)
938 return format_out(data
)
939 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
940 logger
.error("http_delete_vim_net_sdn_detach error {}: {}".format(e
.http_code
, str(e
)))
941 bottle
.abort(e
.http_code
, str(e
))
942 except Exception as e
:
943 logger
.error("Unexpected exception: ", exc_info
=True)
944 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
946 @bottle.route(url_base
+ '/<tenant_id>/vim/<datacenter_id>/<item>', method
='GET')
947 @bottle.route(url_base
+ '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method
='GET')
948 def http_get_vim_items(tenant_id
, datacenter_id
, item
, name
=None):
949 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
951 data
= nfvo
.vim_action_get(mydb
, tenant_id
, datacenter_id
, item
, name
)
952 return format_out(data
)
953 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
954 logger
.error("http_get_vim_items error {}: {}".format(e
.http_code
, str(e
)))
955 bottle
.abort(e
.http_code
, str(e
))
956 except Exception as e
:
957 logger
.error("Unexpected exception: ", exc_info
=True)
958 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
961 @bottle.route(url_base
+ '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method
='DELETE')
962 def http_del_vim_items(tenant_id
, datacenter_id
, item
, name
):
963 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
965 data
= nfvo
.vim_action_delete(mydb
, tenant_id
, datacenter_id
, item
, name
)
966 return format_out({"result":data
})
967 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
968 logger
.error("http_del_vim_items error {}: {}".format(e
.http_code
, str(e
)))
969 bottle
.abort(e
.http_code
, str(e
))
970 except Exception as e
:
971 logger
.error("Unexpected exception: ", exc_info
=True)
972 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
975 @bottle.route(url_base
+ '/<tenant_id>/vim/<datacenter_id>/<item>', method
='POST')
976 def http_post_vim_items(tenant_id
, datacenter_id
, item
):
977 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
978 http_content
,_
= format_in( object_schema
)
980 data
= nfvo
.vim_action_create(mydb
, tenant_id
, datacenter_id
, item
, http_content
)
981 return format_out(data
)
982 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
983 logger
.error("http_post_vim_items error {}: {}".format(e
.http_code
, str(e
)))
984 bottle
.abort(e
.http_code
, str(e
))
985 except Exception as e
:
986 logger
.error("Unexpected exception: ", exc_info
=True)
987 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
990 @bottle.route(url_base
+ '/<tenant_id>/vnfs', method
='GET')
991 def http_get_vnfs(tenant_id
):
992 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
994 if tenant_id
!= 'any':
995 #check valid tenant_id
996 nfvo
.check_tenant(mydb
, tenant_id
)
997 select_
,where_
,limit_
= filter_query_string(bottle
.request
.query
, None,
998 ('uuid','name','description','public', "tenant_id", "created_at") )
1000 if tenant_id
!= "any":
1001 where_or
["tenant_id"] = tenant_id
1002 where_or
["public"] = True
1003 vnfs
= mydb
.get_rows(FROM
='vnfs', SELECT
=select_
,WHERE
=where_
,WHERE_OR
=where_or
, WHERE_AND_OR
="AND",LIMIT
=limit_
)
1004 #change_keys_http2db(content, http2db_vnf, reverse=True)
1005 utils
.convert_str2boolean(vnfs
, ('public',))
1006 convert_datetime2str(vnfs
)
1007 data
={'vnfs' : vnfs
}
1008 return format_out(data
)
1009 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1010 logger
.error("http_get_vnfs error {}: {}".format(e
.http_code
, str(e
)))
1011 bottle
.abort(e
.http_code
, str(e
))
1012 except Exception as e
:
1013 logger
.error("Unexpected exception: ", exc_info
=True)
1014 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1017 @bottle.route(url_base
+ '/<tenant_id>/vnfs/<vnf_id>', method
='GET')
1018 def http_get_vnf_id(tenant_id
,vnf_id
):
1019 '''get vnf details, can use both uuid or name'''
1020 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1022 vnf
= nfvo
.get_vnf_id(mydb
,tenant_id
,vnf_id
)
1023 utils
.convert_str2boolean(vnf
, ('public',))
1024 convert_datetime2str(vnf
)
1025 return format_out(vnf
)
1026 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1027 logger
.error("http_get_vnf_id error {}: {}".format(e
.http_code
, str(e
)))
1028 bottle
.abort(e
.http_code
, str(e
))
1029 except Exception as e
:
1030 logger
.error("Unexpected exception: ", exc_info
=True)
1031 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1034 @bottle.route(url_base
+ '/<tenant_id>/vnfs', method
='POST')
1035 def http_post_vnfs(tenant_id
):
1036 '''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'''
1037 #print "Parsing the YAML file of the VNF"
1039 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1040 http_content
, used_schema
= format_in( vnfd_schema_v01
, ("schema_version",), {"0.2": vnfd_schema_v02
})
1041 r
= utils
.remove_extra_items(http_content
, used_schema
)
1043 logger
.debug("Remove received extra items %s", str(r
))
1045 if used_schema
== vnfd_schema_v01
:
1046 vnf_id
= nfvo
.new_vnf(mydb
,tenant_id
,http_content
)
1047 elif used_schema
== vnfd_schema_v02
:
1048 vnf_id
= nfvo
.new_vnf_v02(mydb
,tenant_id
,http_content
)
1050 logger
.warning('Unexpected schema_version: %s', http_content
.get("schema_version"))
1051 bottle
.abort(HTTP_Bad_Request
, "Invalid schema version")
1052 return http_get_vnf_id(tenant_id
, vnf_id
)
1053 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1054 logger
.error("http_post_vnfs error {}: {}".format(e
.http_code
, str(e
)))
1055 bottle
.abort(e
.http_code
, str(e
))
1056 except Exception as e
:
1057 logger
.error("Unexpected exception: ", exc_info
=True)
1058 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1061 @bottle.route(url_base
+ '/<tenant_id>/vnfs/<vnf_id>', method
='DELETE')
1062 def http_delete_vnf_id(tenant_id
,vnf_id
):
1063 '''delete a vnf from database, and images and flavors in VIM when appropriate, can use both uuid or name'''
1064 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1065 #check valid tenant_id and deletes the vnf, including images,
1067 data
= nfvo
.delete_vnf(mydb
,tenant_id
,vnf_id
)
1068 #print json.dumps(data, indent=4)
1069 return format_out({"result":"VNF " + data
+ " deleted"})
1070 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1071 logger
.error("http_delete_vnf_id error {}: {}".format(e
.http_code
, str(e
)))
1072 bottle
.abort(e
.http_code
, str(e
))
1073 except Exception as e
:
1074 logger
.error("Unexpected exception: ", exc_info
=True)
1075 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1078 #@bottle.route(url_base + '/<tenant_id>/hosts/topology', method='GET')
1079 #@bottle.route(url_base + '/<tenant_id>/physicalview/Madrid-Alcantara', method='GET')
1080 @bottle.route(url_base
+ '/<tenant_id>/physicalview/<datacenter>', method
='GET')
1081 def http_get_hosts(tenant_id
, datacenter
):
1082 '''get the tidvim host hopology from the vim.'''
1083 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1084 #print "http_get_hosts received by tenant " + tenant_id + ' datacenter ' + datacenter
1086 if datacenter
== 'treeview':
1087 data
= nfvo
.get_hosts(mydb
, tenant_id
)
1089 #openmano-gui is using a hardcoded value for the datacenter
1090 result
, data
= nfvo
.get_hosts_info(mydb
, tenant_id
) #, datacenter)
1093 #print "http_get_hosts error %d %s" % (-result, data)
1094 bottle
.abort(-result
, data
)
1096 convert_datetime2str(data
)
1097 #print json.dumps(data, indent=4)
1098 return format_out(data
)
1099 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1100 logger
.error("http_get_hosts error {}: {}".format(e
.http_code
, str(e
)))
1101 bottle
.abort(e
.http_code
, str(e
))
1102 except Exception as e
:
1103 logger
.error("Unexpected exception: ", exc_info
=True)
1104 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1107 @bottle.route(url_base
+ '/<path:path>', method
='OPTIONS')
1108 def http_options_deploy(path
):
1109 '''For some reason GUI web ask for OPTIONS that must be responded'''
1110 #TODO: check correct path, and correct headers request
1111 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1112 bottle
.response
.set_header('Access-Control-Allow-Methods','POST, GET, PUT, DELETE, OPTIONS')
1113 bottle
.response
.set_header('Accept','application/yaml,application/json')
1114 bottle
.response
.set_header('Content-Type','application/yaml,application/json')
1115 bottle
.response
.set_header('Access-Control-Allow-Headers','content-type')
1116 bottle
.response
.set_header('Access-Control-Allow-Origin','*')
1119 @bottle.route(url_base
+ '/<tenant_id>/topology/deploy', method
='POST')
1120 def http_post_deploy(tenant_id
):
1121 '''post topology deploy.'''
1122 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1124 http_content
, used_schema
= format_in( nsd_schema_v01
, ("schema_version",), {2: nsd_schema_v02
})
1125 #r = utils.remove_extra_items(http_content, used_schema)
1126 #if r is not None: print "http_post_deploy: Warning: remove extra items ", r
1127 #print "http_post_deploy input: ", http_content
1130 scenario_id
= nfvo
.new_scenario(mydb
, tenant_id
, http_content
)
1131 instance
= nfvo
.start_scenario(mydb
, tenant_id
, scenario_id
, http_content
['name'], http_content
['name'])
1132 #print json.dumps(data, indent=4)
1133 return format_out(instance
)
1134 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1135 logger
.error("http_post_deploy error {}: {}".format(e
.http_code
, str(e
)))
1136 bottle
.abort(e
.http_code
, str(e
))
1137 except Exception as e
:
1138 logger
.error("Unexpected exception: ", exc_info
=True)
1139 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1142 @bottle.route(url_base
+ '/<tenant_id>/topology/verify', method
='POST')
1143 def http_post_verify(tenant_id
):
1145 # '''post topology verify'''
1146 # print "http_post_verify by tenant " + tenant_id + ' datacenter ' + datacenter
1147 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1154 @bottle.route(url_base
+ '/<tenant_id>/scenarios', method
='POST')
1155 def http_post_scenarios(tenant_id
):
1156 '''add a scenario into the catalogue. Creates the scenario and its internal structure in the OPENMANO DB'''
1157 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1158 http_content
, used_schema
= format_in( nsd_schema_v01
, ("schema_version",), {2: nsd_schema_v02
, "0.3": nsd_schema_v03
})
1159 #r = utils.remove_extra_items(http_content, used_schema)
1160 #if r is not None: print "http_post_scenarios: Warning: remove extra items ", r
1161 #print "http_post_scenarios input: ", http_content
1163 if used_schema
== nsd_schema_v01
:
1164 scenario_id
= nfvo
.new_scenario(mydb
, tenant_id
, http_content
)
1165 elif used_schema
== nsd_schema_v02
:
1166 scenario_id
= nfvo
.new_scenario_v02(mydb
, tenant_id
, http_content
, "0.2")
1167 elif used_schema
== nsd_schema_v03
:
1168 scenario_id
= nfvo
.new_scenario_v02(mydb
, tenant_id
, http_content
, "0.3")
1170 logger
.warning('Unexpected schema_version: %s', http_content
.get("schema_version"))
1171 bottle
.abort(HTTP_Bad_Request
, "Invalid schema version")
1172 #print json.dumps(data, indent=4)
1173 #return format_out(data)
1174 return http_get_scenario_id(tenant_id
, scenario_id
)
1175 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1176 logger
.error("http_post_scenarios error {}: {}".format(e
.http_code
, str(e
)))
1177 bottle
.abort(e
.http_code
, str(e
))
1178 except Exception as e
:
1179 logger
.error("Unexpected exception: ", exc_info
=True)
1180 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1183 @bottle.route(url_base
+ '/<tenant_id>/scenarios/<scenario_id>/action', method
='POST')
1184 def http_post_scenario_action(tenant_id
, scenario_id
):
1185 '''take an action over a scenario'''
1186 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1188 http_content
, _
= format_in(scenario_action_schema
)
1189 r
= utils
.remove_extra_items(http_content
, scenario_action_schema
)
1191 logger
.debug("Remove received extra items %s", str(r
))
1193 # check valid tenant_id
1194 nfvo
.check_tenant(mydb
, tenant_id
)
1195 if "start" in http_content
:
1196 data
= nfvo
.start_scenario(mydb
, tenant_id
, scenario_id
, http_content
['start']['instance_name'], \
1197 http_content
['start'].get('description',http_content
['start']['instance_name']),
1198 http_content
['start'].get('datacenter') )
1199 return format_out(data
)
1200 elif "deploy" in http_content
: #Equivalent to start
1201 data
= nfvo
.start_scenario(mydb
, tenant_id
, scenario_id
, http_content
['deploy']['instance_name'],
1202 http_content
['deploy'].get('description',http_content
['deploy']['instance_name']),
1203 http_content
['deploy'].get('datacenter') )
1204 return format_out(data
)
1205 elif "reserve" in http_content
: #Reserve resources
1206 data
= nfvo
.start_scenario(mydb
, tenant_id
, scenario_id
, http_content
['reserve']['instance_name'],
1207 http_content
['reserve'].get('description',http_content
['reserve']['instance_name']),
1208 http_content
['reserve'].get('datacenter'), startvms
=False )
1209 return format_out(data
)
1210 elif "verify" in http_content
: #Equivalent to start and then delete
1211 data
= nfvo
.start_scenario(mydb
, tenant_id
, scenario_id
, http_content
['verify']['instance_name'],
1212 http_content
['verify'].get('description',http_content
['verify']['instance_name']),
1213 http_content
['verify'].get('datacenter'), startvms
=False )
1214 instance_id
= data
['uuid']
1215 nfvo
.delete_instance(mydb
, tenant_id
,instance_id
)
1216 return format_out({"result":"Verify OK"})
1217 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1218 logger
.error("http_post_scenario_action error {}: {}".format(e
.http_code
, str(e
)))
1219 bottle
.abort(e
.http_code
, str(e
))
1220 except Exception as e
:
1221 logger
.error("Unexpected exception: ", exc_info
=True)
1222 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1225 @bottle.route(url_base
+ '/<tenant_id>/scenarios', method
='GET')
1226 def http_get_scenarios(tenant_id
):
1227 '''get scenarios list'''
1228 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1230 #check valid tenant_id
1231 if tenant_id
!= "any":
1232 nfvo
.check_tenant(mydb
, tenant_id
)
1234 s
,w
,l
=filter_query_string(bottle
.request
.query
, None, ('uuid', 'name', 'description', 'tenant_id', 'created_at', 'public'))
1236 if tenant_id
!= "any":
1237 where_or
["tenant_id"] = tenant_id
1238 where_or
["public"] = True
1239 scenarios
= mydb
.get_rows(SELECT
=s
, WHERE
=w
, WHERE_OR
=where_or
, WHERE_AND_OR
="AND", LIMIT
=l
, FROM
='scenarios')
1240 convert_datetime2str(scenarios
)
1241 utils
.convert_str2boolean(scenarios
, ('public',) )
1242 data
={'scenarios':scenarios
}
1243 #print json.dumps(scenarios, indent=4)
1244 return format_out(data
)
1245 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1246 logger
.error("http_get_scenarios error {}: {}".format(e
.http_code
, str(e
)))
1247 bottle
.abort(e
.http_code
, str(e
))
1248 except Exception as e
:
1249 logger
.error("Unexpected exception: ", exc_info
=True)
1250 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1253 @bottle.route(url_base
+ '/<tenant_id>/scenarios/<scenario_id>', method
='GET')
1254 def http_get_scenario_id(tenant_id
, scenario_id
):
1255 '''get scenario details, can use both uuid or name'''
1256 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1258 #check valid tenant_id
1259 if tenant_id
!= "any":
1260 nfvo
.check_tenant(mydb
, tenant_id
)
1262 scenario
= mydb
.get_scenario(scenario_id
, tenant_id
)
1263 convert_datetime2str(scenario
)
1264 data
={'scenario' : scenario
}
1265 return format_out(data
)
1266 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1267 logger
.error("http_get_scenarios error {}: {}".format(e
.http_code
, str(e
)))
1268 bottle
.abort(e
.http_code
, str(e
))
1269 except Exception as e
:
1270 logger
.error("Unexpected exception: ", exc_info
=True)
1271 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1274 @bottle.route(url_base
+ '/<tenant_id>/scenarios/<scenario_id>', method
='DELETE')
1275 def http_delete_scenario_id(tenant_id
, scenario_id
):
1276 '''delete a scenario from database, can use both uuid or name'''
1277 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1279 #check valid tenant_id
1280 if tenant_id
!= "any":
1281 nfvo
.check_tenant(mydb
, tenant_id
)
1283 data
= mydb
.delete_scenario(scenario_id
, tenant_id
)
1284 #print json.dumps(data, indent=4)
1285 return format_out({"result":"scenario " + data
+ " deleted"})
1286 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1287 logger
.error("http_delete_scenario_id error {}: {}".format(e
.http_code
, str(e
)))
1288 bottle
.abort(e
.http_code
, str(e
))
1289 except Exception as e
:
1290 logger
.error("Unexpected exception: ", exc_info
=True)
1291 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1294 @bottle.route(url_base
+ '/<tenant_id>/scenarios/<scenario_id>', method
='PUT')
1295 def http_put_scenario_id(tenant_id
, scenario_id
):
1296 '''edit an existing scenario id'''
1297 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1298 http_content
,_
= format_in( scenario_edit_schema
)
1299 #r = utils.remove_extra_items(http_content, scenario_edit_schema)
1300 #if r is not None: print "http_put_scenario_id: Warning: remove extra items ", r
1301 #print "http_put_scenario_id input: ", http_content
1303 nfvo
.edit_scenario(mydb
, tenant_id
, scenario_id
, http_content
)
1304 #print json.dumps(data, indent=4)
1305 #return format_out(data)
1306 return http_get_scenario_id(tenant_id
, scenario_id
)
1307 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1308 logger
.error("http_put_scenario_id error {}: {}".format(e
.http_code
, str(e
)))
1309 bottle
.abort(e
.http_code
, str(e
))
1310 except Exception as e
:
1311 logger
.error("Unexpected exception: ", exc_info
=True)
1312 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1314 @bottle.route(url_base
+ '/<tenant_id>/instances', method
='POST')
1315 def http_post_instances(tenant_id
):
1316 '''create an instance-scenario'''
1317 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1319 http_content
, used_schema
= format_in(instance_scenario_create_schema_v01
)
1320 r
= utils
.remove_extra_items(http_content
, used_schema
)
1322 logger
.warning("http_post_instances: Warning: remove extra items %s", str(r
))
1324 #check valid tenant_id
1325 if tenant_id
!= "any":
1326 nfvo
.check_tenant(mydb
, tenant_id
)
1327 data
= nfvo
.create_instance(mydb
, tenant_id
, http_content
["instance"])
1328 return format_out(data
)
1329 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1330 logger
.error("http_post_instances error {}: {}".format(e
.http_code
, str(e
)))
1331 bottle
.abort(e
.http_code
, str(e
))
1332 except Exception as e
:
1333 logger
.error("Unexpected exception: ", exc_info
=True)
1334 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1339 @bottle.route(url_base
+ '/<tenant_id>/instances', method
='GET')
1340 def http_get_instances(tenant_id
):
1341 '''get instance list'''
1343 #check valid tenant_id
1344 if tenant_id
!= "any":
1345 nfvo
.check_tenant(mydb
, tenant_id
)
1347 s
,w
,l
=filter_query_string(bottle
.request
.query
, None, ('uuid', 'name', 'scenario_id', 'tenant_id', 'description', 'created_at'))
1348 if tenant_id
!= "any":
1349 w
['tenant_id'] = tenant_id
1350 instances
= mydb
.get_rows(SELECT
=s
, WHERE
=w
, LIMIT
=l
, FROM
='instance_scenarios')
1351 convert_datetime2str(instances
)
1352 utils
.convert_str2boolean(instances
, ('public',) )
1353 data
={'instances':instances
}
1354 return format_out(data
)
1355 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1356 logger
.error("http_get_instances error {}: {}".format(e
.http_code
, str(e
)))
1357 bottle
.abort(e
.http_code
, str(e
))
1358 except Exception as e
:
1359 logger
.error("Unexpected exception: ", exc_info
=True)
1360 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1363 @bottle.route(url_base
+ '/<tenant_id>/instances/<instance_id>', method
='GET')
1364 def http_get_instance_id(tenant_id
, instance_id
):
1365 '''get instances details, can use both uuid or name'''
1366 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1368 #check valid tenant_id
1369 if tenant_id
!= "any":
1370 nfvo
.check_tenant(mydb
, tenant_id
)
1371 if tenant_id
== "any":
1373 #obtain data (first time is only to check that the instance exists)
1374 instance_dict
= mydb
.get_instance_scenario(instance_id
, tenant_id
, verbose
=True)
1376 nfvo
.refresh_instance(mydb
, tenant_id
, instance_dict
)
1377 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1378 logger
.warn("nfvo.refresh_instance couldn't refresh the status of the instance: %s" % str(e
))
1379 # obtain data with results upated
1380 instance
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
1381 # Workaround to SO, convert vnfs:vms:interfaces:ip_address from ";" separated list to report the first value
1382 for vnf
in instance
.get("vnfs", ()):
1383 for vm
in vnf
.get("vms", ()):
1384 for iface
in vm
.get("interfaces", ()):
1385 if iface
.get("ip_address"):
1386 index
= iface
["ip_address"].find(";")
1388 iface
["ip_address"] = iface
["ip_address"][:index
]
1389 convert_datetime2str(instance
)
1390 # print json.dumps(instance, indent=4)
1391 return format_out(instance
)
1392 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1393 logger
.error("http_get_instance_id 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(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1400 @bottle.route(url_base
+ '/<tenant_id>/instances/<instance_id>', method
='DELETE')
1401 def http_delete_instance_id(tenant_id
, instance_id
):
1402 '''delete instance from VIM and from database, can use both uuid or name'''
1403 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1405 #check valid tenant_id
1406 if tenant_id
!= "any":
1407 nfvo
.check_tenant(mydb
, tenant_id
)
1408 if tenant_id
== "any":
1411 message
= nfvo
.delete_instance(mydb
, tenant_id
,instance_id
)
1412 return format_out({"result":message
})
1413 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1414 logger
.error("http_delete_instance_id error {}: {}".format(e
.http_code
, str(e
)))
1415 bottle
.abort(e
.http_code
, str(e
))
1416 except Exception as e
:
1417 logger
.error("Unexpected exception: ", exc_info
=True)
1418 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1421 @bottle.route(url_base
+ '/<tenant_id>/instances/<instance_id>/action', method
='POST')
1422 def http_post_instance_scenario_action(tenant_id
, instance_id
):
1423 '''take an action over a scenario instance'''
1424 logger
.debug('FROM %s %s %s', bottle
.request
.remote_addr
, bottle
.request
.method
, bottle
.request
.url
)
1426 http_content
, _
= format_in(instance_scenario_action_schema
)
1427 r
= utils
.remove_extra_items(http_content
, instance_scenario_action_schema
)
1429 logger
.debug("Remove received extra items %s", str(r
))
1431 #check valid tenant_id
1432 if tenant_id
!= "any":
1433 nfvo
.check_tenant(mydb
, tenant_id
)
1435 #print "http_post_instance_scenario_action input: ", http_content
1437 instance
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
1438 instance_id
= instance
["uuid"]
1440 data
= nfvo
.instance_action(mydb
, tenant_id
, instance_id
, http_content
)
1441 return format_out(data
)
1442 except (nfvo
.NfvoException
, db_base_Exception
) as e
:
1443 logger
.error("http_post_instance_scenario_action error {}: {}".format(e
.http_code
, str(e
)))
1444 bottle
.abort(e
.http_code
, str(e
))
1445 except Exception as e
:
1446 logger
.error("Unexpected exception: ", exc_info
=True)
1447 bottle
.abort(HTTP_Internal_Server_Error
, type(e
).__name
__ + ": " + str(e
))
1459 def error400(error
):
1460 e
={"error":{"code":error
.status_code
, "type":error
.status
, "description":error
.body
}}
1461 bottle
.response
.headers
['Access-Control-Allow-Origin'] = '*'
1462 return format_out(e
)