blob: 374676e64e3ed5233eea95cbe6d3f01cd568d260 [file] [log] [blame]
tierno7edb6752016-03-21 17:37:52 +01001# -*- coding: utf-8 -*-
2
3##
tierno92021022018-09-12 16:29:23 +02004# Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
tierno7edb6752016-03-21 17:37:52 +01005# This file is part of openmano
6# All Rights Reserved.
7#
8# Licensed under the Apache License, Version 2.0 (the "License"); you may
9# not use this file except in compliance with the License. You may obtain
10# a copy of the License at
11#
12# http://www.apache.org/licenses/LICENSE-2.0
13#
14# Unless required by applicable law or agreed to in writing, software
15# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17# License for the specific language governing permissions and limitations
18# under the License.
19#
20# For those usages not covered by the Apache License, Version 2.0 please
21# contact with: nfvlabs@tid.es
22##
23
24'''
25HTTP server implementing the openmano API. It will answer to POST, PUT, GET methods in the appropriate URLs
26and will use the nfvo.py module to run the appropriate method.
27Every YAML/JSON file is checked against a schema in openmano_schemas.py module.
28'''
29__author__="Alfonso Tierno, Gerardo Garcia"
30__date__ ="$17-sep-2014 09:07:15$"
31
32import bottle
33import yaml
34import json
35import threading
36import time
tiernof97fd272016-07-11 14:32:37 +020037import logging
tierno7edb6752016-03-21 17:37:52 +010038
39from jsonschema import validate as js_v, exceptions as js_e
40from openmano_schemas import vnfd_schema_v01, vnfd_schema_v02, \
garciadeblas9f8456e2016-09-05 05:02:59 +020041 nsd_schema_v01, nsd_schema_v02, nsd_schema_v03, scenario_edit_schema, \
garciadeblas0c317ee2016-08-29 12:33:06 +020042 scenario_action_schema, instance_scenario_action_schema, instance_scenario_create_schema_v01, \
tierno7edb6752016-03-21 17:37:52 +010043 tenant_schema, tenant_edit_schema,\
44 datacenter_schema, datacenter_edit_schema, datacenter_action_schema, datacenter_associate_schema,\
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +010045 object_schema, netmap_new_schema, netmap_edit_schema, sdn_controller_schema, sdn_controller_edit_schema, \
Pablo Montes Moreno6aa0b2b2017-05-23 18:33:12 +020046 sdn_port_mapping_schema, sdn_external_port_schema
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +010047
tierno7edb6752016-03-21 17:37:52 +010048import nfvo
tierno42fcc3b2016-07-06 17:20:40 +020049import utils
tiernof97fd272016-07-11 14:32:37 +020050from db_base import db_base_Exception
51from functools import wraps
tierno7edb6752016-03-21 17:37:52 +010052
53global mydb
54global url_base
tiernof97fd272016-07-11 14:32:37 +020055global logger
tierno7edb6752016-03-21 17:37:52 +010056url_base="/openmano"
tierno73ad9e42016-09-12 18:11:11 +020057logger = None
tierno7edb6752016-03-21 17:37:52 +010058
59HTTP_Bad_Request = 400
60HTTP_Unauthorized = 401
61HTTP_Not_Found = 404
62HTTP_Forbidden = 403
63HTTP_Method_Not_Allowed = 405
64HTTP_Not_Acceptable = 406
65HTTP_Service_Unavailable = 503
66HTTP_Internal_Server_Error= 500
67
68def delete_nulls(var):
69 if type(var) is dict:
70 for k in var.keys():
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:
76 for k in var:
77 if type(k) is dict: delete_nulls(k)
78 if len(var) == 0: return True
79 return False
80
81def 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
84 '''
85 if type(var) is dict:
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:
93 for v in var:
94 convert_datetime2str(v)
95
tiernof97fd272016-07-11 14:32:37 +020096def log_to_logger(fn):
97 '''
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.)
100 '''
101 @wraps(fn)
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,
107 bottle.request.url,
108 bottle.response.status))
109 return actual_response
110 return _log_to_logger
tierno7edb6752016-03-21 17:37:52 +0100111
112class httpserver(threading.Thread):
113 def __init__(self, db, admin=False, host='localhost', port=9090):
114 #global url_base
115 global mydb
tiernof97fd272016-07-11 14:32:37 +0200116 global logger
tierno7edb6752016-03-21 17:37:52 +0100117 #initialization
tierno73ad9e42016-09-12 18:11:11 +0200118 if not logger:
119 logger = logging.getLogger('openmano.http')
tierno7edb6752016-03-21 17:37:52 +0100120 threading.Thread.__init__(self)
121 self.host = host
122 self.port = port #Port where the listen service must be started
123 if admin==True:
124 self.name = "http_admin"
125 else:
126 self.name = "http"
127 #self.url_preffix = 'http://' + host + ':' + str(port) + url_base
128 mydb = db
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
132 self.daemon = True
133 self.setDaemon(True)
134
135 def run(self):
tiernof97fd272016-07-11 14:32:37 +0200136 bottle.install(log_to_logger)
137 bottle.run(host=self.host, port=self.port, debug=False, quiet=True)
tierno7edb6752016-03-21 17:37:52 +0100138
139def run_bottle(db, host_='localhost', port_=9090):
140 '''used for launching in main thread, so that it can be debugged'''
141 global mydb
142 mydb = db
143 bottle.run(host=host_, port=port_, debug=True) #quiet=True
144
145
146@bottle.route(url_base + '/', method='GET')
147def http_get():
tiernoefd80c92016-09-16 14:17:46 +0200148 #print
tierno7edb6752016-03-21 17:37:52 +0100149 return 'works' #TODO: to be completed
150
151#
152# Util functions
153#
154
155def 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
159 Attributes:
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:
165 for d in data:
166 change_keys_http2db(d, http_db, reverse)
167 elif type(data) is dict or type(data) is bottle.FormsDict:
168 if reverse:
169 for k,v in http_db.items():
170 if v in data: data[k]=data.pop(v)
171 else:
172 for k,v in http_db.items():
173 if k in data: data[v]=data.pop(k)
174
175def format_out(data):
176 '''return string of dictionary data according to requested json, yaml, xml. By default json'''
tiernoefd80c92016-09-16 14:17:46 +0200177 logger.debug("OUT: " + yaml.safe_dump(data, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True) )
tierno7edb6752016-03-21 17:37:52 +0100178 if 'application/yaml' in bottle.request.headers.get('Accept'):
179 bottle.response.content_type='application/yaml'
tierno7edb6752016-03-21 17:37:52 +0100180 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"
185
gcalvinoc62cfa52017-10-05 18:21:25 +0200186def format_in(default_schema, version_fields=None, version_dict_schema=None, confidential_data=False):
tiernof1ba57e2017-09-07 12:23:19 +0200187 """
188 Parse the content of HTTP request against a json_schema
189 :param default_schema: The schema to be parsed by default if no version field is found in the client data. In None
190 no validation is done
191 :param version_fields: If provided it contains a tuple or list with the fields to iterate across the client data to
192 obtain the version
193 :param version_dict_schema: It contains a dictionary with the version as key, and json schema to apply as value.
194 It can contain a None as key, and this is apply if the client data version does not match any key
195 :return: user_data, used_schema: if the data is successfully decoded and matches the schema.
196 Launch a bottle abort if fails
197 """
tierno7edb6752016-03-21 17:37:52 +0100198 #print "HEADERS :" + str(bottle.request.headers.items())
199 try:
200 error_text = "Invalid header format "
201 format_type = bottle.request.headers.get('Content-Type', 'application/json')
202 if 'application/json' in format_type:
203 error_text = "Invalid json format "
204 #Use the json decoder instead of bottle decoder because it informs about the location of error formats with a ValueError exception
205 client_data = json.load(bottle.request.body)
206 #client_data = bottle.request.json()
207 elif 'application/yaml' in format_type:
208 error_text = "Invalid yaml format "
209 client_data = yaml.load(bottle.request.body)
210 elif 'application/xml' in format_type:
211 bottle.abort(501, "Content-Type: application/xml not supported yet.")
212 else:
tiernoefd80c92016-09-16 14:17:46 +0200213 logger.warning('Content-Type ' + str(format_type) + ' not supported.')
tierno7edb6752016-03-21 17:37:52 +0100214 bottle.abort(HTTP_Not_Acceptable, 'Content-Type ' + str(format_type) + ' not supported.')
215 return
tiernof1ba57e2017-09-07 12:23:19 +0200216 # if client_data == None:
tierno7edb6752016-03-21 17:37:52 +0100217 # bottle.abort(HTTP_Bad_Request, "Content error, empty")
218 # return
gcalvinoc62cfa52017-10-05 18:21:25 +0200219 if confidential_data:
220 logger.debug('IN: %s', remove_clear_passwd (yaml.safe_dump(client_data, explicit_start=True, indent=4, default_flow_style=False,
221 tags=False, encoding='utf-8', allow_unicode=True)))
222 else:
223 logger.debug('IN: %s', yaml.safe_dump(client_data, explicit_start=True, indent=4, default_flow_style=False,
tiernof1ba57e2017-09-07 12:23:19 +0200224 tags=False, encoding='utf-8', allow_unicode=True) )
225 # look for the client provider version
tierno7edb6752016-03-21 17:37:52 +0100226 error_text = "Invalid content "
tiernof1ba57e2017-09-07 12:23:19 +0200227 if not default_schema and not version_fields:
228 return client_data, None
tierno7edb6752016-03-21 17:37:52 +0100229 client_version = None
230 used_schema = None
231 if version_fields != None:
232 client_version = client_data
233 for field in version_fields:
234 if field in client_version:
235 client_version = client_version[field]
236 else:
237 client_version=None
238 break
tiernof1ba57e2017-09-07 12:23:19 +0200239 if client_version == None:
240 used_schema = default_schema
241 elif version_dict_schema != None:
tierno7edb6752016-03-21 17:37:52 +0100242 if client_version in version_dict_schema:
243 used_schema = version_dict_schema[client_version]
244 elif None in version_dict_schema:
245 used_schema = version_dict_schema[None]
246 if used_schema==None:
247 bottle.abort(HTTP_Bad_Request, "Invalid schema version or missing version field")
248
249 js_v(client_data, used_schema)
250 return client_data, used_schema
tiernoecc68392018-09-06 13:47:11 +0200251 except (TypeError, ValueError, yaml.YAMLError) as exc:
tierno7edb6752016-03-21 17:37:52 +0100252 error_text += str(exc)
tiernoefd80c92016-09-16 14:17:46 +0200253 logger.error(error_text)
tierno7edb6752016-03-21 17:37:52 +0100254 bottle.abort(HTTP_Bad_Request, error_text)
255 except js_e.ValidationError as exc:
tiernoefd80c92016-09-16 14:17:46 +0200256 logger.error("validate_in error, jsonschema exception at '%s' '%s' ", str(exc.path), str(exc.message))
tierno7edb6752016-03-21 17:37:52 +0100257 error_pos = ""
258 if len(exc.path)>0: error_pos=" at " + ":".join(map(json.dumps, exc.path))
259 bottle.abort(HTTP_Bad_Request, error_text + exc.message + error_pos)
260 #except:
261 # bottle.abort(HTTP_Bad_Request, "Content error: Failed to parse Content-Type", error_pos)
262 # raise
263
264def filter_query_string(qs, http2db, allowed):
265 '''Process query string (qs) checking that contains only valid tokens for avoiding SQL injection
266 Attributes:
267 'qs': bottle.FormsDict variable to be processed. None or empty is considered valid
268 'http2db': dictionary with change from http API naming (dictionary key) to database naming(dictionary value)
269 'allowed': list of allowed string tokens (API http naming). All the keys of 'qs' must be one of 'allowed'
270 Return: A tuple with the (select,where,limit) to be use in a database query. All of then transformed to the database naming
271 select: list of items to retrieve, filtered by query string 'field=token'. If no 'field' is present, allowed list is returned
272 where: dictionary with key, value, taken from the query string token=value. Empty if nothing is provided
273 limit: limit dictated by user with the query string 'limit'. 100 by default
274 abort if not permited, using bottel.abort
275 '''
276 where={}
277 limit=100
278 select=[]
tiernof97fd272016-07-11 14:32:37 +0200279 #if type(qs) is not bottle.FormsDict:
280 # bottle.abort(HTTP_Internal_Server_Error, '!!!!!!!!!!!!!!invalid query string not a dictionary')
281 # #bottle.abort(HTTP_Internal_Server_Error, "call programmer")
282 for k in qs:
283 if k=='field':
284 select += qs.getall(k)
285 for v in select:
286 if v not in allowed:
287 bottle.abort(HTTP_Bad_Request, "Invalid query string at 'field="+v+"'")
288 elif k=='limit':
289 try:
290 limit=int(qs[k])
291 except:
292 bottle.abort(HTTP_Bad_Request, "Invalid query string at 'limit="+qs[k]+"'")
293 else:
294 if k not in allowed:
295 bottle.abort(HTTP_Bad_Request, "Invalid query string at '"+k+"="+qs[k]+"'")
296 if qs[k]!="null": where[k]=qs[k]
297 else: where[k]=None
tierno7edb6752016-03-21 17:37:52 +0100298 if len(select)==0: select += allowed
299 #change from http api to database naming
300 for i in range(0,len(select)):
301 k=select[i]
302 if http2db and k in http2db:
303 select[i] = http2db[k]
304 if http2db:
305 change_keys_http2db(where, http2db)
tiernof97fd272016-07-11 14:32:37 +0200306 #print "filter_query_string", select,where,limit
tierno7edb6752016-03-21 17:37:52 +0100307
308 return select,where,limit
309
310@bottle.hook('after_request')
311def enable_cors():
312 '''Don't know yet if really needed. Keep it just in case'''
313 bottle.response.headers['Access-Control-Allow-Origin'] = '*'
314
tierno6ddeded2017-05-16 15:40:26 +0200315@bottle.route(url_base + '/version', method='GET')
316def http_get_version():
317 return nfvo.get_version()
tierno7edb6752016-03-21 17:37:52 +0100318#
319# VNFs
320#
321
322@bottle.route(url_base + '/tenants', method='GET')
323def http_get_tenants():
tiernof97fd272016-07-11 14:32:37 +0200324 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +0100325 select_,where_,limit_ = filter_query_string(bottle.request.query, None,
326 ('uuid','name','description','created_at') )
tiernof97fd272016-07-11 14:32:37 +0200327 try:
328 tenants = mydb.get_rows(FROM='nfvo_tenants', SELECT=select_,WHERE=where_,LIMIT=limit_)
tierno7edb6752016-03-21 17:37:52 +0100329 #change_keys_http2db(content, http2db_tenant, reverse=True)
tiernof97fd272016-07-11 14:32:37 +0200330 convert_datetime2str(tenants)
331 data={'tenants' : tenants}
tierno7edb6752016-03-21 17:37:52 +0100332 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +0200333 except bottle.HTTPError:
334 raise
tiernof97fd272016-07-11 14:32:37 +0200335 except db_base_Exception as e:
336 logger.error("http_get_tenants error {}: {}".format(e.http_code, str(e)))
337 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000338 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000339 logger.error("Unexpected exception: ", exc_info=True)
340 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000341
tierno7edb6752016-03-21 17:37:52 +0100342
343@bottle.route(url_base + '/tenants/<tenant_id>', method='GET')
344def http_get_tenant_id(tenant_id):
345 '''get tenant details, can use both uuid or name'''
346 #obtain data
tiernof97fd272016-07-11 14:32:37 +0200347 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
348 try:
gcalvinoc62cfa52017-10-05 18:21:25 +0200349 from_ = 'nfvo_tenants'
350 select_, where_, limit_ = filter_query_string(bottle.request.query, None,
351 ('uuid', 'name', 'description', 'created_at'))
tiernod2b560b2017-10-11 10:30:18 +0200352 what = 'uuid' if utils.check_valid_uuid(tenant_id) else 'name'
353 where_[what] = tenant_id
tierno9c22f2d2017-10-09 16:23:55 +0200354 tenants = mydb.get_rows(FROM=from_, SELECT=select_,WHERE=where_)
tiernof97fd272016-07-11 14:32:37 +0200355 #change_keys_http2db(content, http2db_tenant, reverse=True)
tiernod2b560b2017-10-11 10:30:18 +0200356 if len(tenants) == 0:
357 bottle.abort(HTTP_Not_Found, "No tenant found with {}='{}'".format(what, tenant_id))
358 elif len(tenants) > 1:
359 bottle.abort(HTTP_Bad_Request, "More than one tenant found with {}='{}'".format(what, tenant_id))
360 convert_datetime2str(tenants[0])
361 data = {'tenant': tenants[0]}
tiernof97fd272016-07-11 14:32:37 +0200362 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +0200363 except bottle.HTTPError:
364 raise
tiernof97fd272016-07-11 14:32:37 +0200365 except db_base_Exception as e:
366 logger.error("http_get_tenant_id error {}: {}".format(e.http_code, str(e)))
367 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000368 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000369 logger.error("Unexpected exception: ", exc_info=True)
370 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000371
tierno7edb6752016-03-21 17:37:52 +0100372
373@bottle.route(url_base + '/tenants', method='POST')
374def http_post_tenants():
375 '''insert a tenant into the catalogue. '''
376 #parse input data
tiernof97fd272016-07-11 14:32:37 +0200377 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +0100378 http_content,_ = format_in( tenant_schema )
tierno42fcc3b2016-07-06 17:20:40 +0200379 r = utils.remove_extra_items(http_content, tenant_schema)
tiernoefd80c92016-09-16 14:17:46 +0200380 if r:
381 logger.debug("Remove received extra items %s", str(r))
tiernof97fd272016-07-11 14:32:37 +0200382 try:
383 data = nfvo.new_tenant(mydb, http_content['tenant'])
tierno7edb6752016-03-21 17:37:52 +0100384 return http_get_tenant_id(data)
tiernod2b560b2017-10-11 10:30:18 +0200385 except bottle.HTTPError:
386 raise
tiernof97fd272016-07-11 14:32:37 +0200387 except (nfvo.NfvoException, db_base_Exception) as e:
388 logger.error("http_post_tenants error {}: {}".format(e.http_code, str(e)))
389 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000390 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000391 logger.error("Unexpected exception: ", exc_info=True)
392 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000393
tierno7edb6752016-03-21 17:37:52 +0100394
395@bottle.route(url_base + '/tenants/<tenant_id>', method='PUT')
396def http_edit_tenant_id(tenant_id):
397 '''edit tenant details, can use both uuid or name'''
398 #parse input data
tiernof97fd272016-07-11 14:32:37 +0200399 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +0100400 http_content,_ = format_in( tenant_edit_schema )
tierno42fcc3b2016-07-06 17:20:40 +0200401 r = utils.remove_extra_items(http_content, tenant_edit_schema)
tiernoefd80c92016-09-16 14:17:46 +0200402 if r:
403 logger.debug("Remove received extra items %s", str(r))
tierno7edb6752016-03-21 17:37:52 +0100404
405 #obtain data, check that only one exist
tiernof97fd272016-07-11 14:32:37 +0200406 try:
407 tenant = mydb.get_table_by_uuid_name('nfvo_tenants', tenant_id)
408 #edit data
409 tenant_id = tenant['uuid']
410 where={'uuid': tenant['uuid']}
411 mydb.update_rows('nfvo_tenants', http_content['tenant'], where)
412 return http_get_tenant_id(tenant_id)
tiernod2b560b2017-10-11 10:30:18 +0200413 except bottle.HTTPError:
414 raise
tiernof97fd272016-07-11 14:32:37 +0200415 except db_base_Exception as e:
416 logger.error("http_edit_tenant_id error {}: {}".format(e.http_code, str(e)))
417 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000418 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000419 logger.error("Unexpected exception: ", exc_info=True)
420 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000421
tierno7edb6752016-03-21 17:37:52 +0100422
423@bottle.route(url_base + '/tenants/<tenant_id>', method='DELETE')
424def http_delete_tenant_id(tenant_id):
425 '''delete a tenant from database, can use both uuid or name'''
tiernof97fd272016-07-11 14:32:37 +0200426 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
427 try:
428 data = nfvo.delete_tenant(mydb, tenant_id)
tierno7edb6752016-03-21 17:37:52 +0100429 return format_out({"result":"tenant " + data + " deleted"})
tiernod2b560b2017-10-11 10:30:18 +0200430 except bottle.HTTPError:
431 raise
tiernof97fd272016-07-11 14:32:37 +0200432 except db_base_Exception as e:
433 logger.error("http_delete_tenant_id error {}: {}".format(e.http_code, str(e)))
434 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000435 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000436 logger.error("Unexpected exception: ", exc_info=True)
437 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000438
tierno7edb6752016-03-21 17:37:52 +0100439
440@bottle.route(url_base + '/<tenant_id>/datacenters', method='GET')
441def http_get_datacenters(tenant_id):
tiernof97fd272016-07-11 14:32:37 +0200442 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
443 try:
444 if tenant_id != 'any':
445 #check valid tenant_id
446 nfvo.check_tenant(mydb, tenant_id)
447 select_,where_,limit_ = filter_query_string(bottle.request.query, None,
448 ('uuid','name','vim_url','type','created_at') )
449 if tenant_id != 'any':
450 where_['nfvo_tenant_id'] = tenant_id
451 if 'created_at' in select_:
452 select_[ select_.index('created_at') ] = 'd.created_at as created_at'
453 if 'created_at' in where_:
454 where_['d.created_at'] = where_.pop('created_at')
455 datacenters = mydb.get_rows(FROM='datacenters as d join tenants_datacenters as td on d.uuid=td.datacenter_id',
456 SELECT=select_,WHERE=where_,LIMIT=limit_)
457 else:
458 datacenters = mydb.get_rows(FROM='datacenters',
459 SELECT=select_,WHERE=where_,LIMIT=limit_)
tierno7edb6752016-03-21 17:37:52 +0100460 #change_keys_http2db(content, http2db_tenant, reverse=True)
tiernof97fd272016-07-11 14:32:37 +0200461 convert_datetime2str(datacenters)
462 data={'datacenters' : datacenters}
tierno7edb6752016-03-21 17:37:52 +0100463 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +0200464 except bottle.HTTPError:
465 raise
tiernof97fd272016-07-11 14:32:37 +0200466 except (nfvo.NfvoException, db_base_Exception) as e:
467 logger.error("http_get_datacenters error {}: {}".format(e.http_code, str(e)))
468 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000469 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000470 logger.error("Unexpected exception: ", exc_info=True)
471 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000472
tierno7edb6752016-03-21 17:37:52 +0100473
tiernod3750b32018-07-20 15:33:08 +0200474@bottle.route(url_base + '/<tenant_id>/vim_accounts', method='GET')
475@bottle.route(url_base + '/<tenant_id>/vim_accounts/<vim_account_id>', method='GET')
476def http_get_vim_account(tenant_id, vim_account_id=None):
477 '''get vim_account list/details, '''
478 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
479 try:
480 select_ = ('uuid', 'name', 'dt.datacenter_id as vim_id', 'vim_tenant_name', 'vim_tenant_id', 'user', 'config',
481 'dt.created_at as created_at', 'passwd')
482 where_ = {'nfvo_tenant_id': tenant_id}
483 if vim_account_id:
484 where_['dt.uuid'] = vim_account_id
485 from_ = 'tenants_datacenters as td join datacenter_tenants as dt on dt.uuid=td.datacenter_tenant_id'
486 vim_accounts = mydb.get_rows(SELECT=select_, FROM=from_, WHERE=where_)
487
488 if len(vim_accounts) == 0 and vim_account_id:
489 bottle.abort(HTTP_Not_Found, "No vim_account found for tenant {} and id '{}'".format(tenant_id,
490 vim_account_id))
491 for vim_account in vim_accounts:
492 if vim_account["passwd"]:
493 vim_account["passwd"] = "******"
494 if vim_account['config'] != None:
495 try:
496 config_dict = yaml.load(vim_account['config'])
497 vim_account['config'] = config_dict
498 if vim_account['config'].get('admin_password'):
499 vim_account['config']['admin_password'] = "******"
500 if vim_account['config'].get('vcenter_password'):
501 vim_account['config']['vcenter_password'] = "******"
502 if vim_account['config'].get('nsx_password'):
503 vim_account['config']['nsx_password'] = "******"
504 except Exception as e:
505 logger.error("Exception '%s' while trying to load config information", str(e))
506 # change_keys_http2db(content, http2db_datacenter, reverse=True)
507 #convert_datetime2str(vim_account)
508 if vim_account_id:
509 return format_out({"datacenter": vim_accounts[0]})
510 else:
511 return format_out({"datacenters": vim_accounts})
512 except bottle.HTTPError:
513 raise
514 except (nfvo.NfvoException, db_base_Exception) as e:
515 logger.error("http_get_datacenter_id error {}: {}".format(e.http_code, str(e)))
516 bottle.abort(e.http_code, str(e))
517 except Exception as e:
518 logger.error("Unexpected exception: ", exc_info=True)
519 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
520
521
tierno7edb6752016-03-21 17:37:52 +0100522@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='GET')
523def http_get_datacenter_id(tenant_id, datacenter_id):
524 '''get datacenter details, can use both uuid or name'''
tiernof97fd272016-07-11 14:32:37 +0200525 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
526 try:
527 if tenant_id != 'any':
528 #check valid tenant_id
529 nfvo.check_tenant(mydb, tenant_id)
530 #obtain data
531 what = 'uuid' if utils.check_valid_uuid(datacenter_id) else 'name'
532 where_={}
533 where_[what] = datacenter_id
tierno8008c3a2016-10-13 15:34:28 +0000534 select_=['uuid', 'name','vim_url', 'vim_url_admin', 'type', 'd.config as config', 'description', 'd.created_at as created_at']
tiernof97fd272016-07-11 14:32:37 +0200535 if tenant_id != 'any':
536 select_.append("datacenter_tenant_id")
537 where_['td.nfvo_tenant_id']= tenant_id
538 from_='datacenters as d join tenants_datacenters as td on d.uuid=td.datacenter_id'
539 else:
540 from_='datacenters as d'
541 datacenters = mydb.get_rows(
542 SELECT=select_,
543 FROM=from_,
544 WHERE=where_)
545
546 if len(datacenters)==0:
547 bottle.abort( HTTP_Not_Found, "No datacenter found for tenant with {} '{}'".format(what, datacenter_id) )
548 elif len(datacenters)>1:
549 bottle.abort( HTTP_Bad_Request, "More than one datacenter found for tenant with {} '{}'".format(what, datacenter_id) )
550 datacenter = datacenters[0]
551 if tenant_id != 'any':
552 #get vim tenant info
553 vim_tenants = mydb.get_rows(
tierno8008c3a2016-10-13 15:34:28 +0000554 SELECT=("vim_tenant_name", "vim_tenant_id", "user", "passwd", "config"),
tiernof97fd272016-07-11 14:32:37 +0200555 FROM="datacenter_tenants",
556 WHERE={"uuid": datacenters[0]["datacenter_tenant_id"]},
557 ORDER_BY=("created", ) )
558 del datacenter["datacenter_tenant_id"]
559 datacenter["vim_tenants"] = vim_tenants
tierno8008c3a2016-10-13 15:34:28 +0000560 for vim_tenant in vim_tenants:
561 if vim_tenant["passwd"]:
562 vim_tenant["passwd"] = "******"
563 if vim_tenant['config'] != None:
564 try:
565 config_dict = yaml.load(vim_tenant['config'])
566 vim_tenant['config'] = config_dict
gcalvinoc62cfa52017-10-05 18:21:25 +0200567 if vim_tenant['config'].get('admin_password'):
568 vim_tenant['config']['admin_password'] = "******"
569 if vim_tenant['config'].get('vcenter_password'):
570 vim_tenant['config']['vcenter_password'] = "******"
571 if vim_tenant['config'].get('nsx_password'):
572 vim_tenant['config']['nsx_password'] = "******"
venkatamahesh6ecca182017-01-27 23:04:40 +0530573 except Exception as e:
tierno8008c3a2016-10-13 15:34:28 +0000574 logger.error("Exception '%s' while trying to load config information", str(e))
575
tiernof97fd272016-07-11 14:32:37 +0200576 if datacenter['config'] != None:
577 try:
578 config_dict = yaml.load(datacenter['config'])
579 datacenter['config'] = config_dict
gcalvinoc62cfa52017-10-05 18:21:25 +0200580 if datacenter['config'].get('admin_password'):
581 datacenter['config']['admin_password'] = "******"
582 if datacenter['config'].get('vcenter_password'):
583 datacenter['config']['vcenter_password'] = "******"
584 if datacenter['config'].get('nsx_password'):
585 datacenter['config']['nsx_password'] = "******"
venkatamahesh6ecca182017-01-27 23:04:40 +0530586 except Exception as e:
tiernoefd80c92016-09-16 14:17:46 +0200587 logger.error("Exception '%s' while trying to load config information", str(e))
tiernof97fd272016-07-11 14:32:37 +0200588 #change_keys_http2db(content, http2db_datacenter, reverse=True)
589 convert_datetime2str(datacenter)
590 data={'datacenter' : datacenter}
591 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +0200592 except bottle.HTTPError:
593 raise
tiernof97fd272016-07-11 14:32:37 +0200594 except (nfvo.NfvoException, db_base_Exception) as e:
595 logger.error("http_get_datacenter_id error {}: {}".format(e.http_code, str(e)))
596 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000597 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000598 logger.error("Unexpected exception: ", exc_info=True)
599 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
600
tierno7edb6752016-03-21 17:37:52 +0100601
602@bottle.route(url_base + '/datacenters', method='POST')
603def http_post_datacenters():
garciadeblasc27b0462017-03-22 18:57:47 +0100604 '''insert a datacenter into the catalogue. '''
tierno7edb6752016-03-21 17:37:52 +0100605 #parse input data
tiernof97fd272016-07-11 14:32:37 +0200606 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
gcalvinoc62cfa52017-10-05 18:21:25 +0200607 http_content,_ = format_in(datacenter_schema, confidential_data=True)
tierno42fcc3b2016-07-06 17:20:40 +0200608 r = utils.remove_extra_items(http_content, datacenter_schema)
tiernoefd80c92016-09-16 14:17:46 +0200609 if r:
610 logger.debug("Remove received extra items %s", str(r))
tiernof97fd272016-07-11 14:32:37 +0200611 try:
612 data = nfvo.new_datacenter(mydb, http_content['datacenter'])
tierno7edb6752016-03-21 17:37:52 +0100613 return http_get_datacenter_id('any', data)
tiernod2b560b2017-10-11 10:30:18 +0200614 except bottle.HTTPError:
615 raise
tiernof97fd272016-07-11 14:32:37 +0200616 except (nfvo.NfvoException, db_base_Exception) as e:
617 logger.error("http_post_datacenters error {}: {}".format(e.http_code, str(e)))
618 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000619 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000620 logger.error("Unexpected exception: ", exc_info=True)
621 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
622
tierno7edb6752016-03-21 17:37:52 +0100623
624@bottle.route(url_base + '/datacenters/<datacenter_id_name>', method='PUT')
625def http_edit_datacenter_id(datacenter_id_name):
626 '''edit datacenter details, can use both uuid or name'''
tiernof97fd272016-07-11 14:32:37 +0200627 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +0100628 #parse input data
629 http_content,_ = format_in( datacenter_edit_schema )
tierno42fcc3b2016-07-06 17:20:40 +0200630 r = utils.remove_extra_items(http_content, datacenter_edit_schema)
tiernoefd80c92016-09-16 14:17:46 +0200631 if r:
632 logger.debug("Remove received extra items %s", str(r))
tierno7edb6752016-03-21 17:37:52 +0100633
tiernof97fd272016-07-11 14:32:37 +0200634 try:
635 datacenter_id = nfvo.edit_datacenter(mydb, datacenter_id_name, http_content['datacenter'])
tierno7edb6752016-03-21 17:37:52 +0100636 return http_get_datacenter_id('any', datacenter_id)
tiernod2b560b2017-10-11 10:30:18 +0200637 except bottle.HTTPError:
638 raise
tiernof97fd272016-07-11 14:32:37 +0200639 except (nfvo.NfvoException, db_base_Exception) as e:
640 logger.error("http_edit_datacenter_id error {}: {}".format(e.http_code, str(e)))
641 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000642 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000643 logger.error("Unexpected exception: ", exc_info=True)
644 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
645
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +0100646@bottle.route(url_base + '/<tenant_id>/sdn_controllers', method='POST')
647def http_post_sdn_controller(tenant_id):
648 '''insert a sdn controller into the catalogue. '''
649 #parse input data
650 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
651 http_content,_ = format_in( sdn_controller_schema )
652 try:
653 logger.debug("tenant_id: "+tenant_id)
654 #logger.debug("content: {}".format(http_content['sdn_controller']))
655
656 data = nfvo.sdn_controller_create(mydb, tenant_id, http_content['sdn_controller'])
657 return format_out({"sdn_controller": nfvo.sdn_controller_list(mydb, tenant_id, data)})
tiernod2b560b2017-10-11 10:30:18 +0200658 except bottle.HTTPError:
659 raise
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +0100660 except (nfvo.NfvoException, db_base_Exception) as e:
661 logger.error("http_post_sdn_controller error {}: {}".format(e.http_code, str(e)))
662 bottle.abort(e.http_code, str(e))
663 except Exception as e:
664 logger.error("Unexpected exception: ", exc_info=True)
665 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
666
667@bottle.route(url_base + '/<tenant_id>/sdn_controllers/<controller_id>', method='PUT')
668def http_put_sdn_controller_update(tenant_id, controller_id):
669 '''Update sdn controller'''
670 #parse input data
671 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
672 http_content,_ = format_in( sdn_controller_edit_schema )
673# r = utils.remove_extra_items(http_content, datacenter_schema)
674# if r:
675# logger.debug("Remove received extra items %s", str(r))
676 try:
677 #logger.debug("tenant_id: "+tenant_id)
678 logger.debug("content: {}".format(http_content['sdn_controller']))
679
680 data = nfvo.sdn_controller_update(mydb, tenant_id, controller_id, http_content['sdn_controller'])
681 return format_out({"sdn_controller": nfvo.sdn_controller_list(mydb, tenant_id, controller_id)})
682
tiernod2b560b2017-10-11 10:30:18 +0200683 except bottle.HTTPError:
684 raise
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +0100685 except (nfvo.NfvoException, db_base_Exception) as e:
686 logger.error("http_post_sdn_controller error {}: {}".format(e.http_code, str(e)))
687 bottle.abort(e.http_code, str(e))
688 except Exception as e:
689 logger.error("Unexpected exception: ", exc_info=True)
690 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
691
692@bottle.route(url_base + '/<tenant_id>/sdn_controllers', method='GET')
693def http_get_sdn_controller(tenant_id):
694 '''get sdn controllers list, can use both uuid or name'''
695 try:
696 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
697
698 data = {'sdn_controllers': nfvo.sdn_controller_list(mydb, tenant_id)}
699 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +0200700 except bottle.HTTPError:
701 raise
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +0100702 except (nfvo.NfvoException, db_base_Exception) as e:
703 logger.error("http_get_sdn_controller error {}: {}".format(e.http_code, str(e)))
704 bottle.abort(e.http_code, str(e))
705 except Exception as e:
706 logger.error("Unexpected exception: ", exc_info=True)
707 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
708
709@bottle.route(url_base + '/<tenant_id>/sdn_controllers/<controller_id>', method='GET')
710def http_get_sdn_controller_id(tenant_id, controller_id):
711 '''get sdn controller details, can use both uuid or name'''
712 try:
713 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
714 data = nfvo.sdn_controller_list(mydb, tenant_id, controller_id)
715 return format_out({"sdn_controllers": data})
tiernod2b560b2017-10-11 10:30:18 +0200716 except bottle.HTTPError:
717 raise
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +0100718 except (nfvo.NfvoException, db_base_Exception) as e:
719 logger.error("http_get_sdn_controller_id error {}: {}".format(e.http_code, str(e)))
720 bottle.abort(e.http_code, str(e))
721 except Exception as e:
722 logger.error("Unexpected exception: ", exc_info=True)
723 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
724
725@bottle.route(url_base + '/<tenant_id>/sdn_controllers/<controller_id>', method='DELETE')
726def http_delete_sdn_controller_id(tenant_id, controller_id):
727 '''delete sdn controller, can use both uuid or name'''
728 try:
729 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
730 data = nfvo.sdn_controller_delete(mydb, tenant_id, controller_id)
731 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +0200732 except bottle.HTTPError:
733 raise
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +0100734 except (nfvo.NfvoException, db_base_Exception) as e:
735 logger.error("http_delete_sdn_controller_id error {}: {}".format(e.http_code, str(e)))
736 bottle.abort(e.http_code, str(e))
737 except Exception as e:
738 logger.error("Unexpected exception: ", exc_info=True)
739 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
740
741@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method='POST')
742def http_post_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
743 '''Set the sdn port mapping for a datacenter. '''
744 #parse input data
745 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
746 http_content, _ = format_in(sdn_port_mapping_schema)
747# r = utils.remove_extra_items(http_content, datacenter_schema)
748# if r:
749# logger.debug("Remove received extra items %s", str(r))
750 try:
751 data = nfvo.datacenter_sdn_port_mapping_set(mydb, tenant_id, datacenter_id, http_content['sdn_port_mapping'])
752 return format_out({"sdn_port_mapping": data})
tiernod2b560b2017-10-11 10:30:18 +0200753 except bottle.HTTPError:
754 raise
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +0100755 except (nfvo.NfvoException, db_base_Exception) as e:
756 logger.error("http_post_datacenter_sdn_port_mapping error {}: {}".format(e.http_code, str(e)))
757 bottle.abort(e.http_code, str(e))
758 except Exception as e:
759 logger.error("Unexpected exception: ", exc_info=True)
760 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
761
762@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method='GET')
763def http_get_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
764 '''get datacenter sdn mapping details, can use both uuid or name'''
765 try:
766 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
767
768 data = nfvo.datacenter_sdn_port_mapping_list(mydb, tenant_id, datacenter_id)
769 return format_out({"sdn_port_mapping": data})
tiernod2b560b2017-10-11 10:30:18 +0200770 except bottle.HTTPError:
771 raise
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +0100772 except (nfvo.NfvoException, db_base_Exception) as e:
773 logger.error("http_get_datacenter_sdn_port_mapping error {}: {}".format(e.http_code, str(e)))
774 bottle.abort(e.http_code, str(e))
775 except Exception as e:
776 logger.error("Unexpected exception: ", exc_info=True)
777 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
778
779@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method='DELETE')
780def http_delete_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
781 '''clean datacenter sdn mapping, can use both uuid or name'''
782 try:
783 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
784 data = nfvo.datacenter_sdn_port_mapping_delete(mydb, tenant_id, datacenter_id)
785 return format_out({"result": data})
tiernod2b560b2017-10-11 10:30:18 +0200786 except bottle.HTTPError:
787 raise
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +0100788 except (nfvo.NfvoException, db_base_Exception) as e:
789 logger.error("http_delete_datacenter_sdn_port_mapping error {}: {}".format(e.http_code, str(e)))
790 bottle.abort(e.http_code, str(e))
791 except Exception as e:
792 logger.error("Unexpected exception: ", exc_info=True)
793 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno7edb6752016-03-21 17:37:52 +0100794
795@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/networks', method='GET') #deprecated
796@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='GET')
797@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method='GET')
798def http_getnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
799 '''get datacenter networks, can use both uuid or name'''
tiernof97fd272016-07-11 14:32:37 +0200800 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +0100801 #obtain data
tiernof97fd272016-07-11 14:32:37 +0200802 try:
803 datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter_id, "datacenter")
804 where_= {"datacenter_id":datacenter_dict['uuid']}
805 if netmap_id:
806 if utils.check_valid_uuid(netmap_id):
807 where_["uuid"] = netmap_id
808 else:
809 where_["name"] = netmap_id
810 netmaps =mydb.get_rows(FROM='datacenter_nets',
811 SELECT=('name','vim_net_id as vim_id', 'uuid', 'type','multipoint','shared','description', 'created_at'),
812 WHERE=where_ )
813 convert_datetime2str(netmaps)
814 utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
815 if netmap_id and len(netmaps)==1:
816 data={'netmap' : netmaps[0]}
817 elif netmap_id and len(netmaps)==0:
818 bottle.abort(HTTP_Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.iteritems())) )
819 return
tierno7edb6752016-03-21 17:37:52 +0100820 else:
tiernof97fd272016-07-11 14:32:37 +0200821 data={'netmaps' : netmaps}
822 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +0200823 except bottle.HTTPError:
824 raise
tiernof97fd272016-07-11 14:32:37 +0200825 except (nfvo.NfvoException, db_base_Exception) as e:
826 logger.error("http_getnetwork_datacenter_id error {}: {}".format(e.http_code, str(e)))
827 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000828 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000829 logger.error("Unexpected exception: ", exc_info=True)
830 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
831
tierno7edb6752016-03-21 17:37:52 +0100832
833@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='DELETE')
834@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method='DELETE')
835def http_delnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id=None):
836 '''get datacenter networks, can use both uuid or name'''
tiernof97fd272016-07-11 14:32:37 +0200837 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +0100838 #obtain data
tiernof97fd272016-07-11 14:32:37 +0200839 try:
840 datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter_id, "datacenter")
841 where_= {"datacenter_id":datacenter_dict['uuid']}
842 if netmap_id:
843 if utils.check_valid_uuid(netmap_id):
844 where_["uuid"] = netmap_id
845 else:
846 where_["name"] = netmap_id
847 #change_keys_http2db(content, http2db_tenant, reverse=True)
848 deleted = mydb.delete_row(FROM='datacenter_nets', WHERE= where_)
tiernod2b560b2017-10-11 10:30:18 +0200849 if deleted == 0 and netmap_id:
tiernof97fd272016-07-11 14:32:37 +0200850 bottle.abort(HTTP_Not_Found, "No netmap found with " + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), where_.iteritems())) )
851 if netmap_id:
852 return format_out({"result": "netmap %s deleted" % netmap_id})
tierno7edb6752016-03-21 17:37:52 +0100853 else:
tiernof97fd272016-07-11 14:32:37 +0200854 return format_out({"result": "%d netmap deleted" % deleted})
tiernod2b560b2017-10-11 10:30:18 +0200855 except bottle.HTTPError:
856 raise
tiernof97fd272016-07-11 14:32:37 +0200857 except (nfvo.NfvoException, db_base_Exception) as e:
858 logger.error("http_delnetmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
859 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000860 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000861 logger.error("Unexpected exception: ", exc_info=True)
862 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno7edb6752016-03-21 17:37:52 +0100863
864
865@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/upload', method='POST')
866def http_uploadnetmap_datacenter_id(tenant_id, datacenter_id):
tiernof97fd272016-07-11 14:32:37 +0200867 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
868 try:
869 netmaps = nfvo.datacenter_new_netmap(mydb, tenant_id, datacenter_id, None)
870 convert_datetime2str(netmaps)
871 utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
872 data={'netmaps' : netmaps}
873 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +0200874 except bottle.HTTPError:
875 raise
tiernof97fd272016-07-11 14:32:37 +0200876 except (nfvo.NfvoException, db_base_Exception) as e:
877 logger.error("http_uploadnetmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
878 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000879 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000880 logger.error("Unexpected exception: ", exc_info=True)
881 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
882
tierno7edb6752016-03-21 17:37:52 +0100883
884@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='POST')
885def http_postnetmap_datacenter_id(tenant_id, datacenter_id):
886 '''creates a new netmap'''
tiernof97fd272016-07-11 14:32:37 +0200887 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +0100888 #parse input data
889 http_content,_ = format_in( netmap_new_schema )
tierno42fcc3b2016-07-06 17:20:40 +0200890 r = utils.remove_extra_items(http_content, netmap_new_schema)
tiernoefd80c92016-09-16 14:17:46 +0200891 if r:
892 logger.debug("Remove received extra items %s", str(r))
tiernof97fd272016-07-11 14:32:37 +0200893 try:
894 #obtain data, check that only one exist
895 netmaps = nfvo.datacenter_new_netmap(mydb, tenant_id, datacenter_id, http_content)
896 convert_datetime2str(netmaps)
897 utils.convert_str2boolean(netmaps, ('shared', 'multipoint') )
898 data={'netmaps' : netmaps}
899 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +0200900 except bottle.HTTPError:
901 raise
tiernof97fd272016-07-11 14:32:37 +0200902 except (nfvo.NfvoException, db_base_Exception) as e:
903 logger.error("http_postnetmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
904 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000905 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000906 logger.error("Unexpected exception: ", exc_info=True)
907 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
908
tierno7edb6752016-03-21 17:37:52 +0100909
910@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps/<netmap_id>', method='PUT')
911def http_putnettmap_datacenter_id(tenant_id, datacenter_id, netmap_id):
912 '''edit a netmap'''
tiernof97fd272016-07-11 14:32:37 +0200913 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +0100914 #parse input data
915 http_content,_ = format_in( netmap_edit_schema )
tierno42fcc3b2016-07-06 17:20:40 +0200916 r = utils.remove_extra_items(http_content, netmap_edit_schema)
tiernoefd80c92016-09-16 14:17:46 +0200917 if r:
918 logger.debug("Remove received extra items %s", str(r))
tierno7edb6752016-03-21 17:37:52 +0100919
920 #obtain data, check that only one exist
tiernof97fd272016-07-11 14:32:37 +0200921 try:
922 nfvo.datacenter_edit_netmap(mydb, tenant_id, datacenter_id, netmap_id, http_content)
tierno7edb6752016-03-21 17:37:52 +0100923 return http_getnetmap_datacenter_id(tenant_id, datacenter_id, netmap_id)
tiernod2b560b2017-10-11 10:30:18 +0200924 except bottle.HTTPError:
925 raise
tiernof97fd272016-07-11 14:32:37 +0200926 except (nfvo.NfvoException, db_base_Exception) as e:
927 logger.error("http_putnettmap_datacenter_id error {}: {}".format(e.http_code, str(e)))
928 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000929 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000930 logger.error("Unexpected exception: ", exc_info=True)
931 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno7edb6752016-03-21 17:37:52 +0100932
933
934@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/action', method='POST')
935def http_action_datacenter_id(tenant_id, datacenter_id):
936 '''perform an action over datacenter, can use both uuid or name'''
tiernof97fd272016-07-11 14:32:37 +0200937 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +0100938 #parse input data
939 http_content,_ = format_in( datacenter_action_schema )
tierno42fcc3b2016-07-06 17:20:40 +0200940 r = utils.remove_extra_items(http_content, datacenter_action_schema)
tiernoefd80c92016-09-16 14:17:46 +0200941 if r:
942 logger.debug("Remove received extra items %s", str(r))
tiernof97fd272016-07-11 14:32:37 +0200943 try:
944 #obtain data, check that only one exist
945 result = nfvo.datacenter_action(mydb, tenant_id, datacenter_id, http_content)
946 if 'net-update' in http_content:
947 return http_getnetmap_datacenter_id(datacenter_id)
948 else:
949 return format_out(result)
tiernod2b560b2017-10-11 10:30:18 +0200950 except bottle.HTTPError:
951 raise
tiernof97fd272016-07-11 14:32:37 +0200952 except (nfvo.NfvoException, db_base_Exception) as e:
953 logger.error("http_action_datacenter_id error {}: {}".format(e.http_code, str(e)))
954 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000955 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000956 logger.error("Unexpected exception: ", exc_info=True)
957 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno7edb6752016-03-21 17:37:52 +0100958
959
960@bottle.route(url_base + '/datacenters/<datacenter_id>', method='DELETE')
961def http_delete_datacenter_id( datacenter_id):
962 '''delete a tenant from database, can use both uuid or name'''
963
tiernof97fd272016-07-11 14:32:37 +0200964 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
965 try:
966 data = nfvo.delete_datacenter(mydb, datacenter_id)
967 return format_out({"result":"datacenter '" + data + "' deleted"})
tiernod2b560b2017-10-11 10:30:18 +0200968 except bottle.HTTPError:
969 raise
tiernof97fd272016-07-11 14:32:37 +0200970 except (nfvo.NfvoException, db_base_Exception) as e:
971 logger.error("http_delete_datacenter_id error {}: {}".format(e.http_code, str(e)))
972 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000973 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000974 logger.error("Unexpected exception: ", exc_info=True)
975 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
976
tierno7edb6752016-03-21 17:37:52 +0100977
978@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='POST')
tiernod3750b32018-07-20 15:33:08 +0200979@bottle.route(url_base + '/<tenant_id>/vim_accounts', method='POST')
980def http_associate_datacenters(tenant_id, datacenter_id=None):
tierno7edb6752016-03-21 17:37:52 +0100981 '''associate an existing datacenter to a this tenant. '''
tiernof97fd272016-07-11 14:32:37 +0200982 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +0100983 #parse input data
gcalvinoc62cfa52017-10-05 18:21:25 +0200984 http_content,_ = format_in(datacenter_associate_schema, confidential_data=True)
tierno42fcc3b2016-07-06 17:20:40 +0200985 r = utils.remove_extra_items(http_content, datacenter_associate_schema)
tiernoefd80c92016-09-16 14:17:46 +0200986 if r:
987 logger.debug("Remove received extra items %s", str(r))
tiernof97fd272016-07-11 14:32:37 +0200988 try:
tiernod3750b32018-07-20 15:33:08 +0200989 vim_account_id = nfvo.create_vim_account(mydb, tenant_id, datacenter_id,
990 **http_content['datacenter'])
991 return http_get_vim_account(tenant_id, vim_account_id)
tiernod2b560b2017-10-11 10:30:18 +0200992 except bottle.HTTPError:
993 raise
tiernof97fd272016-07-11 14:32:37 +0200994 except (nfvo.NfvoException, db_base_Exception) as e:
995 logger.error("http_associate_datacenters error {}: {}".format(e.http_code, str(e)))
996 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +0000997 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +0000998 logger.error("Unexpected exception: ", exc_info=True)
999 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1000
tiernod3750b32018-07-20 15:33:08 +02001001@bottle.route(url_base + '/<tenant_id>/vim_accounts/<vim_account_id>', method='PUT')
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +01001002@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='PUT')
tiernod3750b32018-07-20 15:33:08 +02001003def http_vim_account_edit(tenant_id, vim_account_id=None, datacenter_id=None):
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +01001004 '''associate an existing datacenter to a this tenant. '''
1005 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1006 #parse input data
tiernod3750b32018-07-20 15:33:08 +02001007 http_content,_ = format_in(datacenter_associate_schema)
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +01001008 r = utils.remove_extra_items(http_content, datacenter_associate_schema)
1009 if r:
1010 logger.debug("Remove received extra items %s", str(r))
1011 try:
tiernod3750b32018-07-20 15:33:08 +02001012 vim_account_id = nfvo.edit_vim_account(mydb, tenant_id, vim_account_id, datacenter_id=datacenter_id,
1013 **http_content['datacenter'])
1014 return http_get_vim_account(tenant_id, vim_account_id)
tiernod2b560b2017-10-11 10:30:18 +02001015 except bottle.HTTPError:
1016 raise
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +01001017 except (nfvo.NfvoException, db_base_Exception) as e:
tiernod3750b32018-07-20 15:33:08 +02001018 logger.error("http_vim_account_edit error {}: {}".format(e.http_code, str(e)))
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +01001019 bottle.abort(e.http_code, str(e))
1020 except Exception as e:
1021 logger.error("Unexpected exception: ", exc_info=True)
1022 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno7edb6752016-03-21 17:37:52 +01001023
tiernod3750b32018-07-20 15:33:08 +02001024
tierno7edb6752016-03-21 17:37:52 +01001025@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='DELETE')
tiernod3750b32018-07-20 15:33:08 +02001026@bottle.route(url_base + '/<tenant_id>/vim_accounts/<vim_account_id>', method='DELETE')
1027def http_deassociate_datacenters(tenant_id, datacenter_id=None, vim_account_id=None):
tierno7edb6752016-03-21 17:37:52 +01001028 '''deassociate an existing datacenter to a this tenant. '''
tiernof97fd272016-07-11 14:32:37 +02001029 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1030 try:
tiernod3750b32018-07-20 15:33:08 +02001031 data = nfvo.delete_vim_account(mydb, tenant_id, vim_account_id, datacenter_id)
tiernof97fd272016-07-11 14:32:37 +02001032 return format_out({"result": data})
tiernod2b560b2017-10-11 10:30:18 +02001033 except bottle.HTTPError:
1034 raise
tiernof97fd272016-07-11 14:32:37 +02001035 except (nfvo.NfvoException, db_base_Exception) as e:
1036 logger.error("http_deassociate_datacenters error {}: {}".format(e.http_code, str(e)))
1037 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001038 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001039 logger.error("Unexpected exception: ", exc_info=True)
1040 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1041
Pablo Montes Moreno6aa0b2b2017-05-23 18:33:12 +02001042@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/network/<network_id>/attach', method='POST')
1043def http_post_vim_net_sdn_attach(tenant_id, datacenter_id, network_id):
1044 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1045 http_content, _ = format_in(sdn_external_port_schema)
1046 try:
1047 data = nfvo.vim_net_sdn_attach(mydb, tenant_id, datacenter_id, network_id, http_content)
1048 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +02001049 except bottle.HTTPError:
1050 raise
Pablo Montes Moreno6aa0b2b2017-05-23 18:33:12 +02001051 except (nfvo.NfvoException, db_base_Exception) as e:
1052 logger.error("http_post_vim_net_sdn_attach error {}: {}".format(e.http_code, str(e)))
1053 bottle.abort(e.http_code, str(e))
1054 except Exception as e:
1055 logger.error("Unexpected exception: ", exc_info=True)
1056 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1057
1058@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/network/<network_id>/detach', method='DELETE')
1059@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/network/<network_id>/detach/<port_id>', method='DELETE')
1060def http_delete_vim_net_sdn_detach(tenant_id, datacenter_id, network_id, port_id=None):
1061 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1062 try:
1063 data = nfvo.vim_net_sdn_detach(mydb, tenant_id, datacenter_id, network_id, port_id)
1064 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +02001065 except bottle.HTTPError:
1066 raise
Pablo Montes Moreno6aa0b2b2017-05-23 18:33:12 +02001067 except (nfvo.NfvoException, db_base_Exception) as e:
1068 logger.error("http_delete_vim_net_sdn_detach error {}: {}".format(e.http_code, str(e)))
1069 bottle.abort(e.http_code, str(e))
1070 except Exception as e:
1071 logger.error("Unexpected exception: ", exc_info=True)
1072 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno7edb6752016-03-21 17:37:52 +01001073
tierno7edb6752016-03-21 17:37:52 +01001074@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>', method='GET')
1075@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method='GET')
1076def http_get_vim_items(tenant_id, datacenter_id, item, name=None):
tiernof97fd272016-07-11 14:32:37 +02001077 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1078 try:
1079 data = nfvo.vim_action_get(mydb, tenant_id, datacenter_id, item, name)
tierno7edb6752016-03-21 17:37:52 +01001080 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +02001081 except bottle.HTTPError:
1082 raise
tiernof97fd272016-07-11 14:32:37 +02001083 except (nfvo.NfvoException, db_base_Exception) as e:
1084 logger.error("http_get_vim_items error {}: {}".format(e.http_code, str(e)))
1085 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001086 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001087 logger.error("Unexpected exception: ", exc_info=True)
1088 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1089
tierno7edb6752016-03-21 17:37:52 +01001090
1091@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>/<name>', method='DELETE')
1092def http_del_vim_items(tenant_id, datacenter_id, item, name):
tiernof97fd272016-07-11 14:32:37 +02001093 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1094 try:
1095 data = nfvo.vim_action_delete(mydb, tenant_id, datacenter_id, item, name)
tierno7edb6752016-03-21 17:37:52 +01001096 return format_out({"result":data})
tiernod2b560b2017-10-11 10:30:18 +02001097 except bottle.HTTPError:
1098 raise
tiernof97fd272016-07-11 14:32:37 +02001099 except (nfvo.NfvoException, db_base_Exception) as e:
1100 logger.error("http_del_vim_items error {}: {}".format(e.http_code, str(e)))
1101 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001102 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001103 logger.error("Unexpected exception: ", exc_info=True)
1104 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1105
tierno65a9b0c2016-09-28 14:57:25 +00001106
tierno7edb6752016-03-21 17:37:52 +01001107@bottle.route(url_base + '/<tenant_id>/vim/<datacenter_id>/<item>', method='POST')
1108def http_post_vim_items(tenant_id, datacenter_id, item):
tiernof97fd272016-07-11 14:32:37 +02001109 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +01001110 http_content,_ = format_in( object_schema )
tiernof97fd272016-07-11 14:32:37 +02001111 try:
1112 data = nfvo.vim_action_create(mydb, tenant_id, datacenter_id, item, http_content)
tierno7edb6752016-03-21 17:37:52 +01001113 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +02001114 except bottle.HTTPError:
1115 raise
tiernof97fd272016-07-11 14:32:37 +02001116 except (nfvo.NfvoException, db_base_Exception) as e:
1117 logger.error("http_post_vim_items error {}: {}".format(e.http_code, str(e)))
1118 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001119 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001120 logger.error("Unexpected exception: ", exc_info=True)
1121 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1122
tierno7edb6752016-03-21 17:37:52 +01001123
1124@bottle.route(url_base + '/<tenant_id>/vnfs', method='GET')
1125def http_get_vnfs(tenant_id):
tiernof97fd272016-07-11 14:32:37 +02001126 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1127 try:
1128 if tenant_id != 'any':
1129 #check valid tenant_id
1130 nfvo.check_tenant(mydb, tenant_id)
1131 select_,where_,limit_ = filter_query_string(bottle.request.query, None,
tiernof1ba57e2017-09-07 12:23:19 +02001132 ('uuid', 'name', 'osm_id', 'description', 'public', "tenant_id", "created_at") )
tiernof97fd272016-07-11 14:32:37 +02001133 if tenant_id != "any":
tierno3fcfdb72017-10-24 07:48:24 +02001134 where_["OR"]={"tenant_id": tenant_id, "public": True}
1135 vnfs = mydb.get_rows(FROM='vnfs', SELECT=select_, WHERE=where_, LIMIT=limit_)
1136 # change_keys_http2db(content, http2db_vnf, reverse=True)
tiernof97fd272016-07-11 14:32:37 +02001137 utils.convert_str2boolean(vnfs, ('public',))
1138 convert_datetime2str(vnfs)
tierno3fcfdb72017-10-24 07:48:24 +02001139 data={'vnfs': vnfs}
tierno7edb6752016-03-21 17:37:52 +01001140 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +02001141 except bottle.HTTPError:
1142 raise
tiernof97fd272016-07-11 14:32:37 +02001143 except (nfvo.NfvoException, db_base_Exception) as e:
1144 logger.error("http_get_vnfs error {}: {}".format(e.http_code, str(e)))
1145 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001146 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001147 logger.error("Unexpected exception: ", exc_info=True)
1148 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1149
tierno7edb6752016-03-21 17:37:52 +01001150
1151@bottle.route(url_base + '/<tenant_id>/vnfs/<vnf_id>', method='GET')
1152def http_get_vnf_id(tenant_id,vnf_id):
1153 '''get vnf details, can use both uuid or name'''
tiernof97fd272016-07-11 14:32:37 +02001154 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1155 try:
1156 vnf = nfvo.get_vnf_id(mydb,tenant_id,vnf_id)
1157 utils.convert_str2boolean(vnf, ('public',))
1158 convert_datetime2str(vnf)
1159 return format_out(vnf)
tiernod2b560b2017-10-11 10:30:18 +02001160 except bottle.HTTPError:
1161 raise
tiernof97fd272016-07-11 14:32:37 +02001162 except (nfvo.NfvoException, db_base_Exception) as e:
1163 logger.error("http_get_vnf_id error {}: {}".format(e.http_code, str(e)))
1164 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001165 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001166 logger.error("Unexpected exception: ", exc_info=True)
1167 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1168
tierno7edb6752016-03-21 17:37:52 +01001169
1170@bottle.route(url_base + '/<tenant_id>/vnfs', method='POST')
1171def http_post_vnfs(tenant_id):
tiernof1ba57e2017-09-07 12:23:19 +02001172 """ Insert a vnf into the catalogue. Creates the flavor and images, and fill the tables at database
1173 :param tenant_id: tenant that this vnf belongs to
1174 :return:
1175 """
1176 # print "Parsing the YAML file of the VNF"
1177 # parse input data
tiernof97fd272016-07-11 14:32:37 +02001178 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
garciadeblas9f8456e2016-09-05 05:02:59 +02001179 http_content, used_schema = format_in( vnfd_schema_v01, ("schema_version",), {"0.2": vnfd_schema_v02})
tierno42fcc3b2016-07-06 17:20:40 +02001180 r = utils.remove_extra_items(http_content, used_schema)
tiernoefd80c92016-09-16 14:17:46 +02001181 if r:
1182 logger.debug("Remove received extra items %s", str(r))
tiernof97fd272016-07-11 14:32:37 +02001183 try:
tierno4319dad2016-09-05 12:11:11 +02001184 if used_schema == vnfd_schema_v01:
garciadeblas9f8456e2016-09-05 05:02:59 +02001185 vnf_id = nfvo.new_vnf(mydb,tenant_id,http_content)
tierno4319dad2016-09-05 12:11:11 +02001186 elif used_schema == vnfd_schema_v02:
garciadeblas9f8456e2016-09-05 05:02:59 +02001187 vnf_id = nfvo.new_vnf_v02(mydb,tenant_id,http_content)
1188 else:
1189 logger.warning('Unexpected schema_version: %s', http_content.get("schema_version"))
1190 bottle.abort(HTTP_Bad_Request, "Invalid schema version")
tiernof97fd272016-07-11 14:32:37 +02001191 return http_get_vnf_id(tenant_id, vnf_id)
tiernod2b560b2017-10-11 10:30:18 +02001192 except bottle.HTTPError:
1193 raise
tiernof97fd272016-07-11 14:32:37 +02001194 except (nfvo.NfvoException, db_base_Exception) as e:
1195 logger.error("http_post_vnfs error {}: {}".format(e.http_code, str(e)))
1196 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001197 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001198 logger.error("Unexpected exception: ", exc_info=True)
1199 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1200
tiernof1ba57e2017-09-07 12:23:19 +02001201
1202@bottle.route(url_base + '/v3/<tenant_id>/vnfd', method='POST')
1203def http_post_vnfs_v3(tenant_id):
1204 """
1205 Insert one or several VNFs in the catalog, following OSM IM
1206 :param tenant_id: tenant owner of the VNF
1207 :return: The detailed list of inserted VNFs, following the old format
1208 """
1209 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1210 http_content, _ = format_in(None)
1211 try:
1212 vnfd_uuid_list = nfvo.new_vnfd_v3(mydb, tenant_id, http_content)
1213 vnfd_list = []
1214 for vnfd_uuid in vnfd_uuid_list:
1215 vnf = nfvo.get_vnf_id(mydb, tenant_id, vnfd_uuid)
1216 utils.convert_str2boolean(vnf, ('public',))
1217 convert_datetime2str(vnf)
1218 vnfd_list.append(vnf["vnf"])
1219 return format_out({"vnfd": vnfd_list})
tiernod2b560b2017-10-11 10:30:18 +02001220 except bottle.HTTPError:
1221 raise
tiernof1ba57e2017-09-07 12:23:19 +02001222 except (nfvo.NfvoException, db_base_Exception) as e:
1223 logger.error("http_post_vnfs error {}: {}".format(e.http_code, str(e)))
1224 bottle.abort(e.http_code, str(e))
1225 except Exception as e:
1226 logger.error("Unexpected exception: ", exc_info=True)
1227 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1228
tierno7edb6752016-03-21 17:37:52 +01001229@bottle.route(url_base + '/<tenant_id>/vnfs/<vnf_id>', method='DELETE')
tiernof1ba57e2017-09-07 12:23:19 +02001230def http_delete_vnf_id(tenant_id, vnf_id):
tierno7edb6752016-03-21 17:37:52 +01001231 '''delete a vnf from database, and images and flavors in VIM when appropriate, can use both uuid or name'''
tiernof97fd272016-07-11 14:32:37 +02001232 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +01001233 #check valid tenant_id and deletes the vnf, including images,
tiernof97fd272016-07-11 14:32:37 +02001234 try:
1235 data = nfvo.delete_vnf(mydb,tenant_id,vnf_id)
tierno7edb6752016-03-21 17:37:52 +01001236 #print json.dumps(data, indent=4)
1237 return format_out({"result":"VNF " + data + " deleted"})
tiernod2b560b2017-10-11 10:30:18 +02001238 except bottle.HTTPError:
1239 raise
tiernof97fd272016-07-11 14:32:37 +02001240 except (nfvo.NfvoException, db_base_Exception) as e:
1241 logger.error("http_delete_vnf_id error {}: {}".format(e.http_code, str(e)))
1242 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001243 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001244 logger.error("Unexpected exception: ", exc_info=True)
1245 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1246
tierno7edb6752016-03-21 17:37:52 +01001247
1248#@bottle.route(url_base + '/<tenant_id>/hosts/topology', method='GET')
1249#@bottle.route(url_base + '/<tenant_id>/physicalview/Madrid-Alcantara', method='GET')
1250@bottle.route(url_base + '/<tenant_id>/physicalview/<datacenter>', method='GET')
1251def http_get_hosts(tenant_id, datacenter):
1252 '''get the tidvim host hopology from the vim.'''
tiernof97fd272016-07-11 14:32:37 +02001253 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1254 #print "http_get_hosts received by tenant " + tenant_id + ' datacenter ' + datacenter
1255 try:
1256 if datacenter == 'treeview':
1257 data = nfvo.get_hosts(mydb, tenant_id)
1258 else:
1259 #openmano-gui is using a hardcoded value for the datacenter
1260 result, data = nfvo.get_hosts_info(mydb, tenant_id) #, datacenter)
1261
1262 if result < 0:
tiernoefd80c92016-09-16 14:17:46 +02001263 #print "http_get_hosts error %d %s" % (-result, data)
tiernof97fd272016-07-11 14:32:37 +02001264 bottle.abort(-result, data)
1265 else:
1266 convert_datetime2str(data)
tiernoefd80c92016-09-16 14:17:46 +02001267 #print json.dumps(data, indent=4)
tiernof97fd272016-07-11 14:32:37 +02001268 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +02001269 except bottle.HTTPError:
1270 raise
tiernof97fd272016-07-11 14:32:37 +02001271 except (nfvo.NfvoException, db_base_Exception) as e:
garciadeblas9f8456e2016-09-05 05:02:59 +02001272 logger.error("http_get_hosts error {}: {}".format(e.http_code, str(e)))
tiernof97fd272016-07-11 14:32:37 +02001273 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001274 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001275 logger.error("Unexpected exception: ", exc_info=True)
1276 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno7edb6752016-03-21 17:37:52 +01001277
1278
1279@bottle.route(url_base + '/<path:path>', method='OPTIONS')
1280def http_options_deploy(path):
1281 '''For some reason GUI web ask for OPTIONS that must be responded'''
1282 #TODO: check correct path, and correct headers request
tiernof97fd272016-07-11 14:32:37 +02001283 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +01001284 bottle.response.set_header('Access-Control-Allow-Methods','POST, GET, PUT, DELETE, OPTIONS')
1285 bottle.response.set_header('Accept','application/yaml,application/json')
1286 bottle.response.set_header('Content-Type','application/yaml,application/json')
1287 bottle.response.set_header('Access-Control-Allow-Headers','content-type')
1288 bottle.response.set_header('Access-Control-Allow-Origin','*')
1289 return
1290
1291@bottle.route(url_base + '/<tenant_id>/topology/deploy', method='POST')
1292def http_post_deploy(tenant_id):
1293 '''post topology deploy.'''
tiernof97fd272016-07-11 14:32:37 +02001294 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +01001295
tierno66aa0372016-07-06 17:31:12 +02001296 http_content, used_schema = format_in( nsd_schema_v01, ("schema_version",), {2: nsd_schema_v02})
tierno42fcc3b2016-07-06 17:20:40 +02001297 #r = utils.remove_extra_items(http_content, used_schema)
tierno7edb6752016-03-21 17:37:52 +01001298 #if r is not None: print "http_post_deploy: Warning: remove extra items ", r
tiernof97fd272016-07-11 14:32:37 +02001299 #print "http_post_deploy input: ", http_content
tierno7edb6752016-03-21 17:37:52 +01001300
tiernof97fd272016-07-11 14:32:37 +02001301 try:
1302 scenario_id = nfvo.new_scenario(mydb, tenant_id, http_content)
1303 instance = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['name'], http_content['name'])
1304 #print json.dumps(data, indent=4)
1305 return format_out(instance)
tiernod2b560b2017-10-11 10:30:18 +02001306 except bottle.HTTPError:
1307 raise
tiernof97fd272016-07-11 14:32:37 +02001308 except (nfvo.NfvoException, db_base_Exception) as e:
1309 logger.error("http_post_deploy error {}: {}".format(e.http_code, str(e)))
1310 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001311 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001312 logger.error("Unexpected exception: ", exc_info=True)
1313 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1314
tierno7edb6752016-03-21 17:37:52 +01001315
1316@bottle.route(url_base + '/<tenant_id>/topology/verify', method='POST')
1317def http_post_verify(tenant_id):
1318 #TODO:
1319# '''post topology verify'''
1320# print "http_post_verify by tenant " + tenant_id + ' datacenter ' + datacenter
tiernof97fd272016-07-11 14:32:37 +02001321 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +01001322 return
1323
1324#
1325# SCENARIOS
1326#
1327
1328@bottle.route(url_base + '/<tenant_id>/scenarios', method='POST')
1329def http_post_scenarios(tenant_id):
1330 '''add a scenario into the catalogue. Creates the scenario and its internal structure in the OPENMANO DB'''
tiernof97fd272016-07-11 14:32:37 +02001331 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
garciadeblas9f8456e2016-09-05 05:02:59 +02001332 http_content, used_schema = format_in( nsd_schema_v01, ("schema_version",), {2: nsd_schema_v02, "0.3": nsd_schema_v03})
tierno42fcc3b2016-07-06 17:20:40 +02001333 #r = utils.remove_extra_items(http_content, used_schema)
tierno7edb6752016-03-21 17:37:52 +01001334 #if r is not None: print "http_post_scenarios: Warning: remove extra items ", r
tiernof97fd272016-07-11 14:32:37 +02001335 #print "http_post_scenarios input: ", http_content
1336 try:
tierno4319dad2016-09-05 12:11:11 +02001337 if used_schema == nsd_schema_v01:
tiernof97fd272016-07-11 14:32:37 +02001338 scenario_id = nfvo.new_scenario(mydb, tenant_id, http_content)
tierno4319dad2016-09-05 12:11:11 +02001339 elif used_schema == nsd_schema_v02:
tierno5bb59dc2017-02-13 14:53:54 +01001340 scenario_id = nfvo.new_scenario_v02(mydb, tenant_id, http_content, "0.2")
tierno4319dad2016-09-05 12:11:11 +02001341 elif used_schema == nsd_schema_v03:
tierno5bb59dc2017-02-13 14:53:54 +01001342 scenario_id = nfvo.new_scenario_v02(mydb, tenant_id, http_content, "0.3")
garciadeblas9f8456e2016-09-05 05:02:59 +02001343 else:
1344 logger.warning('Unexpected schema_version: %s', http_content.get("schema_version"))
1345 bottle.abort(HTTP_Bad_Request, "Invalid schema version")
tierno7edb6752016-03-21 17:37:52 +01001346 #print json.dumps(data, indent=4)
1347 #return format_out(data)
tiernof97fd272016-07-11 14:32:37 +02001348 return http_get_scenario_id(tenant_id, scenario_id)
tiernod2b560b2017-10-11 10:30:18 +02001349 except bottle.HTTPError:
1350 raise
tiernof97fd272016-07-11 14:32:37 +02001351 except (nfvo.NfvoException, db_base_Exception) as e:
1352 logger.error("http_post_scenarios error {}: {}".format(e.http_code, str(e)))
1353 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001354 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001355 logger.error("Unexpected exception: ", exc_info=True)
1356 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1357
tiernof1ba57e2017-09-07 12:23:19 +02001358@bottle.route(url_base + '/v3/<tenant_id>/nsd', method='POST')
1359def http_post_nsds_v3(tenant_id):
1360 """
1361 Insert one or several NSDs in the catalog, following OSM IM
1362 :param tenant_id: tenant owner of the NSD
1363 :return: The detailed list of inserted NSDs, following the old format
1364 """
1365 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1366 http_content, _ = format_in(None)
1367 try:
1368 nsd_uuid_list = nfvo.new_nsd_v3(mydb, tenant_id, http_content)
1369 nsd_list = []
1370 for nsd_uuid in nsd_uuid_list:
1371 scenario = mydb.get_scenario(nsd_uuid, tenant_id)
1372 convert_datetime2str(scenario)
1373 nsd_list.append(scenario)
1374 data = {'nsd': nsd_list}
1375 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +02001376 except bottle.HTTPError:
1377 raise
tiernof1ba57e2017-09-07 12:23:19 +02001378 except (nfvo.NfvoException, db_base_Exception) as e:
1379 logger.error("http_post_nsds_v3 error {}: {}".format(e.http_code, str(e)))
1380 bottle.abort(e.http_code, str(e))
1381 except Exception as e:
1382 logger.error("Unexpected exception: ", exc_info=True)
1383 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1384
tierno7edb6752016-03-21 17:37:52 +01001385
1386@bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>/action', method='POST')
1387def http_post_scenario_action(tenant_id, scenario_id):
1388 '''take an action over a scenario'''
tiernof97fd272016-07-11 14:32:37 +02001389 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno551e5322017-01-19 16:16:26 +01001390 # parse input data
1391 http_content, _ = format_in(scenario_action_schema)
1392 r = utils.remove_extra_items(http_content, scenario_action_schema)
1393 if r:
1394 logger.debug("Remove received extra items %s", str(r))
tiernof97fd272016-07-11 14:32:37 +02001395 try:
tierno551e5322017-01-19 16:16:26 +01001396 # check valid tenant_id
1397 nfvo.check_tenant(mydb, tenant_id)
tiernof97fd272016-07-11 14:32:37 +02001398 if "start" in http_content:
1399 data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['start']['instance_name'], \
1400 http_content['start'].get('description',http_content['start']['instance_name']),
1401 http_content['start'].get('datacenter') )
tierno7edb6752016-03-21 17:37:52 +01001402 return format_out(data)
tiernof97fd272016-07-11 14:32:37 +02001403 elif "deploy" in http_content: #Equivalent to start
1404 data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['deploy']['instance_name'],
1405 http_content['deploy'].get('description',http_content['deploy']['instance_name']),
1406 http_content['deploy'].get('datacenter') )
tierno7edb6752016-03-21 17:37:52 +01001407 return format_out(data)
tiernof97fd272016-07-11 14:32:37 +02001408 elif "reserve" in http_content: #Reserve resources
1409 data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['reserve']['instance_name'],
1410 http_content['reserve'].get('description',http_content['reserve']['instance_name']),
1411 http_content['reserve'].get('datacenter'), startvms=False )
tierno7edb6752016-03-21 17:37:52 +01001412 return format_out(data)
tiernof97fd272016-07-11 14:32:37 +02001413 elif "verify" in http_content: #Equivalent to start and then delete
1414 data = nfvo.start_scenario(mydb, tenant_id, scenario_id, http_content['verify']['instance_name'],
1415 http_content['verify'].get('description',http_content['verify']['instance_name']),
1416 http_content['verify'].get('datacenter'), startvms=False )
1417 instance_id = data['uuid']
1418 nfvo.delete_instance(mydb, tenant_id,instance_id)
tierno7edb6752016-03-21 17:37:52 +01001419 return format_out({"result":"Verify OK"})
tiernod2b560b2017-10-11 10:30:18 +02001420 except bottle.HTTPError:
1421 raise
tiernof97fd272016-07-11 14:32:37 +02001422 except (nfvo.NfvoException, db_base_Exception) as e:
1423 logger.error("http_post_scenario_action error {}: {}".format(e.http_code, str(e)))
1424 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001425 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001426 logger.error("Unexpected exception: ", exc_info=True)
1427 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1428
tierno7edb6752016-03-21 17:37:52 +01001429
1430@bottle.route(url_base + '/<tenant_id>/scenarios', method='GET')
1431def http_get_scenarios(tenant_id):
1432 '''get scenarios list'''
tiernof97fd272016-07-11 14:32:37 +02001433 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1434 try:
1435 #check valid tenant_id
1436 if tenant_id != "any":
1437 nfvo.check_tenant(mydb, tenant_id)
1438 #obtain data
tiernof1ba57e2017-09-07 12:23:19 +02001439 s,w,l=filter_query_string(bottle.request.query, None,
1440 ('uuid', 'name', 'osm_id', 'description', 'tenant_id', 'created_at', 'public'))
tiernof97fd272016-07-11 14:32:37 +02001441 if tenant_id != "any":
tierno3fcfdb72017-10-24 07:48:24 +02001442 w["OR"] = {"tenant_id": tenant_id, "public": True}
1443 scenarios = mydb.get_rows(SELECT=s, WHERE=w, LIMIT=l, FROM='scenarios')
tiernof97fd272016-07-11 14:32:37 +02001444 convert_datetime2str(scenarios)
1445 utils.convert_str2boolean(scenarios, ('public',) )
1446 data={'scenarios':scenarios}
tierno7edb6752016-03-21 17:37:52 +01001447 #print json.dumps(scenarios, indent=4)
tiernof97fd272016-07-11 14:32:37 +02001448 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +02001449 except bottle.HTTPError:
1450 raise
tiernof97fd272016-07-11 14:32:37 +02001451 except (nfvo.NfvoException, db_base_Exception) as e:
1452 logger.error("http_get_scenarios error {}: {}".format(e.http_code, str(e)))
1453 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001454 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001455 logger.error("Unexpected exception: ", exc_info=True)
1456 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1457
tierno7edb6752016-03-21 17:37:52 +01001458
1459@bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='GET')
1460def http_get_scenario_id(tenant_id, scenario_id):
1461 '''get scenario details, can use both uuid or name'''
tiernof97fd272016-07-11 14:32:37 +02001462 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1463 try:
1464 #check valid tenant_id
1465 if tenant_id != "any":
1466 nfvo.check_tenant(mydb, tenant_id)
1467 #obtain data
1468 scenario = mydb.get_scenario(scenario_id, tenant_id)
1469 convert_datetime2str(scenario)
1470 data={'scenario' : scenario}
tierno7edb6752016-03-21 17:37:52 +01001471 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +02001472 except bottle.HTTPError:
1473 raise
tiernof97fd272016-07-11 14:32:37 +02001474 except (nfvo.NfvoException, db_base_Exception) as e:
1475 logger.error("http_get_scenarios error {}: {}".format(e.http_code, str(e)))
1476 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001477 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001478 logger.error("Unexpected exception: ", exc_info=True)
1479 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1480
tierno7edb6752016-03-21 17:37:52 +01001481
1482@bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='DELETE')
1483def http_delete_scenario_id(tenant_id, scenario_id):
1484 '''delete a scenario from database, can use both uuid or name'''
tierno664691a2017-01-31 12:43:46 +01001485 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tiernof97fd272016-07-11 14:32:37 +02001486 try:
1487 #check valid tenant_id
1488 if tenant_id != "any":
tierno664691a2017-01-31 12:43:46 +01001489 nfvo.check_tenant(mydb, tenant_id)
tiernof97fd272016-07-11 14:32:37 +02001490 #obtain data
1491 data = mydb.delete_scenario(scenario_id, tenant_id)
tierno7edb6752016-03-21 17:37:52 +01001492 #print json.dumps(data, indent=4)
1493 return format_out({"result":"scenario " + data + " deleted"})
tiernod2b560b2017-10-11 10:30:18 +02001494 except bottle.HTTPError:
1495 raise
tiernof97fd272016-07-11 14:32:37 +02001496 except (nfvo.NfvoException, db_base_Exception) as e:
1497 logger.error("http_delete_scenario_id error {}: {}".format(e.http_code, str(e)))
1498 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001499 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001500 logger.error("Unexpected exception: ", exc_info=True)
1501 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno7edb6752016-03-21 17:37:52 +01001502
1503
1504@bottle.route(url_base + '/<tenant_id>/scenarios/<scenario_id>', method='PUT')
1505def http_put_scenario_id(tenant_id, scenario_id):
1506 '''edit an existing scenario id'''
tiernof97fd272016-07-11 14:32:37 +02001507 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno7edb6752016-03-21 17:37:52 +01001508 http_content,_ = format_in( scenario_edit_schema )
tierno42fcc3b2016-07-06 17:20:40 +02001509 #r = utils.remove_extra_items(http_content, scenario_edit_schema)
tierno7edb6752016-03-21 17:37:52 +01001510 #if r is not None: print "http_put_scenario_id: Warning: remove extra items ", r
tiernof97fd272016-07-11 14:32:37 +02001511 #print "http_put_scenario_id input: ", http_content
1512 try:
1513 nfvo.edit_scenario(mydb, tenant_id, scenario_id, http_content)
tierno7edb6752016-03-21 17:37:52 +01001514 #print json.dumps(data, indent=4)
1515 #return format_out(data)
tiernof97fd272016-07-11 14:32:37 +02001516 return http_get_scenario_id(tenant_id, scenario_id)
tiernod2b560b2017-10-11 10:30:18 +02001517 except bottle.HTTPError:
1518 raise
tiernof97fd272016-07-11 14:32:37 +02001519 except (nfvo.NfvoException, db_base_Exception) as e:
1520 logger.error("http_put_scenario_id error {}: {}".format(e.http_code, str(e)))
1521 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001522 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001523 logger.error("Unexpected exception: ", exc_info=True)
1524 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno7edb6752016-03-21 17:37:52 +01001525
1526@bottle.route(url_base + '/<tenant_id>/instances', method='POST')
1527def http_post_instances(tenant_id):
garciadeblasedca7b32016-09-29 14:01:52 +00001528 '''create an instance-scenario'''
tiernof97fd272016-07-11 14:32:37 +02001529 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno551e5322017-01-19 16:16:26 +01001530 # parse input data
1531 http_content, used_schema = format_in(instance_scenario_create_schema_v01)
1532 r = utils.remove_extra_items(http_content, used_schema)
1533 if r is not None:
1534 logger.warning("http_post_instances: Warning: remove extra items %s", str(r))
tiernof97fd272016-07-11 14:32:37 +02001535 try:
1536 #check valid tenant_id
1537 if tenant_id != "any":
1538 nfvo.check_tenant(mydb, tenant_id)
tiernof97fd272016-07-11 14:32:37 +02001539 data = nfvo.create_instance(mydb, tenant_id, http_content["instance"])
tierno7edb6752016-03-21 17:37:52 +01001540 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +02001541 except bottle.HTTPError:
1542 raise
tiernof97fd272016-07-11 14:32:37 +02001543 except (nfvo.NfvoException, db_base_Exception) as e:
1544 logger.error("http_post_instances error {}: {}".format(e.http_code, str(e)))
1545 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001546 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001547 logger.error("Unexpected exception: ", exc_info=True)
1548 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno7edb6752016-03-21 17:37:52 +01001549
1550#
1551# INSTANCES
1552#
1553@bottle.route(url_base + '/<tenant_id>/instances', method='GET')
1554def http_get_instances(tenant_id):
1555 '''get instance list'''
tiernof97fd272016-07-11 14:32:37 +02001556 try:
1557 #check valid tenant_id
1558 if tenant_id != "any":
1559 nfvo.check_tenant(mydb, tenant_id)
1560 #obtain data
1561 s,w,l=filter_query_string(bottle.request.query, None, ('uuid', 'name', 'scenario_id', 'tenant_id', 'description', 'created_at'))
1562 if tenant_id != "any":
1563 w['tenant_id'] = tenant_id
1564 instances = mydb.get_rows(SELECT=s, WHERE=w, LIMIT=l, FROM='instance_scenarios')
1565 convert_datetime2str(instances)
1566 utils.convert_str2boolean(instances, ('public',) )
1567 data={'instances':instances}
1568 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +02001569 except bottle.HTTPError:
1570 raise
tiernof97fd272016-07-11 14:32:37 +02001571 except (nfvo.NfvoException, db_base_Exception) as e:
1572 logger.error("http_get_instances error {}: {}".format(e.http_code, str(e)))
1573 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001574 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001575 logger.error("Unexpected exception: ", exc_info=True)
1576 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1577
tierno7edb6752016-03-21 17:37:52 +01001578
1579@bottle.route(url_base + '/<tenant_id>/instances/<instance_id>', method='GET')
1580def http_get_instance_id(tenant_id, instance_id):
1581 '''get instances details, can use both uuid or name'''
tiernof97fd272016-07-11 14:32:37 +02001582 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1583 try:
tierno7f426e92018-06-28 15:21:32 +02001584
tiernof97fd272016-07-11 14:32:37 +02001585 #check valid tenant_id
1586 if tenant_id != "any":
1587 nfvo.check_tenant(mydb, tenant_id)
1588 if tenant_id == "any":
1589 tenant_id = None
tierno7f426e92018-06-28 15:21:32 +02001590
1591 instance = nfvo.get_instance_id(mydb, tenant_id, instance_id)
1592
tiernof5755962017-07-13 15:44:34 +02001593 # Workaround to SO, convert vnfs:vms:interfaces:ip_address from ";" separated list to report the first value
1594 for vnf in instance.get("vnfs", ()):
1595 for vm in vnf.get("vms", ()):
1596 for iface in vm.get("interfaces", ()):
1597 if iface.get("ip_address"):
1598 index = iface["ip_address"].find(";")
1599 if index >= 0:
1600 iface["ip_address"] = iface["ip_address"][:index]
tiernof97fd272016-07-11 14:32:37 +02001601 convert_datetime2str(instance)
tiernof5755962017-07-13 15:44:34 +02001602 # print json.dumps(instance, indent=4)
tiernof97fd272016-07-11 14:32:37 +02001603 return format_out(instance)
tiernod2b560b2017-10-11 10:30:18 +02001604 except bottle.HTTPError:
1605 raise
tiernof97fd272016-07-11 14:32:37 +02001606 except (nfvo.NfvoException, db_base_Exception) as e:
1607 logger.error("http_get_instance_id error {}: {}".format(e.http_code, str(e)))
1608 bottle.abort(e.http_code, str(e))
tierno8e995ce2016-09-22 08:13:00 +00001609 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001610 logger.error("Unexpected exception: ", exc_info=True)
1611 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1612
tierno7edb6752016-03-21 17:37:52 +01001613
1614@bottle.route(url_base + '/<tenant_id>/instances/<instance_id>', method='DELETE')
1615def http_delete_instance_id(tenant_id, instance_id):
1616 '''delete instance from VIM and from database, can use both uuid or name'''
tiernof97fd272016-07-11 14:32:37 +02001617 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1618 try:
1619 #check valid tenant_id
1620 if tenant_id != "any":
1621 nfvo.check_tenant(mydb, tenant_id)
1622 if tenant_id == "any":
1623 tenant_id = None
1624 #obtain data
1625 message = nfvo.delete_instance(mydb, tenant_id,instance_id)
tierno7edb6752016-03-21 17:37:52 +01001626 return format_out({"result":message})
tiernod2b560b2017-10-11 10:30:18 +02001627 except bottle.HTTPError:
1628 raise
tiernof97fd272016-07-11 14:32:37 +02001629 except (nfvo.NfvoException, db_base_Exception) as e:
1630 logger.error("http_delete_instance_id error {}: {}".format(e.http_code, str(e)))
1631 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001632 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001633 logger.error("Unexpected exception: ", exc_info=True)
1634 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1635
tierno7edb6752016-03-21 17:37:52 +01001636
1637@bottle.route(url_base + '/<tenant_id>/instances/<instance_id>/action', method='POST')
1638def http_post_instance_scenario_action(tenant_id, instance_id):
tierno868220c2017-09-26 00:11:05 +02001639 """
1640 take an action over a scenario instance
1641 :param tenant_id: tenant where user belongs to
1642 :param instance_id: instance indentity
1643 :return:
1644 """
tiernof97fd272016-07-11 14:32:37 +02001645 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
tierno551e5322017-01-19 16:16:26 +01001646 # parse input data
1647 http_content, _ = format_in(instance_scenario_action_schema)
1648 r = utils.remove_extra_items(http_content, instance_scenario_action_schema)
1649 if r:
1650 logger.debug("Remove received extra items %s", str(r))
tiernof97fd272016-07-11 14:32:37 +02001651 try:
1652 #check valid tenant_id
1653 if tenant_id != "any":
1654 nfvo.check_tenant(mydb, tenant_id)
1655
tiernof97fd272016-07-11 14:32:37 +02001656 #print "http_post_instance_scenario_action input: ", http_content
1657 #obtain data
1658 instance = mydb.get_instance_scenario(instance_id, tenant_id)
1659 instance_id = instance["uuid"]
1660
1661 data = nfvo.instance_action(mydb, tenant_id, instance_id, http_content)
tierno7edb6752016-03-21 17:37:52 +01001662 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +02001663 except bottle.HTTPError:
1664 raise
tiernof97fd272016-07-11 14:32:37 +02001665 except (nfvo.NfvoException, db_base_Exception) as e:
1666 logger.error("http_post_instance_scenario_action error {}: {}".format(e.http_code, str(e)))
1667 bottle.abort(e.http_code, str(e))
tierno65a9b0c2016-09-28 14:57:25 +00001668 except Exception as e:
garciadeblasedca7b32016-09-29 14:01:52 +00001669 logger.error("Unexpected exception: ", exc_info=True)
1670 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
tierno7edb6752016-03-21 17:37:52 +01001671
1672
tierno868220c2017-09-26 00:11:05 +02001673@bottle.route(url_base + '/<tenant_id>/instances/<instance_id>/action', method='GET')
1674@bottle.route(url_base + '/<tenant_id>/instances/<instance_id>/action/<action_id>', method='GET')
1675def http_get_instance_scenario_action(tenant_id, instance_id, action_id=None):
1676 """
1677 List the actions done over an instance, or the action details
1678 :param tenant_id: tenant where user belongs to. Can be "any" to ignore
1679 :param instance_id: instance id, can be "any" to get actions of all instances
1680 :return:
1681 """
1682 logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
1683 try:
1684 # check valid tenant_id
1685 if tenant_id != "any":
1686 nfvo.check_tenant(mydb, tenant_id)
1687 data = nfvo.instance_action_get(mydb, tenant_id, instance_id, action_id)
1688 return format_out(data)
tiernod2b560b2017-10-11 10:30:18 +02001689 except bottle.HTTPError:
1690 raise
tierno868220c2017-09-26 00:11:05 +02001691 except (nfvo.NfvoException, db_base_Exception) as e:
1692 logger.error("http_get_instance_scenario_action error {}: {}".format(e.http_code, str(e)))
1693 bottle.abort(e.http_code, str(e))
1694 except Exception as e:
1695 logger.error("Unexpected exception: ", exc_info=True)
1696 bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
1697
gcalvinoc62cfa52017-10-05 18:21:25 +02001698def remove_clear_passwd(data):
1699 """
1700 Removes clear passwords from the data received
1701 :param data: data with clear password
1702 :return: data without the password information
1703 """
1704
1705 passw = ['password: ', 'passwd: ']
1706
1707 for pattern in passw:
1708 init = data.find(pattern)
1709 while init != -1:
1710 end = data.find('\n', init)
1711 data = data[:init] + '{}******'.format(pattern) + data[end:]
1712 init += 1
1713 init = data.find(pattern, init)
1714 return data
tierno868220c2017-09-26 00:11:05 +02001715
tierno7edb6752016-03-21 17:37:52 +01001716@bottle.error(400)
1717@bottle.error(401)
1718@bottle.error(404)
1719@bottle.error(403)
1720@bottle.error(405)
1721@bottle.error(406)
1722@bottle.error(409)
1723@bottle.error(503)
1724@bottle.error(500)
1725def error400(error):
1726 e={"error":{"code":error.status_code, "type":error.status, "description":error.body}}
1727 bottle.response.headers['Access-Control-Allow-Origin'] = '*'
1728 return format_out(e)
1729