openmano first code upload
[osm/RO.git] / nfvo_db.py
1 # -*- coding: utf-8 -*-
2
3 ##
4 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
5 # This file is part of openmano
6 # All Rights Reserved.
7 #
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 # not use this file except in compliance with the License. You may obtain
10 # a copy of the License at
11 #
12 # http://www.apache.org/licenses/LICENSE-2.0
13 #
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 # License for the specific language governing permissions and limitations
18 # under the License.
19 #
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact with: nfvlabs@tid.es
22 ##
23
24 '''
25 NFVO DB engine. It implements all the methods to interact with the Openmano Database
26 '''
27 __author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
28 __date__ ="$28-aug-2014 10:05:01$"
29
30 import MySQLdb as mdb
31 import uuid as myUuid
32 from utils import auxiliary_functions as af
33 import json
34 import yaml
35 import time
36
37 HTTP_Bad_Request = 400
38 HTTP_Unauthorized = 401
39 HTTP_Not_Found = 404
40 HTTP_Method_Not_Allowed = 405
41 HTTP_Request_Timeout = 408
42 HTTP_Conflict = 409
43 HTTP_Service_Unavailable = 503
44 HTTP_Internal_Server_Error = 500
45
46 tables_with_created_field=["datacenters","instance_nets","instance_scenarios","instance_vms","instance_vnfs",
47 "interfaces","nets","nfvo_tenants","scenarios","sce_interfaces","sce_nets",
48 "sce_vnfs","tenants_datacenters","datacenter_tenants","vms","vnfs"]
49
50 class nfvo_db():
51 def __init__(self):
52 #initialization
53 return
54
55 def connect(self, host=None, user=None, passwd=None, database=None):
56 '''Connect to specific data base.
57 The first time a valid host, user, passwd and database must be provided,
58 Following calls can skip this parameters
59 '''
60 try:
61 if host is not None: self.host = host
62 if user is not None: self.user = user
63 if passwd is not None: self.passwd = passwd
64 if database is not None: self.database = database
65
66 self.con = mdb.connect(self.host, self.user, self.passwd, self.database)
67 print "DB: connected to %s@%s -> %s" % (self.user, self.host, self.database)
68 return 0
69 except mdb.Error, e:
70 print "nfvo_db.connect Error connecting to DB %s@%s -> %s Error %d: %s" % (self.user, self.host, self.database, e.args[0], e.args[1])
71 return -1
72
73 def get_db_version(self):
74 ''' Obtain the database schema version.
75 Return: (negative, text) if error or version 0.0 where schema_version table is missing
76 (version_int, version_text) if ok
77 '''
78 cmd = "SELECT version_int,version,openmano_ver FROM schema_version"
79 for retry_ in range(0,2):
80 try:
81 with self.con:
82 self.cur = self.con.cursor()
83 #print cmd
84 self.cur.execute(cmd)
85 rows = self.cur.fetchall()
86 highest_version_int=0
87 highest_version=""
88 #print rows
89 for row in rows: #look for the latest version
90 if row[0]>highest_version_int:
91 highest_version_int, highest_version = row[0:2]
92 return highest_version_int, highest_version
93 except (mdb.Error, AttributeError), e:
94 #print cmd
95 print "get_db_version DB Exception %d: %s" % (e.args[0], e.args[1])
96 r,c = self.format_error(e)
97 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
98
99 def disconnect(self):
100 '''disconnect from specific data base'''
101 try:
102 self.con.close()
103 del self.con
104 except mdb.Error, e:
105 print "Error disconnecting from DB: Error %d: %s" % (e.args[0], e.args[1])
106 return -1
107 except AttributeError, e: #self.con not defined
108 if e[0][-5:] == "'con'": return -1, "Database internal error, no connection."
109 else: raise
110
111 def format_error(self, e, command=None, extra=None):
112 if type(e[0]) is str:
113 if e[0][-5:] == "'con'": return -HTTP_Internal_Server_Error, "DB Exception, no connection."
114 else: raise
115 if e.args[0]==2006 or e.args[0]==2013 : #MySQL server has gone away (((or))) Exception 2013: Lost connection to MySQL server during query
116 #reconnect
117 self.connect()
118 return -HTTP_Request_Timeout,"Database reconnection. Try Again"
119
120 fk=e.args[1].find("foreign key constraint fails")
121 if fk>=0:
122 if command=="update": return -HTTP_Bad_Request, "tenant_id %s not found." % extra
123 elif command=="delete": return -HTTP_Bad_Request, "Resource is not free. There are %s that prevent deleting it." % extra
124 de = e.args[1].find("Duplicate entry")
125 fk = e.args[1].find("for key")
126 uk = e.args[1].find("Unknown column")
127 wc = e.args[1].find("in 'where clause'")
128 fl = e.args[1].find("in 'field list'")
129 #print de, fk, uk, wc,fl
130 if de>=0:
131 if fk>=0: #error 1062
132 return -HTTP_Conflict, "Value %s already in use for %s" % (e.args[1][de+15:fk], e.args[1][fk+7:])
133 if uk>=0:
134 if wc>=0:
135 return -HTTP_Bad_Request, "Field %s can not be used for filtering" % e.args[1][uk+14:wc]
136 if fl>=0:
137 return -HTTP_Bad_Request, "Field %s does not exist" % e.args[1][uk+14:wc]
138 return -HTTP_Internal_Server_Error, "Database internal Error %d: %s" % (e.args[0], e.args[1])
139
140 def __str2db_format(self, data):
141 '''Convert string data to database format.
142 If data is None it returns the 'Null' text,
143 otherwise it returns the text surrounded by quotes ensuring internal quotes are escaped.
144 '''
145 if data==None:
146 return 'Null'
147 out=str(data)
148 if "'" not in out:
149 return "'" + out + "'"
150 elif '"' not in out:
151 return '"' + out + '"'
152 else:
153 return json.dumps(out)
154
155 def __tuple2db_format_set(self, data):
156 '''Compose the needed text for a SQL SET, parameter 'data' is a pair tuple (A,B),
157 and it returns the text 'A="B"', where A is a field of a table and B is the value
158 If B is None it returns the 'A=Null' text, without surrounding Null by quotes
159 If B is not None it returns the text "A='B'" or 'A="B"' where B is surrounded by quotes,
160 and it ensures internal quotes of B are escaped.
161 '''
162 if data[1]==None:
163 return str(data[0]) + "=Null"
164 out=str(data[1])
165 if "'" not in out:
166 return str(data[0]) + "='" + out + "'"
167 elif '"' not in out:
168 return str(data[0]) + '="' + out + '"'
169 else:
170 return str(data[0]) + '=' + json.dumps(out)
171
172 def __tuple2db_format_where(self, data):
173 '''Compose the needed text for a SQL WHERE, parameter 'data' is a pair tuple (A,B),
174 and it returns the text 'A="B"', where A is a field of a table and B is the value
175 If B is None it returns the 'A is Null' text, without surrounding Null by quotes
176 If B is not None it returns the text "A='B'" or 'A="B"' where B is surrounded by quotes,
177 and it ensures internal quotes of B are escaped.
178 '''
179 if data[1]==None:
180 return str(data[0]) + " is Null"
181
182 # if type(data[1]) is tuple: #this can only happen in a WHERE_OR clause
183 # text =[]
184 # for d in data[1]:
185 # if d==None:
186 # text.append(str(data[0]) + " is Null")
187 # continue
188 # out=str(d)
189 # if "'" not in out:
190 # text.append( str(data[0]) + "='" + out + "'" )
191 # elif '"' not in out:
192 # text.append( str(data[0]) + '="' + out + '"' )
193 # else:
194 # text.append( str(data[0]) + '=' + json.dumps(out) )
195 # return " OR ".join(text)
196
197 out=str(data[1])
198 if "'" not in out:
199 return str(data[0]) + "='" + out + "'"
200 elif '"' not in out:
201 return str(data[0]) + '="' + out + '"'
202 else:
203 return str(data[0]) + '=' + json.dumps(out)
204
205 def __tuple2db_format_where_not(self, data):
206 '''Compose the needed text for a SQL WHERE(not). parameter 'data' is a pair tuple (A,B),
207 and it returns the text 'A<>"B"', where A is a field of a table and B is the value
208 If B is None it returns the 'A is not Null' text, without surrounding Null by quotes
209 If B is not None it returns the text "A<>'B'" or 'A<>"B"' where B is surrounded by quotes,
210 and it ensures internal quotes of B are escaped.
211 '''
212 if data[1]==None:
213 return str(data[0]) + " is not Null"
214 out=str(data[1])
215 if "'" not in out:
216 return str(data[0]) + "<>'" + out + "'"
217 elif '"' not in out:
218 return str(data[0]) + '<>"' + out + '"'
219 else:
220 return str(data[0]) + '<>' + json.dumps(out)
221
222 def __remove_quotes(self, data):
223 '''remove single quotes ' of any string content of data dictionary'''
224 for k,v in data.items():
225 if type(v) == str:
226 if "'" in v:
227 data[k] = data[k].replace("'","_")
228
229 def __update_rows(self, table, UPDATE, WHERE, log=False, modified_time=0):
230 ''' Update one or several rows into a table.
231 Atributes
232 UPDATE: dictionary with the key: value to change
233 table: table where to update
234 WHERE: dictionary of elements to update
235 Return: (result, descriptive text) where result indicates the number of updated files, negative if error
236 '''
237 #gettting uuid
238 uuid = WHERE['uuid'] if 'uuid' in WHERE else None
239 values = ",".join(map(self.__tuple2db_format_set, UPDATE.iteritems() ))
240 if modified_time:
241 values += ",modified_at=%f" % modified_time
242 cmd= "UPDATE " + table +" SET " + values +\
243 " WHERE " + " and ".join(map(self.__tuple2db_format_where, WHERE.iteritems() ))
244 print cmd
245 self.cur.execute(cmd)
246 nb_rows = self.cur.rowcount
247 if nb_rows > 0 and log:
248 #inserting new log
249 if uuid is None: uuid_k = uuid_v = ""
250 else: uuid_k=",uuid"; uuid_v=",'" + str(uuid) + "'"
251 cmd = "INSERT INTO logs (related,level%s,description) VALUES ('%s','debug'%s,\"updating %d entry %s\")" \
252 % (uuid_k, table, uuid_v, nb_rows, (str(UPDATE)).replace('"','-') )
253 print cmd
254 self.cur.execute(cmd)
255 return nb_rows, "%d updated from %s" % (nb_rows, table[:-1] )
256
257 def _new_row_internal(self, table, INSERT, tenant_id=None, add_uuid=False, root_uuid=None, log=False, created_time=0):
258 ''' Add one row into a table. It DOES NOT begin or end the transaction, so self.con.cursor must be created
259 Attribute
260 INSERT: dictionary with the key: value to insert
261 table: table where to insert
262 tenant_id: only useful for logs. If provided, logs will use this tenant_id
263 add_uuid: if True, it will create an uuid key entry at INSERT if not provided
264 It checks presence of uuid and add one automatically otherwise
265 Return: (result, uuid) where result can be 0 if error, or 1 if ok
266 '''
267
268 if add_uuid:
269 #create uuid if not provided
270 if 'uuid' not in INSERT:
271 uuid = INSERT['uuid'] = str(myUuid.uuid1()) # create_uuid
272 else:
273 uuid = str(INSERT['uuid'])
274 else:
275 uuid=None
276 if add_uuid:
277 #defining root_uuid if not provided
278 if root_uuid is None:
279 root_uuid = uuid
280 if created_time:
281 created_at = created_time
282 else:
283 created_at=time.time()
284 #inserting new uuid
285 cmd = "INSERT INTO uuids (uuid, root_uuid, used_at, created_at) VALUES ('%s','%s','%s', %f)" % (uuid, root_uuid, table, created_at)
286 print cmd
287 self.cur.execute(cmd)
288 #insertion
289 cmd= "INSERT INTO " + table +" SET " + \
290 ",".join(map(self.__tuple2db_format_set, INSERT.iteritems() ))
291 if created_time:
292 cmd += ",created_at=%f" % created_time
293 print cmd
294 self.cur.execute(cmd)
295 nb_rows = self.cur.rowcount
296 #inserting new log
297 if nb_rows > 0 and log:
298 if add_uuid: del INSERT['uuid']
299 if uuid is None: uuid_k = uuid_v = ""
300 else: uuid_k=",uuid"; uuid_v=",'" + str(uuid) + "'"
301 if tenant_id is None: tenant_k = tenant_v = ""
302 else: tenant_k=",nfvo_tenant_id"; tenant_v=",'" + str(tenant_id) + "'"
303 cmd = "INSERT INTO logs (related,level%s%s,description) VALUES ('%s','debug'%s%s,\"new %s %s\")" \
304 % (uuid_k, tenant_k, table, uuid_v, tenant_v, table[:-1], str(INSERT).replace('"','-'))
305 print cmd
306 self.cur.execute(cmd)
307 return nb_rows, uuid
308
309 def __get_rows(self,table,uuid):
310 self.cur.execute("SELECT * FROM " + str(table) +" where uuid='" + str(uuid) + "'")
311 rows = self.cur.fetchall()
312 return self.cur.rowcount, rows
313
314 def new_row(self, table, INSERT, tenant_id=None, add_uuid=False, log=False, created_time=0):
315 ''' Add one row into a table.
316 Attribute
317 INSERT: dictionary with the key: value to insert
318 table: table where to insert
319 tenant_id: only useful for logs. If provided, logs will use this tenant_id
320 add_uuid: if True, it will create an uuid key entry at INSERT if not provided
321 It checks presence of uuid and add one automatically otherwise
322 Return: (result, uuid) where result can be 0 if error, or 1 if ok
323 '''
324 if table in tables_with_created_field and created_time==0:
325 created_time=time.time()
326 for retry_ in range(0,2):
327 try:
328 with self.con:
329 self.cur = self.con.cursor()
330 return self._new_row_internal(table, INSERT, tenant_id, add_uuid, None, log, created_time)
331
332 except (mdb.Error, AttributeError), e:
333 print "nfvo_db.new_row DB Exception %d: %s" % (e.args[0], e.args[1])
334 r,c = self.format_error(e)
335 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
336
337 def update_rows(self, table, UPDATE, WHERE, log=False, modified_time=0):
338 ''' Update one or several rows into a table.
339 Atributes
340 UPDATE: dictionary with the key: value to change
341 table: table where to update
342 WHERE: dictionary of elements to update
343 Return: (result, descriptive text) where result indicates the number of updated files
344 '''
345 if table in tables_with_created_field and modified_time==0:
346 modified_time=time.time()
347 for retry_ in range(0,2):
348 try:
349 with self.con:
350 self.cur = self.con.cursor()
351 return self.__update_rows(table, UPDATE, WHERE, log)
352
353 except (mdb.Error, AttributeError), e:
354 print "nfvo_db.update_rows DB Exception %d: %s" % (e.args[0], e.args[1])
355 r,c = self.format_error(e)
356 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
357
358 def delete_row(self, table, uuid, tenant_id=None, log=True):
359 for retry_ in range(0,2):
360 try:
361 with self.con:
362 #delete host
363 self.cur = self.con.cursor()
364 cmd = "DELETE FROM %s WHERE uuid = '%s'" % (table, uuid)
365 print cmd
366 self.cur.execute(cmd)
367 deleted = self.cur.rowcount
368 if deleted == 1:
369 #delete uuid
370 if table == 'tenants': tenant_str=uuid
371 elif tenant_id:
372 tenant_str = tenant_id
373 else:
374 tenant_str = 'Null'
375 self.cur = self.con.cursor()
376 cmd = "DELETE FROM uuids WHERE root_uuid = '%s'" % uuid
377 print cmd
378 self.cur.execute(cmd)
379 #inserting new log
380 if log:
381 cmd = "INSERT INTO logs (related,level,uuid,nfvo_tenant_id,description) VALUES ('%s','debug','%s','%s','delete %s')" % (table, uuid, tenant_str, table[:-1])
382 print cmd
383 self.cur.execute(cmd)
384 return deleted, table[:-1] + " '%s' %s" %(uuid, "deleted" if deleted==1 else "not found")
385 except (mdb.Error, AttributeError), e:
386 print "nfvo_db.delete_row DB Exception %d: %s" % (e.args[0], e.args[1])
387 r,c = self.format_error(e, "delete", 'instances' if table=='hosts' or table=='tenants' else 'dependencies')
388 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
389
390 def delete_row_by_dict(self, **sql_dict):
391 ''' Deletes rows from a table.
392 Attribute sql_dir: dictionary with the following key: value
393 'FROM': string of table name (Mandatory)
394 'WHERE': dict of key:values, translated to key=value AND ... (Optional)
395 'WHERE_NOT': dict of key:values, translated to key<>value AND ... (Optional)
396 'LIMIT': limit of number of rows (Optional)
397 Return: the (number of items deleted, descriptive test) if ok; (negative, descriptive text) if error
398 '''
399 #print sql_dict
400 from_ = "FROM " + str(sql_dict['FROM'])
401 #print 'from_', from_
402 if 'WHERE' in sql_dict and len(sql_dict['WHERE']) > 0:
403 w=sql_dict['WHERE']
404 where_ = "WHERE " + " AND ".join(map(self.__tuple2db_format_where, w.iteritems()))
405 else: where_ = ""
406 if 'WHERE_NOT' in sql_dict and len(sql_dict['WHERE_NOT']) > 0:
407 w=sql_dict['WHERE_NOT']
408 where_2 = " AND ".join(map(self.__tuple2db_format_where_not, w.iteritems()))
409 if len(where_)==0: where_ = "WHERE " + where_2
410 else: where_ = where_ + " AND " + where_2
411 #print 'where_', where_
412 limit_ = "LIMIT " + str(sql_dict['LIMIT']) if 'LIMIT' in sql_dict else ""
413 #print 'limit_', limit_
414 cmd = " ".join( ("DELETE", from_, where_, limit_) )
415 print cmd
416 for retry_ in range(0,2):
417 try:
418 with self.con:
419 #delete host
420 self.cur = self.con.cursor()
421 self.cur.execute(cmd)
422 deleted = self.cur.rowcount
423 return deleted, "%d deleted from %s" % (deleted, sql_dict['FROM'][:-1] )
424 except (mdb.Error, AttributeError), e:
425 print "nfvo_db.delete_row DB Exception %d: %s" % (e.args[0], e.args[1])
426 r,c = self.format_error(e, "delete", 'dependencies')
427 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
428
429 def get_rows(self,table,uuid):
430 '''get row from a table based on uuid'''
431 for retry_ in range(0,2):
432 try:
433 with self.con:
434 self.cur = self.con.cursor(mdb.cursors.DictCursor)
435 self.cur.execute("SELECT * FROM " + str(table) +" where uuid='" + str(uuid) + "'")
436 rows = self.cur.fetchall()
437 return self.cur.rowcount, rows
438 except (mdb.Error, AttributeError), e:
439 print "nfvo_db.get_rows DB Exception %d: %s" % (e.args[0], e.args[1])
440 r,c = self.format_error(e)
441 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
442
443 def get_table(self, **sql_dict):
444 ''' Obtain rows from a table.
445 Attribute sql_dir: dictionary with the following key: value
446 'SELECT': list or tuple of fields to retrieve) (by default all)
447 'FROM': string of table name (Mandatory)
448 'WHERE': dict of key:values, translated to key=value (key is null) AND ... (Optional)
449 'WHERE_NOT': dict of key:values, translated to key<>value (key is not null) AND ... (Optional)
450 'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
451 'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional
452 'LIMIT': limit of number of rows (Optional)
453 'ORDER_BY': list or tuple of fields to order
454 Return: a list with dictionaries at each row
455 '''
456 #print sql_dict
457 select_= "SELECT " + ("*" if 'SELECT' not in sql_dict else ",".join(map(str,sql_dict['SELECT'])) )
458 #print 'select_', select_
459 from_ = "FROM " + str(sql_dict['FROM'])
460 #print 'from_', from_
461 where_and = ""
462 where_or = ""
463 w=sql_dict.get('WHERE')
464 if w:
465 where_and = " AND ".join(map(self.__tuple2db_format_where, w.iteritems() ))
466 w=sql_dict.get('WHERE_NOT')
467 if w:
468 if where_and: where_and += " AND "
469 where_and += " AND ".join(map(self.__tuple2db_format_where_not, w.iteritems() ) )
470 w=sql_dict.get('WHERE_OR')
471 if w:
472 where_or = " OR ".join(map(self.__tuple2db_format_where, w.iteritems() ))
473 if where_and and where_or:
474 if sql_dict.get("WHERE_AND_OR") == "AND":
475 where_ = "WHERE " + where_and + " AND (" + where_or + ")"
476 else:
477 where_ = "WHERE (" + where_and + ") OR " + where_or
478 elif where_and and not where_or:
479 where_ = "WHERE " + where_and
480 elif not where_and and where_or:
481 where_ = "WHERE " + where_or
482 else:
483 where_ = ""
484 #print 'where_', where_
485 limit_ = "LIMIT " + str(sql_dict['LIMIT']) if 'LIMIT' in sql_dict else ""
486 order_ = "ORDER BY " + ",".join(map(str,sql_dict['SELECT'])) if 'ORDER_BY' in sql_dict else ""
487
488 #print 'limit_', limit_
489 cmd = " ".join( (select_, from_, where_, limit_, order_) )
490 for retry_ in range(0,2):
491 try:
492 with self.con:
493 self.cur = self.con.cursor(mdb.cursors.DictCursor)
494 print cmd
495 self.cur.execute(cmd)
496 rows = self.cur.fetchall()
497 return self.cur.rowcount, rows
498 except (mdb.Error, AttributeError), e:
499 print "nfvo_db.get_table DB Exception %d: %s" % (e.args[0], e.args[1])
500 r,c = self.format_error(e)
501 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
502
503 def get_table_by_uuid_name(self, table, uuid_name, error_item_text=None, allow_serveral=False, WHERE_OR={}, WHERE_AND_OR="OR"):
504 ''' Obtain One row from a table based on name or uuid.
505 Attribute:
506 table: string of table name
507 uuid_name: name or uuid. If not uuid format is found, it is considered a name
508 allow_severeral: if False return ERROR if more than one row are founded
509 error_item_text: in case of error it identifies the 'item' name for a proper output text
510 'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
511 'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional
512 Return: if allow_several==False, a dictionary with this row, or error if no item is found or more than one is found
513 if allow_several==True, a list of dictionaries with the row or rows, error if no item is found
514 '''
515
516 if error_item_text==None:
517 error_item_text = table
518 what = 'uuid' if af.check_valid_uuid(uuid_name) else 'name'
519 cmd = " SELECT * FROM %s WHERE %s='%s'" % (table, what, uuid_name)
520 if WHERE_OR:
521 where_or = " OR ".join(map(self.__tuple2db_format_where, WHERE_OR.iteritems() ))
522 if WHERE_AND_OR == "AND":
523 cmd += " AND (" + where_or + ")"
524 else:
525 cmd += " OR " + where_or
526
527
528 for retry_ in range(0,2):
529 try:
530 with self.con:
531 self.cur = self.con.cursor(mdb.cursors.DictCursor)
532 print cmd
533 self.cur.execute(cmd)
534 number = self.cur.rowcount
535 if number==0:
536 return -HTTP_Not_Found, "No %s found with %s '%s'" %(error_item_text, what, uuid_name)
537 elif number>1 and not allow_serveral:
538 return -HTTP_Bad_Request, "More than one %s found with %s '%s'" %(error_item_text, what, uuid_name)
539 if allow_serveral:
540 rows = self.cur.fetchall()
541 else:
542 rows = self.cur.fetchone()
543 return number, rows
544 except (mdb.Error, AttributeError), e:
545 print "nfvo_db.get_table_by_uuid_name DB Exception %d: %s" % (e.args[0], e.args[1])
546 r,c = self.format_error(e)
547 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
548
549 def get_uuid(self, uuid):
550 '''check in the database if this uuid is already present'''
551 for retry_ in range(0,2):
552 try:
553 with self.con:
554 self.cur = self.con.cursor(mdb.cursors.DictCursor)
555 self.cur.execute("SELECT * FROM uuids where uuid='" + str(uuid) + "'")
556 rows = self.cur.fetchall()
557 return self.cur.rowcount, rows
558 except (mdb.Error, AttributeError), e:
559 print "nfvo_db.get_uuid DB Exception %d: %s" % (e.args[0], e.args[1])
560 r,c = self.format_error(e)
561 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
562
563 def new_vnf_as_a_whole(self,nfvo_tenant,vnf_name,vnf_descriptor,VNFCDict):
564 print "Adding new vnf to the NFVO database"
565 for retry_ in range(0,2):
566 created_time = time.time()
567 try:
568 with self.con:
569
570 myVNFDict = {}
571 myVNFDict["name"] = vnf_name
572 myVNFDict["descriptor"] = vnf_descriptor['vnf'].get('descriptor')
573 myVNFDict["public"] = vnf_descriptor['vnf'].get('public', "false")
574 myVNFDict["description"] = vnf_descriptor['vnf']['description']
575 myVNFDict["class"] = vnf_descriptor['vnf'].get('class',"MISC")
576 myVNFDict["tenant_id"] = vnf_descriptor['vnf'].get("tenant_id")
577
578 result, vnf_id = self._new_vnf(myVNFDict,nfvo_tenant,created_time)
579 if result < 0:
580 return result, "Error creating vnf in NFVO database: %s" %vnf_id
581
582 print "VNF %s added to NFVO DB. VNF id: %s" % (vnf_name,vnf_id)
583
584 print "Adding new vms to the NFVO database"
585 #For each vm, we must create the appropriate vm in the NFVO database.
586 vmDict = {}
587 for _,vm in VNFCDict.iteritems():
588 #This code could make the name of the vms grow and grow.
589 #If we agree to follow this convention, we should check with a regex that the vnfc name is not including yet the vnf name
590 #vm['name'] = "%s-%s" % (vnf_name,vm['name'])
591 print "VM name: %s. Description: %s" % (vm['name'], vm['description'])
592 vm["vnf_id"] = vnf_id
593 created_time += 0.00001
594 result, vm_id = self._new_vm(vm,nfvo_tenant,vnf_id,created_time)
595 if result < 0:
596 return result, "Error creating vm in NFVO database: %s" %vm_id
597
598 print "Internal vm id in NFVO DB: %s" % vm_id
599 vmDict[vm['name']] = vm_id
600
601 #Collect the data interfaces of each VM/VNFC under the 'numas' field
602 dataifacesDict = {}
603 for vm in vnf_descriptor['vnf']['VNFC']:
604 dataifacesDict[vm['name']] = {}
605 for numa in vm.get('numas', []):
606 for dataiface in numa.get('interfaces',[]):
607 af.convert_bandwidth(dataiface)
608 dataifacesDict[vm['name']][dataiface['name']] = {}
609 dataifacesDict[vm['name']][dataiface['name']]['vpci'] = dataiface['vpci']
610 dataifacesDict[vm['name']][dataiface['name']]['bw'] = dataiface['bandwidth']
611 dataifacesDict[vm['name']][dataiface['name']]['model'] = "PF" if dataiface['dedicated']=="yes" else ("VF" if dataiface['dedicated']=="no" else "VFnotShared")
612
613 #Collect the bridge interfaces of each VM/VNFC under the 'bridge-ifaces' field
614 bridgeInterfacesDict = {}
615 for vm in vnf_descriptor['vnf']['VNFC']:
616 if 'bridge-ifaces' in vm:
617 bridgeInterfacesDict[vm['name']] = {}
618 for bridgeiface in vm['bridge-ifaces']:
619 af.convert_bandwidth(bridgeiface)
620 bridgeInterfacesDict[vm['name']][bridgeiface['name']] = {}
621 bridgeInterfacesDict[vm['name']][bridgeiface['name']]['vpci'] = bridgeiface.get('vpci',None)
622 bridgeInterfacesDict[vm['name']][bridgeiface['name']]['mac'] = bridgeiface.get('mac_address',None)
623 bridgeInterfacesDict[vm['name']][bridgeiface['name']]['bw'] = bridgeiface.get('bandwidth', None)
624 bridgeInterfacesDict[vm['name']][bridgeiface['name']]['model'] = bridgeiface.get('model', None)
625
626 #For each internal connection, we add it to the interfaceDict and we create the appropriate net in the NFVO database.
627 print "Adding new nets (VNF internal nets) to the NFVO database (if any)"
628 internalconnList = []
629 if 'internal-connections' in vnf_descriptor['vnf']:
630 for net in vnf_descriptor['vnf']['internal-connections']:
631 print "CODE TO BE CHECKED"
632 print "Net name: %s. Description: %s" % (net['name'], net['description'])
633
634 myNetDict = {}
635 myNetDict["name"] = net['name']
636 myNetDict["description"] = net['description']
637 myNetDict["type"] = net['type']
638 myNetDict["vnf_id"] = vnf_id
639
640 created_time += 0.00001
641 result, net_id = self._new_net(myNetDict,nfvo_tenant,vnf_id, created_time)
642 if result < 0:
643 return result, "Error creating net in NFVO database: %s" %net_id
644
645 for element in net['elements']:
646 ifaceItem = {}
647 #ifaceItem["internal_name"] = "%s-%s-%s" % (net['name'],element['VNFC'], element['local_iface_name'])
648 ifaceItem["internal_name"] = element['local_iface_name']
649 #ifaceItem["vm_id"] = vmDict["%s-%s" % (vnf_name,element['VNFC'])]
650 ifaceItem["vm_id"] = vmDict[element['VNFC']]
651 ifaceItem["net_id"] = net_id
652 ifaceItem["type"] = net['type']
653 if ifaceItem ["type"] == "data":
654 ifaceItem["vpci"] = dataifacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['vpci']
655 ifaceItem["bw"] = dataifacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['bw']
656 ifaceItem["model"] = dataifacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['model']
657 else:
658 ifaceItem["vpci"] = bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['vpci']
659 ifaceItem["mac"] = bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['mac_address']
660 ifaceItem["bw"] = bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['bw']
661 ifaceItem["model"] = bridgeInterfacesDict[ element['VNFC'] ][ element['local_iface_name'] ]['model']
662 internalconnList.append(ifaceItem)
663
664 print "Internal net id in NFVO DB: %s" % net_id
665
666 print "Adding internal interfaces to the NFVO database (if any)"
667 for iface in internalconnList:
668 print "Iface name: %s" % iface['internal_name']
669 created_time += 0.00001
670 result, iface_id = self._new_interface(iface,nfvo_tenant,vnf_id,created_time)
671 if result < 0:
672 return result, "Error creating iface in NFVO database: %s" %iface_id
673 print "Iface id in NFVO DB: %s" % iface_id
674
675 print "Adding external interfaces to the NFVO database"
676 for iface in vnf_descriptor['vnf']['external-connections']:
677 myIfaceDict = {}
678 #myIfaceDict["internal_name"] = "%s-%s-%s" % (vnf_name,iface['VNFC'], iface['local_iface_name'])
679 myIfaceDict["internal_name"] = iface['local_iface_name']
680 #myIfaceDict["vm_id"] = vmDict["%s-%s" % (vnf_name,iface['VNFC'])]
681 myIfaceDict["vm_id"] = vmDict[iface['VNFC']]
682 myIfaceDict["external_name"] = iface['name']
683 myIfaceDict["type"] = iface['type']
684 if iface["type"] == "data":
685 myIfaceDict["vpci"] = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['vpci']
686 myIfaceDict["bw"] = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['bw']
687 myIfaceDict["model"] = dataifacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['model']
688 else:
689 myIfaceDict["vpci"] = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['vpci']
690 myIfaceDict["bw"] = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['bw']
691 myIfaceDict["model"] = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['model']
692 myIfaceDict["mac"] = bridgeInterfacesDict[ iface['VNFC'] ][ iface['local_iface_name'] ]['mac']
693 print "Iface name: %s" % iface['name']
694 created_time += 0.00001
695 result, iface_id = self._new_interface(myIfaceDict,nfvo_tenant,vnf_id,created_time)
696 if result < 0:
697 return result, "Error creating iface in NFVO database: %s" %iface_id
698 print "Iface id in NFVO DB: %s" % iface_id
699
700 return 1,vnf_id
701
702 except (mdb.Error, AttributeError), e:
703 print "new_vnf_as_a_whole DB Exception %d: %s" % (e.args[0], e.args[1])
704 r,c = self.format_error(e)
705 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
706
707 def _new_vnf(self, vnf_dict, tenant_id, created_time=0):
708 #return self.new_row('vnfs', vnf_dict, None, tenant_id, True, True)
709 return self._new_row_internal('vnfs', vnf_dict, tenant_id, add_uuid=True, root_uuid=None, log=True, created_time=created_time)
710
711 def _new_vm(self, vm_dict, tenant_id, vnf_id = None, created_time=0):
712 #return self.new_row('vms', vm_dict, tenant_id, True, True)
713 return self._new_row_internal('vms', vm_dict, tenant_id, add_uuid=True, root_uuid=vnf_id, log=True, created_time=created_time)
714
715
716 def _new_net(self, net_dict, tenant_id, vnf_id = None, created_time=0):
717 #return self.new_row('nets', net_dict, tenant_id, True, True)
718 return self._new_row_internal('nets', net_dict, tenant_id, add_uuid=True, root_uuid=vnf_id, log=True, created_time=created_time)
719
720 def _new_interface(self, interface_dict, tenant_id, vnf_id = None, created_time=0):
721 #return self.new_row('interfaces', interface_dict, tenant_id, True, True)
722 return self._new_row_internal('interfaces', interface_dict, tenant_id, add_uuid=True, root_uuid=vnf_id, log=True, created_time=created_time)
723
724 def new_scenario(self, scenario_dict):
725 for retry_ in range(0,2):
726 created_time = time.time()
727 try:
728 with self.con:
729 self.cur = self.con.cursor()
730 tenant_id = scenario_dict.get('tenant_id')
731 #scenario
732 INSERT_={'tenant_id': tenant_id,
733 'name': scenario_dict['name'],'description': scenario_dict['description']}
734
735 r,scenario_uuid = self._new_row_internal('scenarios', INSERT_, tenant_id, True, None, True,created_time)
736 if r<0:
737 print 'nfvo_db.new_scenario Error inserting at table scenarios: ' + scenario_uuid
738 return r,scenario_uuid
739 #sce_nets
740 for net in scenario_dict['nets'].values():
741 net_dict={'scenario_id': scenario_uuid}
742 net_dict["name"] = net["name"]
743 net_dict["type"] = net["type"]
744 net_dict["description"] = net.get("description")
745 net_dict["external"] = net.get("external", False)
746 if "graph" in net:
747 #net["graph"]=yaml.safe_dump(net["graph"],default_flow_style=True,width=256)
748 #TODO, must be json because of the GUI, change to yaml
749 net_dict["graph"]=json.dumps(net["graph"])
750 created_time += 0.00001
751 r,net_uuid = self._new_row_internal('sce_nets', net_dict, tenant_id, True, None, True, created_time)
752 if r<0:
753 print 'nfvo_db.new_scenario Error inserting at table sce_vnfs: ' + net_uuid
754 return r, net_uuid
755 net['uuid']=net_uuid
756 #sce_vnfs
757 for k,vnf in scenario_dict['vnfs'].items():
758 INSERT_={'scenario_id': scenario_uuid,
759 'name': k,
760 'vnf_id': vnf['uuid'],
761 #'description': scenario_dict['name']
762 'description': vnf['description']
763 }
764 if "graph" in vnf:
765 #INSERT_["graph"]=yaml.safe_dump(vnf["graph"],default_flow_style=True,width=256)
766 #TODO, must be json because of the GUI, change to yaml
767 INSERT_["graph"]=json.dumps(vnf["graph"])
768 created_time += 0.00001
769 r,scn_vnf_uuid = self._new_row_internal('sce_vnfs', INSERT_, tenant_id, True, scenario_uuid, True, created_time)
770 if r<0:
771 print 'nfvo_db.new_scenario Error inserting at table sce_vnfs: ' + scn_vnf_uuid
772 return r, scn_vnf_uuid
773 vnf['scn_vnf_uuid']=scn_vnf_uuid
774 #sce_interfaces
775 for iface in vnf['ifaces'].values():
776 print 'iface', iface
777 if 'net_key' not in iface:
778 continue
779 iface['net_id'] = scenario_dict['nets'][ iface['net_key'] ]['uuid']
780 INSERT_={'sce_vnf_id': scn_vnf_uuid,
781 'sce_net_id': iface['net_id'],
782 'interface_id': iface[ 'uuid' ]
783 }
784 created_time += 0.00001
785 r,iface_uuid = self._new_row_internal('sce_interfaces', INSERT_, tenant_id, True, scenario_uuid, True, created_time)
786 if r<0:
787 print 'nfvo_db.new_scenario Error inserting at table sce_vnfs: ' + iface_uuid
788 return r, iface_uuid
789
790 return 1, scenario_uuid
791
792 except (mdb.Error, AttributeError), e:
793 print "nfvo_db.new_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
794 r,c = self.format_error(e)
795 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
796
797 def edit_scenario(self, scenario_dict):
798 for retry_ in range(0,2):
799 modified_time = time.time()
800 try:
801 with self.con:
802 self.cur = self.con.cursor()
803 #check that scenario exist
804 tenant_id = scenario_dict.get('tenant_id')
805 scenario_uuid = scenario_dict['uuid']
806
807 where_text = "uuid='%s'" % scenario_uuid
808 if not tenant_id and tenant_id != "any":
809 where_text += " AND (tenant_id='%s' OR public='True')" % (tenant_id)
810 self.cur.execute("SELECT * FROM scenarios WHERE "+ where_text)
811 self.cur.fetchall()
812 if self.cur.rowcount==0:
813 return -HTTP_Bad_Request, "No scenario found with this criteria " + where_text
814 elif self.cur.rowcount>1:
815 return -HTTP_Bad_Request, "More than one scenario found with this criteria " + where_text
816
817 #scenario
818 nodes = {}
819 topology = scenario_dict.pop("topology", None)
820 if topology != None and "nodes" in topology:
821 nodes = topology.get("nodes",{})
822 UPDATE_ = {}
823 if "name" in scenario_dict: UPDATE_["name"] = scenario_dict["name"]
824 if "description" in scenario_dict: UPDATE_["description"] = scenario_dict["description"]
825 if len(UPDATE_)>0:
826 WHERE_={'tenant_id': tenant_id, 'uuid': scenario_uuid}
827 r,c = self.__update_rows('scenarios', UPDATE_, WHERE_, modified_time=modified_time)
828 if r<0:
829 print 'nfvo_db.edit_scenario Error ' + c + ' updating table scenarios: ' + scenario_uuid
830 return r,scenario_uuid
831 #sce_nets
832 for node_id, node in nodes.items():
833 if "graph" in node:
834 #node["graph"] = yaml.safe_dump(node["graph"],default_flow_style=True,width=256)
835 #TODO, must be json because of the GUI, change to yaml
836 node["graph"] = json.dumps(node["graph"])
837 WHERE_={'scenario_id': scenario_uuid, 'uuid': node_id}
838 r,c = self.__update_rows('sce_nets', node, WHERE_)
839 if r<=0:
840 r,c = self.__update_rows('sce_vnfs', node, WHERE_, modified_time=modified_time)
841 if r<0:
842 print 'nfvo_db.edit_scenario Error updating table sce_nets,sce_vnfs: ' + scenario_uuid
843 return r, scenario_uuid
844 return 1, scenario_uuid
845
846 except (mdb.Error, AttributeError), e:
847 print "nfvo_db.new_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
848 r,c = self.format_error(e)
849 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
850
851 # def get_instance_scenario(self, instance_scenario_id, tenant_id=None):
852 # '''Obtain the scenario instance information, filtering by one or serveral of the tenant, uuid or name
853 # instance_scenario_id is the uuid or the name if it is not a valid uuid format
854 # Only one scenario isntance must mutch the filtering or an error is returned
855 # '''
856 # print "1******************************************************************"
857 # try:
858 # with self.con:
859 # self.cur = self.con.cursor(mdb.cursors.DictCursor)
860 # #scenario table
861 # where_list=[]
862 # if tenant_id is not None: where_list.append( "tenant_id='" + tenant_id +"'" )
863 # if af.check_valid_uuid(instance_scenario_id):
864 # where_list.append( "uuid='" + instance_scenario_id +"'" )
865 # else:
866 # where_list.append( "name='" + instance_scenario_id +"'" )
867 # where_text = " AND ".join(where_list)
868 # self.cur.execute("SELECT * FROM instance_scenarios WHERE "+ where_text)
869 # rows = self.cur.fetchall()
870 # if self.cur.rowcount==0:
871 # return -HTTP_Bad_Request, "No scenario instance found with this criteria " + where_text
872 # elif self.cur.rowcount>1:
873 # return -HTTP_Bad_Request, "More than one scenario instance found with this criteria " + where_text
874 # instance_scenario_dict = rows[0]
875 #
876 # #instance_vnfs
877 # self.cur.execute("SELECT uuid,vnf_id FROM instance_vnfs WHERE instance_scenario_id='"+ instance_scenario_dict['uuid'] + "'")
878 # instance_scenario_dict['instance_vnfs'] = self.cur.fetchall()
879 # for vnf in instance_scenario_dict['instance_vnfs']:
880 # #instance_vms
881 # self.cur.execute("SELECT uuid, vim_vm_id "+
882 # "FROM instance_vms "+
883 # "WHERE instance_vnf_id='" + vnf['uuid'] +"'"
884 # )
885 # vnf['instance_vms'] = self.cur.fetchall()
886 # #instance_nets
887 # self.cur.execute("SELECT uuid, vim_net_id FROM instance_nets WHERE instance_scenario_id='"+ instance_scenario_dict['uuid'] + "'")
888 # instance_scenario_dict['instance_nets'] = self.cur.fetchall()
889 #
890 # #instance_interfaces
891 # self.cur.execute("SELECT uuid, vim_interface_id, instance_vm_id, instance_net_id FROM instance_interfaces WHERE instance_scenario_id='"+ instance_scenario_dict['uuid'] + "'")
892 # instance_scenario_dict['instance_interfaces'] = self.cur.fetchall()
893 #
894 # af.convert_datetime2str(instance_scenario_dict)
895 # af.convert_str2boolean(instance_scenario_dict, ('public','shared','external') )
896 # print "2******************************************************************"
897 # return 1, instance_scenario_dict
898 # except (mdb.Error, AttributeError), e:
899 # print "nfvo_db.get_instance_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
900 # return self.format_error(e)
901
902 def get_scenario(self, scenario_id, tenant_id=None, datacenter_id=None):
903 '''Obtain the scenario information, filtering by one or serveral of the tenant, uuid or name
904 scenario_id is the uuid or the name if it is not a valid uuid format
905 if datacenter_id is provided, it supply aditional vim_id fields with the matching vim uuid
906 Only one scenario must mutch the filtering or an error is returned
907 '''
908 for retry_ in range(0,2):
909 try:
910 with self.con:
911 self.cur = self.con.cursor(mdb.cursors.DictCursor)
912 #scenario table
913 if af.check_valid_uuid(scenario_id):
914 where_text = "uuid='%s'" % scenario_id
915 else:
916 where_text = "name='%s'" % scenario_id
917 if not tenant_id and tenant_id != "any":
918 where_text += " AND (tenant_id='%s' OR public='True')" % (tenant_id)
919 cmd = "SELECT * FROM scenarios WHERE "+ where_text
920 print cmd
921 self.cur.execute(cmd)
922 rows = self.cur.fetchall()
923 if self.cur.rowcount==0:
924 return -HTTP_Bad_Request, "No scenario found with this criteria " + where_text
925 elif self.cur.rowcount>1:
926 return -HTTP_Bad_Request, "More than one scenario found with this criteria " + where_text
927 scenario_dict = rows[0]
928
929 #sce_vnfs
930 cmd = "SELECT uuid,name,vnf_id,description FROM sce_vnfs WHERE scenario_id='%s' ORDER BY created_at" % scenario_dict['uuid']
931 self.cur.execute(cmd)
932 scenario_dict['vnfs'] = self.cur.fetchall()
933 for vnf in scenario_dict['vnfs']:
934 #sce_interfaces
935 cmd = "SELECT uuid,sce_net_id,interface_id FROM sce_interfaces WHERE sce_vnf_id='%s' ORDER BY created_at" %vnf['uuid']
936 self.cur.execute(cmd)
937 vnf['interfaces'] = self.cur.fetchall()
938 #vms
939 cmd = "SELECT vms.uuid as uuid, flavor_id, image_id, vms.name as name, vms.description as description " \
940 " FROM vnfs join vms on vnfs.uuid=vms.vnf_id " \
941 " WHERE vnfs.uuid='" + vnf['vnf_id'] +"'" \
942 " ORDER BY vms.created_at"
943 self.cur.execute(cmd)
944 vnf['vms'] = self.cur.fetchall()
945 for vm in vnf['vms']:
946 if datacenter_id!=None:
947 self.cur.execute("SELECT vim_id FROM datacenters_images WHERE image_id='%s' AND datacenter_id='%s'" %(vm['image_id'],datacenter_id))
948 if self.cur.rowcount==1:
949 vim_image_dict = self.cur.fetchone()
950 vm['vim_image_id']=vim_image_dict['vim_id']
951 self.cur.execute("SELECT vim_id FROM datacenters_flavors WHERE flavor_id='%s' AND datacenter_id='%s'" %(vm['flavor_id'],datacenter_id))
952 if self.cur.rowcount==1:
953 vim_flavor_dict = self.cur.fetchone()
954 vm['vim_flavor_id']=vim_flavor_dict['vim_id']
955
956 #interfaces
957 cmd = "SELECT uuid,internal_name,external_name,net_id,type,vpci,mac,bw,model" \
958 " FROM interfaces" \
959 " WHERE vm_id='%s'" \
960 " ORDER BY created_at" % vm['uuid']
961 self.cur.execute(cmd)
962 vm['interfaces'] = self.cur.fetchall()
963 #nets every net of a vms
964 self.cur.execute("SELECT uuid,name,type,description FROM nets WHERE vnf_id='" + vnf['vnf_id'] +"'" )
965 vnf['nets'] = self.cur.fetchall()
966 #sce_nets
967 cmd = "SELECT uuid,name,type,external,description" \
968 " FROM sce_nets WHERE scenario_id='%s'" \
969 " ORDER BY created_at " % scenario_dict['uuid']
970 self.cur.execute(cmd)
971 scenario_dict['nets'] = self.cur.fetchall()
972 #datacenter_nets
973 for net in scenario_dict['nets']:
974 if str(net['external']) == 'false':
975 continue
976 WHERE_=" WHERE name='%s'" % net['name']
977 if datacenter_id!=None:
978 WHERE_ += " AND datacenter_id='%s'" % datacenter_id
979 self.cur.execute("SELECT vim_net_id FROM datacenter_nets" + WHERE_ )
980 d_net = self.cur.fetchone()
981 if d_net==None or datacenter_id==None:
982 #print "nfvo_db.get_scenario() WARNING external net %s not found" % net['name']
983 net['vim_id']=None
984 else:
985 net['vim_id']=d_net['vim_net_id']
986
987 af.convert_datetime2str(scenario_dict)
988 af.convert_str2boolean(scenario_dict, ('public','shared','external') )
989 return 1, scenario_dict
990 except (mdb.Error, AttributeError), e:
991 print "nfvo_db.get_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
992 r,c = self.format_error(e)
993 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
994
995 def get_uuid_from_name(self, table, name):
996 '''Searchs in table the name and returns the uuid
997 '''
998 for retry_ in range(0,2):
999 try:
1000 with self.con:
1001 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1002 where_text = "name='" + name +"'"
1003 self.cur.execute("SELECT * FROM " + table + " WHERE "+ where_text)
1004 rows = self.cur.fetchall()
1005 if self.cur.rowcount==0:
1006 return 0, "Name %s not found in table %s" %(name, table)
1007 elif self.cur.rowcount>1:
1008 return self.cur.rowcount, "More than one VNF with name %s found in table %s" %(name, table)
1009 return self.cur.rowcount, rows[0]["uuid"]
1010 except (mdb.Error, AttributeError), e:
1011 print "nfvo_db.get_uuid_from_name DB Exception %d: %s" % (e.args[0], e.args[1])
1012 r,c = self.format_error(e)
1013 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1014
1015 def delete_scenario(self, scenario_id, tenant_id=None):
1016 '''Deletes a scenario, filtering by one or several of the tenant, uuid or name
1017 scenario_id is the uuid or the name if it is not a valid uuid format
1018 Only one scenario must mutch the filtering or an error is returned
1019 '''
1020 for retry_ in range(0,2):
1021 try:
1022 with self.con:
1023 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1024
1025 #scenario table
1026 if af.check_valid_uuid(scenario_id):
1027 where_text = "uuid='%s'" % scenario_id
1028 else:
1029 where_text = "name='%s'" % scenario_id
1030 if not tenant_id and tenant_id != "any":
1031 where_text += " AND (tenant_id='%s' OR public='True')" % tenant_id
1032 self.cur.execute("SELECT * FROM scenarios WHERE "+ where_text)
1033 rows = self.cur.fetchall()
1034 if self.cur.rowcount==0:
1035 return -HTTP_Bad_Request, "No scenario found with this criteria " + where_text
1036 elif self.cur.rowcount>1:
1037 return -HTTP_Bad_Request, "More than one scenario found with this criteria " + where_text
1038 scenario_uuid = rows[0]["uuid"]
1039 scenario_name = rows[0]["name"]
1040
1041 #sce_vnfs
1042 self.cur.execute("DELETE FROM scenarios WHERE uuid='" + scenario_uuid + "'")
1043
1044 return 1, scenario_uuid + " " + scenario_name
1045 except (mdb.Error, AttributeError), e:
1046 print "nfvo_db.delete_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
1047 r,c = self.format_error(e, "delete", "instances running")
1048 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1049
1050 def new_instance_scenario_as_a_whole(self,tenant_id,instance_scenario_name,instance_scenario_description,scenarioDict):
1051 print "Adding new instance scenario to the NFVO database"
1052 for retry_ in range(0,2):
1053 created_time = time.time()
1054 try:
1055 with self.con:
1056 self.cur = self.con.cursor()
1057 #instance_scenarios
1058 datacenter_tenant_id = scenarioDict['datacenter_tenant_id']
1059 datacenter_id = scenarioDict['datacenter_id']
1060 INSERT_={'tenant_id': tenant_id,
1061 'datacenter_tenant_id': datacenter_tenant_id,
1062 'name': instance_scenario_name,
1063 'description': instance_scenario_description,
1064 'scenario_id' : scenarioDict['uuid'],
1065 'datacenter_id': datacenter_id
1066 }
1067 r,instance_uuid = self._new_row_internal('instance_scenarios', INSERT_, tenant_id, True, None, True, created_time)
1068 if r<0:
1069 print 'nfvo_db.new_instance_scenario_as_a_whole() Error inserting at table instance_scenarios: ' + instance_uuid
1070 return r, instance_uuid
1071
1072 net_scene2instance={}
1073 #instance_nets #nets interVNF
1074 for net in scenarioDict['nets']:
1075 INSERT_={'vim_net_id': net['vim_id'], 'external': net['external'], 'instance_scenario_id':instance_uuid } #, 'type': net['type']
1076 INSERT_['datacenter_id'] = net.get('datacenter_id', datacenter_id)
1077 INSERT_['datacenter_tenant_id'] = net.get('datacenter_tenant_id', datacenter_tenant_id)
1078 if net.get("uuid"):
1079 INSERT_['sce_net_id'] = net['uuid']
1080 created_time += 0.00001
1081 r,instance_net_uuid = self._new_row_internal('instance_nets', INSERT_, tenant_id, True, instance_uuid, True, created_time)
1082 if r<0:
1083 print 'nfvo_db.new_instance_scenario_as_a_whole() Error inserting at table instance_nets: ' + instance_net_uuid
1084 return r, instance_net_uuid
1085 net_scene2instance[ net['uuid'] ] = instance_net_uuid
1086 net['uuid'] = instance_net_uuid #overwrite scnario uuid by instance uuid
1087
1088 #instance_vnfs
1089 for vnf in scenarioDict['vnfs']:
1090 INSERT_={'instance_scenario_id': instance_uuid, 'vnf_id': vnf['vnf_id'] }
1091 INSERT_['datacenter_id'] = vnf.get('datacenter_id', datacenter_id)
1092 INSERT_['datacenter_tenant_id'] = vnf.get('datacenter_tenant_id', datacenter_tenant_id)
1093 if vnf.get("uuid"):
1094 INSERT_['sce_vnf_id'] = vnf['uuid']
1095 created_time += 0.00001
1096 r,instance_vnf_uuid = self._new_row_internal('instance_vnfs', INSERT_, tenant_id, True, instance_uuid, True,created_time)
1097 if r<0:
1098 print 'nfvo_db.new_instance_scenario_as_a_whole() Error inserting at table instance_vnfs: ' + instance_vnf_uuid
1099 return r, instance_vnf_uuid
1100 vnf['uuid'] = instance_vnf_uuid #overwrite scnario uuid by instance uuid
1101
1102 #instance_nets #nets intraVNF
1103 for net in vnf['nets']:
1104 INSERT_={'vim_net_id': net['vim_id'], 'external': 'false', 'instance_scenario_id':instance_uuid } #, 'type': net['type']
1105 INSERT_['datacenter_id'] = net.get('datacenter_id', datacenter_id)
1106 INSERT_['datacenter_tenant_id'] = net.get('datacenter_tenant_id', datacenter_tenant_id)
1107 if net.get("uuid"):
1108 INSERT_['net_id'] = net['uuid']
1109 created_time += 0.00001
1110 r,instance_net_uuid = self._new_row_internal('instance_nets', INSERT_, tenant_id, True, instance_uuid, True,created_time)
1111 if r<0:
1112 print 'nfvo_db.new_instance_scenario_as_a_whole() Error inserting at table instance_nets: ' + instance_net_uuid
1113 return r, instance_net_uuid
1114 net_scene2instance[ net['uuid'] ] = instance_net_uuid
1115 net['uuid'] = instance_net_uuid #overwrite scnario uuid by instance uuid
1116
1117 #instance_vms
1118 for vm in vnf['vms']:
1119 INSERT_={'instance_vnf_id': instance_vnf_uuid, 'vm_id': vm['uuid'], 'vim_vm_id': vm['vim_id'] }
1120 created_time += 0.00001
1121 r,instance_vm_uuid = self._new_row_internal('instance_vms', INSERT_, tenant_id, True, instance_uuid, True, created_time)
1122 if r<0:
1123 print 'nfvo_db.new_instance_scenario_as_a_whole() Error inserting at table instance_vms: ' + instance_vm_uuid
1124 return r, instance_vm_uuid
1125 vm['uuid'] = instance_vm_uuid #overwrite scnario uuid by instance uuid
1126
1127 #instance_interfaces
1128 for interface in vm['interfaces']:
1129 net_id = interface.get('net_id', None)
1130 if net_id is None:
1131 #check if is connected to a inter VNFs net
1132 for iface in vnf['interfaces']:
1133 if iface['interface_id'] == interface['uuid']:
1134 net_id = iface.get('sce_net_id', None)
1135 break
1136 if net_id is None:
1137 continue
1138 interface_type='external' if interface['external_name'] is not None else 'internal'
1139 INSERT_={'instance_vm_id': instance_vm_uuid, 'instance_net_id': net_scene2instance[net_id],
1140 'interface_id': interface['uuid'], 'vim_interface_id': interface.get('vim_id'), 'type': interface_type }
1141 #created_time += 0.00001
1142 r,interface_uuid = self._new_row_internal('instance_interfaces', INSERT_, tenant_id, True, instance_uuid, True) #, created_time)
1143 if r<0:
1144 print 'nfvo_db.new_instance_scenario_as_a_whole() Error inserting at table instance_interfaces: ' + interface_uuid
1145 return r, interface_uuid
1146 interface['uuid'] = interface_uuid #overwrite scnario uuid by instance uuid
1147
1148
1149
1150 return 1, instance_uuid
1151
1152 except (mdb.Error, AttributeError), e:
1153 print "new_instance_scenario_as_a_whole DB Exception %d: %s" % (e.args[0], e.args[1])
1154 r,c = self.format_error(e)
1155 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1156
1157 def get_instance_scenario(self, instance_id, tenant_id=None, verbose=False):
1158 '''Obtain the instance information, filtering by one or several of the tenant, uuid or name
1159 instance_id is the uuid or the name if it is not a valid uuid format
1160 Only one instance must mutch the filtering or an error is returned
1161 '''
1162 for retry_ in range(0,2):
1163 try:
1164 with self.con:
1165 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1166 #instance table
1167 where_list=[]
1168 if tenant_id is not None: where_list.append( "inst.tenant_id='" + tenant_id +"'" )
1169 if af.check_valid_uuid(instance_id):
1170 where_list.append( "inst.uuid='" + instance_id +"'" )
1171 else:
1172 where_list.append( "inst.name='" + instance_id +"'" )
1173 where_text = " AND ".join(where_list)
1174 command = "SELECT inst.uuid as uuid,inst.name as name,inst.scenario_id as scenario_id, datacenter_id" +\
1175 " ,datacenter_tenant_id, s.name as scenario_name,inst.tenant_id as tenant_id" + \
1176 " ,inst.description as description,inst.created_at as created_at" +\
1177 " FROM instance_scenarios as inst join scenarios as s on inst.scenario_id=s.uuid"+\
1178 " WHERE " + where_text
1179 self.cur.execute(command)
1180 rows = self.cur.fetchall()
1181 if self.cur.rowcount==0:
1182 return -HTTP_Bad_Request, "No instance found with this criteria " + where_text
1183 elif self.cur.rowcount>1:
1184 return -HTTP_Bad_Request, "More than one instance found with this criteria " + where_text
1185 instance_dict = rows[0]
1186
1187 #instance_vnfs
1188 cmd = "SELECT iv.uuid as uuid,sv.vnf_id as vnf_id,sv.name as vnf_name, sce_vnf_id, datacenter_id, datacenter_tenant_id"\
1189 " FROM instance_vnfs as iv join sce_vnfs as sv on iv.sce_vnf_id=sv.uuid" \
1190 " WHERE iv.instance_scenario_id='%s'" \
1191 " ORDER BY iv.created_at " % instance_dict['uuid']
1192 self.cur.execute(cmd)
1193 instance_dict['vnfs'] = self.cur.fetchall()
1194 for vnf in instance_dict['vnfs']:
1195 vnf_manage_iface_list=[]
1196 #instance vms
1197 cmd = "SELECT iv.uuid as uuid, vim_vm_id, status, error_msg, vim_info, iv.created_at as created_at, name "\
1198 " FROM instance_vms as iv join vms on iv.vm_id=vms.uuid "\
1199 " WHERE instance_vnf_id='%s' ORDER BY iv.created_at" % vnf['uuid']
1200 self.cur.execute(cmd)
1201 vnf['vms'] = self.cur.fetchall()
1202 for vm in vnf['vms']:
1203 vm_manage_iface_list=[]
1204 #instance_interfaces
1205 cmd = "SELECT vim_interface_id, instance_net_id, internal_name,external_name, mac_address, ip_address, vim_info, i.type as type "\
1206 " FROM instance_interfaces as ii join interfaces as i on ii.interface_id=i.uuid "\
1207 " WHERE instance_vm_id='%s' ORDER BY created_at" % vm['uuid']
1208 self.cur.execute(cmd )
1209 vm['interfaces'] = self.cur.fetchall()
1210 for iface in vm['interfaces']:
1211 if iface["type"] == "mgmt" and iface["ip_address"]:
1212 vnf_manage_iface_list.append(iface["ip_address"])
1213 vm_manage_iface_list.append(iface["ip_address"])
1214 if not verbose:
1215 del iface["type"]
1216 if vm_manage_iface_list: vm["ip_address"] = ",".join(vm_manage_iface_list)
1217 if vnf_manage_iface_list: vnf["ip_address"] = ",".join(vnf_manage_iface_list)
1218
1219 #instance_nets
1220 #select_text = "instance_nets.uuid as uuid,sce_nets.name as net_name,instance_nets.vim_net_id as net_id,instance_nets.status as status,instance_nets.external as external"
1221 #from_text = "instance_nets join instance_scenarios on instance_nets.instance_scenario_id=instance_scenarios.uuid " + \
1222 # "join sce_nets on instance_scenarios.scenario_id=sce_nets.scenario_id"
1223 #where_text = "instance_nets.instance_scenario_id='"+ instance_dict['uuid'] + "'"
1224 cmd = "SELECT uuid,vim_net_id,status,error_msg,vim_info,external, sce_net_id, net_id as vnf_net_id, datacenter_id, datacenter_tenant_id"\
1225 " FROM instance_nets" \
1226 " WHERE instance_scenario_id='%s' ORDER BY created_at" % instance_dict['uuid']
1227 self.cur.execute(cmd)
1228 instance_dict['nets'] = self.cur.fetchall()
1229
1230 af.convert_datetime2str(instance_dict)
1231 af.convert_str2boolean(instance_dict, ('public','shared','external') )
1232 return 1, instance_dict
1233 except (mdb.Error, AttributeError), e:
1234 print "nfvo_db.get_instance_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
1235 r,c = self.format_error(e)
1236 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1237
1238 def delete_instance_scenario(self, instance_id, tenant_id=None):
1239 '''Deletes a instance_Scenario, filtering by one or serveral of the tenant, uuid or name
1240 instance_id is the uuid or the name if it is not a valid uuid format
1241 Only one instance_scenario must mutch the filtering or an error is returned
1242 '''
1243 for retry_ in range(0,2):
1244 try:
1245 with self.con:
1246 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1247
1248 #instance table
1249 where_list=[]
1250 if tenant_id is not None: where_list.append( "tenant_id='" + tenant_id +"'" )
1251 if af.check_valid_uuid(instance_id):
1252 where_list.append( "uuid='" + instance_id +"'" )
1253 else:
1254 where_list.append( "name='" + instance_id +"'" )
1255 where_text = " AND ".join(where_list)
1256 self.cur.execute("SELECT * FROM instance_scenarios WHERE "+ where_text)
1257 rows = self.cur.fetchall()
1258 if self.cur.rowcount==0:
1259 return -HTTP_Bad_Request, "No instance scenario found with this criteria " + where_text
1260 elif self.cur.rowcount>1:
1261 return -HTTP_Bad_Request, "More than one instance scenario found with this criteria " + where_text
1262 instance_uuid = rows[0]["uuid"]
1263 instance_name = rows[0]["name"]
1264
1265 #sce_vnfs
1266 self.cur.execute("DELETE FROM instance_scenarios WHERE uuid='" + instance_uuid + "'")
1267
1268 return 1, instance_uuid + " " + instance_name
1269 except (mdb.Error, AttributeError), e:
1270 print "nfvo_db.delete_instance_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
1271 r,c = self.format_error(e, "delete", "No dependences can avoid deleting!!!!")
1272 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1273
1274 def new_instance_scenario(self, instance_scenario_dict, tenant_id):
1275 #return self.new_row('vnfs', vnf_dict, None, tenant_id, True, True)
1276 return self._new_row_internal('instance_scenarios', instance_scenario_dict, tenant_id, add_uuid=True, root_uuid=None, log=True)
1277
1278 def update_instance_scenario(self, instance_scenario_dict):
1279 #TODO:
1280 return
1281
1282 def new_instance_vnf(self, instance_vnf_dict, tenant_id, instance_scenario_id = None):
1283 #return self.new_row('vms', vm_dict, tenant_id, True, True)
1284 return self._new_row_internal('instance_vnfs', instance_vnf_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
1285
1286 def update_instance_vnf(self, instance_vnf_dict):
1287 #TODO:
1288 return
1289
1290 def delete_instance_vnf(self, instance_vnf_id):
1291 #TODO:
1292 return
1293
1294 def new_instance_vm(self, instance_vm_dict, tenant_id, instance_scenario_id = None):
1295 #return self.new_row('vms', vm_dict, tenant_id, True, True)
1296 return self._new_row_internal('instance_vms', instance_vm_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
1297
1298 def update_instance_vm(self, instance_vm_dict):
1299 #TODO:
1300 return
1301
1302 def delete_instance_vm(self, instance_vm_id):
1303 #TODO:
1304 return
1305
1306 def new_instance_net(self, instance_net_dict, tenant_id, instance_scenario_id = None):
1307 return self._new_row_internal('instance_nets', instance_net_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
1308
1309 def update_instance_net(self, instance_net_dict):
1310 #TODO:
1311 return
1312
1313 def delete_instance_net(self, instance_net_id):
1314 #TODO:
1315 return
1316
1317 def new_instance_interface(self, instance_interface_dict, tenant_id, instance_scenario_id = None):
1318 return self._new_row_internal('instance_interfaces', instance_interface_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
1319
1320 def update_instance_interface(self, instance_interface_dict):
1321 #TODO:
1322 return
1323
1324 def delete_instance_interface(self, instance_interface_dict):
1325 #TODO:
1326 return
1327
1328 def update_datacenter_nets(self, datacenter_id, new_net_list=[]):
1329 ''' Removes the old and adds the new net list at datacenter list for one datacenter.
1330 Attribute
1331 datacenter_id: uuid of the datacenter to act upon
1332 table: table where to insert
1333 new_net_list: the new values to be inserted. If empty it only deletes the existing nets
1334 Return: (Inserted items, Deleted items) if OK, (-Error, text) if error
1335 '''
1336 for retry_ in range(0,2):
1337 created_time = time.time()
1338 try:
1339 with self.con:
1340 self.cur = self.con.cursor()
1341 cmd="DELETE FROM datacenter_nets WHERE datacenter_id='%s'" % datacenter_id
1342 print cmd
1343 self.cur.execute(cmd)
1344 deleted = self.cur.rowcount
1345 for new_net in new_net_list:
1346 created_time += 0.00001
1347 self._new_row_internal('datacenter_nets', new_net, tenant_id=None, add_uuid=True, created_time=created_time)
1348 return len (new_net_list), deleted
1349 except (mdb.Error, AttributeError), e:
1350 print "nfvo_db.update_datacenter_nets DB Exception %d: %s" % (e.args[0], e.args[1])
1351 r,c = self.format_error(e)
1352 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1353