Merge changes I392f2858,Iba0cab65,I16304baf,Ic5befeff,I77f648f4, ...
[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'],
734 'description': scenario_dict['description'],
735 'public': scenario_dict.get('public', "false")}
736
737 r,scenario_uuid = self._new_row_internal('scenarios', INSERT_, tenant_id, True, None, True,created_time)
738 if r<0:
739 print 'nfvo_db.new_scenario Error inserting at table scenarios: ' + scenario_uuid
740 return r,scenario_uuid
741 #sce_nets
742 for net in scenario_dict['nets'].values():
743 net_dict={'scenario_id': scenario_uuid}
744 net_dict["name"] = net["name"]
745 net_dict["type"] = net["type"]
746 net_dict["description"] = net.get("description")
747 net_dict["external"] = net.get("external", False)
748 if "graph" in net:
749 #net["graph"]=yaml.safe_dump(net["graph"],default_flow_style=True,width=256)
750 #TODO, must be json because of the GUI, change to yaml
751 net_dict["graph"]=json.dumps(net["graph"])
752 created_time += 0.00001
753 r,net_uuid = self._new_row_internal('sce_nets', net_dict, tenant_id, True, None, True, created_time)
754 if r<0:
755 print 'nfvo_db.new_scenario Error inserting at table sce_vnfs: ' + net_uuid
756 return r, net_uuid
757 net['uuid']=net_uuid
758 #sce_vnfs
759 for k,vnf in scenario_dict['vnfs'].items():
760 INSERT_={'scenario_id': scenario_uuid,
761 'name': k,
762 'vnf_id': vnf['uuid'],
763 #'description': scenario_dict['name']
764 'description': vnf['description']
765 }
766 if "graph" in vnf:
767 #INSERT_["graph"]=yaml.safe_dump(vnf["graph"],default_flow_style=True,width=256)
768 #TODO, must be json because of the GUI, change to yaml
769 INSERT_["graph"]=json.dumps(vnf["graph"])
770 created_time += 0.00001
771 r,scn_vnf_uuid = self._new_row_internal('sce_vnfs', INSERT_, tenant_id, True, scenario_uuid, True, created_time)
772 if r<0:
773 print 'nfvo_db.new_scenario Error inserting at table sce_vnfs: ' + scn_vnf_uuid
774 return r, scn_vnf_uuid
775 vnf['scn_vnf_uuid']=scn_vnf_uuid
776 #sce_interfaces
777 for iface in vnf['ifaces'].values():
778 print 'iface', iface
779 if 'net_key' not in iface:
780 continue
781 iface['net_id'] = scenario_dict['nets'][ iface['net_key'] ]['uuid']
782 INSERT_={'sce_vnf_id': scn_vnf_uuid,
783 'sce_net_id': iface['net_id'],
784 'interface_id': iface[ 'uuid' ]
785 }
786 created_time += 0.00001
787 r,iface_uuid = self._new_row_internal('sce_interfaces', INSERT_, tenant_id, True, scenario_uuid, True, created_time)
788 if r<0:
789 print 'nfvo_db.new_scenario Error inserting at table sce_vnfs: ' + iface_uuid
790 return r, iface_uuid
791
792 return 1, scenario_uuid
793
794 except (mdb.Error, AttributeError), e:
795 print "nfvo_db.new_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
796 r,c = self.format_error(e)
797 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
798
799 def edit_scenario(self, scenario_dict):
800 for retry_ in range(0,2):
801 modified_time = time.time()
802 try:
803 with self.con:
804 self.cur = self.con.cursor()
805 #check that scenario exist
806 tenant_id = scenario_dict.get('tenant_id')
807 scenario_uuid = scenario_dict['uuid']
808
809 where_text = "uuid='%s'" % scenario_uuid
810 if not tenant_id and tenant_id != "any":
811 where_text += " AND (tenant_id='%s' OR public='True')" % (tenant_id)
812 self.cur.execute("SELECT * FROM scenarios WHERE "+ where_text)
813 self.cur.fetchall()
814 if self.cur.rowcount==0:
815 return -HTTP_Bad_Request, "No scenario found with this criteria " + where_text
816 elif self.cur.rowcount>1:
817 return -HTTP_Bad_Request, "More than one scenario found with this criteria " + where_text
818
819 #scenario
820 nodes = {}
821 topology = scenario_dict.pop("topology", None)
822 if topology != None and "nodes" in topology:
823 nodes = topology.get("nodes",{})
824 UPDATE_ = {}
825 if "name" in scenario_dict: UPDATE_["name"] = scenario_dict["name"]
826 if "description" in scenario_dict: UPDATE_["description"] = scenario_dict["description"]
827 if len(UPDATE_)>0:
828 WHERE_={'tenant_id': tenant_id, 'uuid': scenario_uuid}
829 r,c = self.__update_rows('scenarios', UPDATE_, WHERE_, modified_time=modified_time)
830 if r<0:
831 print 'nfvo_db.edit_scenario Error ' + c + ' updating table scenarios: ' + scenario_uuid
832 return r,scenario_uuid
833 #sce_nets
834 for node_id, node in nodes.items():
835 if "graph" in node:
836 #node["graph"] = yaml.safe_dump(node["graph"],default_flow_style=True,width=256)
837 #TODO, must be json because of the GUI, change to yaml
838 node["graph"] = json.dumps(node["graph"])
839 WHERE_={'scenario_id': scenario_uuid, 'uuid': node_id}
840 r,c = self.__update_rows('sce_nets', node, WHERE_)
841 if r<=0:
842 r,c = self.__update_rows('sce_vnfs', node, WHERE_, modified_time=modified_time)
843 if r<0:
844 print 'nfvo_db.edit_scenario Error updating table sce_nets,sce_vnfs: ' + scenario_uuid
845 return r, scenario_uuid
846 return 1, scenario_uuid
847
848 except (mdb.Error, AttributeError), e:
849 print "nfvo_db.new_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
850 r,c = self.format_error(e)
851 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
852
853 # def get_instance_scenario(self, instance_scenario_id, tenant_id=None):
854 # '''Obtain the scenario instance information, filtering by one or serveral of the tenant, uuid or name
855 # instance_scenario_id is the uuid or the name if it is not a valid uuid format
856 # Only one scenario isntance must mutch the filtering or an error is returned
857 # '''
858 # print "1******************************************************************"
859 # try:
860 # with self.con:
861 # self.cur = self.con.cursor(mdb.cursors.DictCursor)
862 # #scenario table
863 # where_list=[]
864 # if tenant_id is not None: where_list.append( "tenant_id='" + tenant_id +"'" )
865 # if af.check_valid_uuid(instance_scenario_id):
866 # where_list.append( "uuid='" + instance_scenario_id +"'" )
867 # else:
868 # where_list.append( "name='" + instance_scenario_id +"'" )
869 # where_text = " AND ".join(where_list)
870 # self.cur.execute("SELECT * FROM instance_scenarios WHERE "+ where_text)
871 # rows = self.cur.fetchall()
872 # if self.cur.rowcount==0:
873 # return -HTTP_Bad_Request, "No scenario instance found with this criteria " + where_text
874 # elif self.cur.rowcount>1:
875 # return -HTTP_Bad_Request, "More than one scenario instance found with this criteria " + where_text
876 # instance_scenario_dict = rows[0]
877 #
878 # #instance_vnfs
879 # self.cur.execute("SELECT uuid,vnf_id FROM instance_vnfs WHERE instance_scenario_id='"+ instance_scenario_dict['uuid'] + "'")
880 # instance_scenario_dict['instance_vnfs'] = self.cur.fetchall()
881 # for vnf in instance_scenario_dict['instance_vnfs']:
882 # #instance_vms
883 # self.cur.execute("SELECT uuid, vim_vm_id "+
884 # "FROM instance_vms "+
885 # "WHERE instance_vnf_id='" + vnf['uuid'] +"'"
886 # )
887 # vnf['instance_vms'] = self.cur.fetchall()
888 # #instance_nets
889 # self.cur.execute("SELECT uuid, vim_net_id FROM instance_nets WHERE instance_scenario_id='"+ instance_scenario_dict['uuid'] + "'")
890 # instance_scenario_dict['instance_nets'] = self.cur.fetchall()
891 #
892 # #instance_interfaces
893 # 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'] + "'")
894 # instance_scenario_dict['instance_interfaces'] = self.cur.fetchall()
895 #
896 # af.convert_datetime2str(instance_scenario_dict)
897 # af.convert_str2boolean(instance_scenario_dict, ('public','shared','external') )
898 # print "2******************************************************************"
899 # return 1, instance_scenario_dict
900 # except (mdb.Error, AttributeError), e:
901 # print "nfvo_db.get_instance_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
902 # return self.format_error(e)
903
904 def get_scenario(self, scenario_id, tenant_id=None, datacenter_id=None):
905 '''Obtain the scenario information, filtering by one or serveral of the tenant, uuid or name
906 scenario_id is the uuid or the name if it is not a valid uuid format
907 if datacenter_id is provided, it supply aditional vim_id fields with the matching vim uuid
908 Only one scenario must mutch the filtering or an error is returned
909 '''
910 for retry_ in range(0,2):
911 try:
912 with self.con:
913 self.cur = self.con.cursor(mdb.cursors.DictCursor)
914 #scenario table
915 if af.check_valid_uuid(scenario_id):
916 where_text = "uuid='%s'" % scenario_id
917 else:
918 where_text = "name='%s'" % scenario_id
919 if not tenant_id and tenant_id != "any":
920 where_text += " AND (tenant_id='%s' OR public='True')" % (tenant_id)
921 cmd = "SELECT * FROM scenarios WHERE "+ where_text
922 print cmd
923 self.cur.execute(cmd)
924 rows = self.cur.fetchall()
925 if self.cur.rowcount==0:
926 return -HTTP_Bad_Request, "No scenario found with this criteria " + where_text
927 elif self.cur.rowcount>1:
928 return -HTTP_Bad_Request, "More than one scenario found with this criteria " + where_text
929 scenario_dict = rows[0]
930
931 #sce_vnfs
932 cmd = "SELECT uuid,name,vnf_id,description FROM sce_vnfs WHERE scenario_id='%s' ORDER BY created_at" % scenario_dict['uuid']
933 self.cur.execute(cmd)
934 scenario_dict['vnfs'] = self.cur.fetchall()
935 for vnf in scenario_dict['vnfs']:
936 #sce_interfaces
937 cmd = "SELECT uuid,sce_net_id,interface_id FROM sce_interfaces WHERE sce_vnf_id='%s' ORDER BY created_at" %vnf['uuid']
938 self.cur.execute(cmd)
939 vnf['interfaces'] = self.cur.fetchall()
940 #vms
941 cmd = "SELECT vms.uuid as uuid, flavor_id, image_id, vms.name as name, vms.description as description " \
942 " FROM vnfs join vms on vnfs.uuid=vms.vnf_id " \
943 " WHERE vnfs.uuid='" + vnf['vnf_id'] +"'" \
944 " ORDER BY vms.created_at"
945 self.cur.execute(cmd)
946 vnf['vms'] = self.cur.fetchall()
947 for vm in vnf['vms']:
948 if datacenter_id!=None:
949 self.cur.execute("SELECT vim_id FROM datacenters_images WHERE image_id='%s' AND datacenter_id='%s'" %(vm['image_id'],datacenter_id))
950 if self.cur.rowcount==1:
951 vim_image_dict = self.cur.fetchone()
952 vm['vim_image_id']=vim_image_dict['vim_id']
953 self.cur.execute("SELECT vim_id FROM datacenters_flavors WHERE flavor_id='%s' AND datacenter_id='%s'" %(vm['flavor_id'],datacenter_id))
954 if self.cur.rowcount==1:
955 vim_flavor_dict = self.cur.fetchone()
956 vm['vim_flavor_id']=vim_flavor_dict['vim_id']
957
958 #interfaces
959 cmd = "SELECT uuid,internal_name,external_name,net_id,type,vpci,mac,bw,model" \
960 " FROM interfaces" \
961 " WHERE vm_id='%s'" \
962 " ORDER BY created_at" % vm['uuid']
963 self.cur.execute(cmd)
964 vm['interfaces'] = self.cur.fetchall()
965 #nets every net of a vms
966 self.cur.execute("SELECT uuid,name,type,description FROM nets WHERE vnf_id='" + vnf['vnf_id'] +"'" )
967 vnf['nets'] = self.cur.fetchall()
968 #sce_nets
969 cmd = "SELECT uuid,name,type,external,description" \
970 " FROM sce_nets WHERE scenario_id='%s'" \
971 " ORDER BY created_at " % scenario_dict['uuid']
972 self.cur.execute(cmd)
973 scenario_dict['nets'] = self.cur.fetchall()
974 #datacenter_nets
975 for net in scenario_dict['nets']:
976 if str(net['external']) == 'false':
977 continue
978 WHERE_=" WHERE name='%s'" % net['name']
979 if datacenter_id!=None:
980 WHERE_ += " AND datacenter_id='%s'" % datacenter_id
981 self.cur.execute("SELECT vim_net_id FROM datacenter_nets" + WHERE_ )
982 d_net = self.cur.fetchone()
983 if d_net==None or datacenter_id==None:
984 #print "nfvo_db.get_scenario() WARNING external net %s not found" % net['name']
985 net['vim_id']=None
986 else:
987 net['vim_id']=d_net['vim_net_id']
988
989 af.convert_datetime2str(scenario_dict)
990 af.convert_str2boolean(scenario_dict, ('public','shared','external') )
991 return 1, scenario_dict
992 except (mdb.Error, AttributeError), e:
993 print "nfvo_db.get_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
994 r,c = self.format_error(e)
995 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
996
997 def get_uuid_from_name(self, table, name):
998 '''Searchs in table the name and returns the uuid
999 '''
1000 for retry_ in range(0,2):
1001 try:
1002 with self.con:
1003 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1004 where_text = "name='" + name +"'"
1005 self.cur.execute("SELECT * FROM " + table + " WHERE "+ where_text)
1006 rows = self.cur.fetchall()
1007 if self.cur.rowcount==0:
1008 return 0, "Name %s not found in table %s" %(name, table)
1009 elif self.cur.rowcount>1:
1010 return self.cur.rowcount, "More than one VNF with name %s found in table %s" %(name, table)
1011 return self.cur.rowcount, rows[0]["uuid"]
1012 except (mdb.Error, AttributeError), e:
1013 print "nfvo_db.get_uuid_from_name DB Exception %d: %s" % (e.args[0], e.args[1])
1014 r,c = self.format_error(e)
1015 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1016
1017 def delete_scenario(self, scenario_id, tenant_id=None):
1018 '''Deletes a scenario, filtering by one or several of the tenant, uuid or name
1019 scenario_id is the uuid or the name if it is not a valid uuid format
1020 Only one scenario must mutch the filtering or an error is returned
1021 '''
1022 for retry_ in range(0,2):
1023 try:
1024 with self.con:
1025 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1026
1027 #scenario table
1028 if af.check_valid_uuid(scenario_id):
1029 where_text = "uuid='%s'" % scenario_id
1030 else:
1031 where_text = "name='%s'" % scenario_id
1032 if not tenant_id and tenant_id != "any":
1033 where_text += " AND (tenant_id='%s' OR public='True')" % tenant_id
1034 self.cur.execute("SELECT * FROM scenarios WHERE "+ where_text)
1035 rows = self.cur.fetchall()
1036 if self.cur.rowcount==0:
1037 return -HTTP_Bad_Request, "No scenario found with this criteria " + where_text
1038 elif self.cur.rowcount>1:
1039 return -HTTP_Bad_Request, "More than one scenario found with this criteria " + where_text
1040 scenario_uuid = rows[0]["uuid"]
1041 scenario_name = rows[0]["name"]
1042
1043 #sce_vnfs
1044 self.cur.execute("DELETE FROM scenarios WHERE uuid='" + scenario_uuid + "'")
1045
1046 return 1, scenario_uuid + " " + scenario_name
1047 except (mdb.Error, AttributeError), e:
1048 print "nfvo_db.delete_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
1049 r,c = self.format_error(e, "delete", "instances running")
1050 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1051
1052 def new_instance_scenario_as_a_whole(self,tenant_id,instance_scenario_name,instance_scenario_description,scenarioDict):
1053 print "Adding new instance scenario to the NFVO database"
1054 for retry_ in range(0,2):
1055 created_time = time.time()
1056 try:
1057 with self.con:
1058 self.cur = self.con.cursor()
1059 #instance_scenarios
1060 datacenter_tenant_id = scenarioDict['datacenter_tenant_id']
1061 datacenter_id = scenarioDict['datacenter_id']
1062 INSERT_={'tenant_id': tenant_id,
1063 'datacenter_tenant_id': datacenter_tenant_id,
1064 'name': instance_scenario_name,
1065 'description': instance_scenario_description,
1066 'scenario_id' : scenarioDict['uuid'],
1067 'datacenter_id': datacenter_id
1068 }
1069 r,instance_uuid = self._new_row_internal('instance_scenarios', INSERT_, tenant_id, True, None, True, created_time)
1070 if r<0:
1071 print 'nfvo_db.new_instance_scenario_as_a_whole() Error inserting at table instance_scenarios: ' + instance_uuid
1072 return r, instance_uuid
1073
1074 net_scene2instance={}
1075 #instance_nets #nets interVNF
1076 for net in scenarioDict['nets']:
1077 INSERT_={'vim_net_id': net['vim_id'], 'external': net['external'], 'instance_scenario_id':instance_uuid } #, 'type': net['type']
1078 INSERT_['datacenter_id'] = net.get('datacenter_id', datacenter_id)
1079 INSERT_['datacenter_tenant_id'] = net.get('datacenter_tenant_id', datacenter_tenant_id)
1080 if net.get("uuid"):
1081 INSERT_['sce_net_id'] = net['uuid']
1082 created_time += 0.00001
1083 r,instance_net_uuid = self._new_row_internal('instance_nets', INSERT_, tenant_id, True, instance_uuid, True, created_time)
1084 if r<0:
1085 print 'nfvo_db.new_instance_scenario_as_a_whole() Error inserting at table instance_nets: ' + instance_net_uuid
1086 return r, instance_net_uuid
1087 net_scene2instance[ net['uuid'] ] = instance_net_uuid
1088 net['uuid'] = instance_net_uuid #overwrite scnario uuid by instance uuid
1089
1090 #instance_vnfs
1091 for vnf in scenarioDict['vnfs']:
1092 INSERT_={'instance_scenario_id': instance_uuid, 'vnf_id': vnf['vnf_id'] }
1093 INSERT_['datacenter_id'] = vnf.get('datacenter_id', datacenter_id)
1094 INSERT_['datacenter_tenant_id'] = vnf.get('datacenter_tenant_id', datacenter_tenant_id)
1095 if vnf.get("uuid"):
1096 INSERT_['sce_vnf_id'] = vnf['uuid']
1097 created_time += 0.00001
1098 r,instance_vnf_uuid = self._new_row_internal('instance_vnfs', INSERT_, tenant_id, True, instance_uuid, True,created_time)
1099 if r<0:
1100 print 'nfvo_db.new_instance_scenario_as_a_whole() Error inserting at table instance_vnfs: ' + instance_vnf_uuid
1101 return r, instance_vnf_uuid
1102 vnf['uuid'] = instance_vnf_uuid #overwrite scnario uuid by instance uuid
1103
1104 #instance_nets #nets intraVNF
1105 for net in vnf['nets']:
1106 INSERT_={'vim_net_id': net['vim_id'], 'external': 'false', 'instance_scenario_id':instance_uuid } #, 'type': net['type']
1107 INSERT_['datacenter_id'] = net.get('datacenter_id', datacenter_id)
1108 INSERT_['datacenter_tenant_id'] = net.get('datacenter_tenant_id', datacenter_tenant_id)
1109 if net.get("uuid"):
1110 INSERT_['net_id'] = net['uuid']
1111 created_time += 0.00001
1112 r,instance_net_uuid = self._new_row_internal('instance_nets', INSERT_, tenant_id, True, instance_uuid, True,created_time)
1113 if r<0:
1114 print 'nfvo_db.new_instance_scenario_as_a_whole() Error inserting at table instance_nets: ' + instance_net_uuid
1115 return r, instance_net_uuid
1116 net_scene2instance[ net['uuid'] ] = instance_net_uuid
1117 net['uuid'] = instance_net_uuid #overwrite scnario uuid by instance uuid
1118
1119 #instance_vms
1120 for vm in vnf['vms']:
1121 INSERT_={'instance_vnf_id': instance_vnf_uuid, 'vm_id': vm['uuid'], 'vim_vm_id': vm['vim_id'] }
1122 created_time += 0.00001
1123 r,instance_vm_uuid = self._new_row_internal('instance_vms', INSERT_, tenant_id, True, instance_uuid, True, created_time)
1124 if r<0:
1125 print 'nfvo_db.new_instance_scenario_as_a_whole() Error inserting at table instance_vms: ' + instance_vm_uuid
1126 return r, instance_vm_uuid
1127 vm['uuid'] = instance_vm_uuid #overwrite scnario uuid by instance uuid
1128
1129 #instance_interfaces
1130 for interface in vm['interfaces']:
1131 net_id = interface.get('net_id', None)
1132 if net_id is None:
1133 #check if is connected to a inter VNFs net
1134 for iface in vnf['interfaces']:
1135 if iface['interface_id'] == interface['uuid']:
1136 net_id = iface.get('sce_net_id', None)
1137 break
1138 if net_id is None:
1139 continue
1140 interface_type='external' if interface['external_name'] is not None else 'internal'
1141 INSERT_={'instance_vm_id': instance_vm_uuid, 'instance_net_id': net_scene2instance[net_id],
1142 'interface_id': interface['uuid'], 'vim_interface_id': interface.get('vim_id'), 'type': interface_type }
1143 #created_time += 0.00001
1144 r,interface_uuid = self._new_row_internal('instance_interfaces', INSERT_, tenant_id, True, instance_uuid, True) #, created_time)
1145 if r<0:
1146 print 'nfvo_db.new_instance_scenario_as_a_whole() Error inserting at table instance_interfaces: ' + interface_uuid
1147 return r, interface_uuid
1148 interface['uuid'] = interface_uuid #overwrite scnario uuid by instance uuid
1149
1150
1151
1152 return 1, instance_uuid
1153
1154 except (mdb.Error, AttributeError), e:
1155 print "new_instance_scenario_as_a_whole DB Exception %d: %s" % (e.args[0], e.args[1])
1156 r,c = self.format_error(e)
1157 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1158
1159 def get_instance_scenario(self, instance_id, tenant_id=None, verbose=False):
1160 '''Obtain the instance information, filtering by one or several of the tenant, uuid or name
1161 instance_id is the uuid or the name if it is not a valid uuid format
1162 Only one instance must mutch the filtering or an error is returned
1163 '''
1164 for retry_ in range(0,2):
1165 try:
1166 with self.con:
1167 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1168 #instance table
1169 where_list=[]
1170 if tenant_id is not None: where_list.append( "inst.tenant_id='" + tenant_id +"'" )
1171 if af.check_valid_uuid(instance_id):
1172 where_list.append( "inst.uuid='" + instance_id +"'" )
1173 else:
1174 where_list.append( "inst.name='" + instance_id +"'" )
1175 where_text = " AND ".join(where_list)
1176 command = "SELECT inst.uuid as uuid,inst.name as name,inst.scenario_id as scenario_id, datacenter_id" +\
1177 " ,datacenter_tenant_id, s.name as scenario_name,inst.tenant_id as tenant_id" + \
1178 " ,inst.description as description,inst.created_at as created_at" +\
1179 " FROM instance_scenarios as inst join scenarios as s on inst.scenario_id=s.uuid"+\
1180 " WHERE " + where_text
1181 self.cur.execute(command)
1182 rows = self.cur.fetchall()
1183 if self.cur.rowcount==0:
1184 return -HTTP_Bad_Request, "No instance found with this criteria " + where_text
1185 elif self.cur.rowcount>1:
1186 return -HTTP_Bad_Request, "More than one instance found with this criteria " + where_text
1187 instance_dict = rows[0]
1188
1189 #instance_vnfs
1190 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"\
1191 " FROM instance_vnfs as iv join sce_vnfs as sv on iv.sce_vnf_id=sv.uuid" \
1192 " WHERE iv.instance_scenario_id='%s'" \
1193 " ORDER BY iv.created_at " % instance_dict['uuid']
1194 self.cur.execute(cmd)
1195 instance_dict['vnfs'] = self.cur.fetchall()
1196 for vnf in instance_dict['vnfs']:
1197 vnf_manage_iface_list=[]
1198 #instance vms
1199 cmd = "SELECT iv.uuid as uuid, vim_vm_id, status, error_msg, vim_info, iv.created_at as created_at, name "\
1200 " FROM instance_vms as iv join vms on iv.vm_id=vms.uuid "\
1201 " WHERE instance_vnf_id='%s' ORDER BY iv.created_at" % vnf['uuid']
1202 self.cur.execute(cmd)
1203 vnf['vms'] = self.cur.fetchall()
1204 for vm in vnf['vms']:
1205 vm_manage_iface_list=[]
1206 #instance_interfaces
1207 cmd = "SELECT vim_interface_id, instance_net_id, internal_name,external_name, mac_address, ip_address, vim_info, i.type as type "\
1208 " FROM instance_interfaces as ii join interfaces as i on ii.interface_id=i.uuid "\
1209 " WHERE instance_vm_id='%s' ORDER BY created_at" % vm['uuid']
1210 self.cur.execute(cmd )
1211 vm['interfaces'] = self.cur.fetchall()
1212 for iface in vm['interfaces']:
1213 if iface["type"] == "mgmt" and iface["ip_address"]:
1214 vnf_manage_iface_list.append(iface["ip_address"])
1215 vm_manage_iface_list.append(iface["ip_address"])
1216 if not verbose:
1217 del iface["type"]
1218 if vm_manage_iface_list: vm["ip_address"] = ",".join(vm_manage_iface_list)
1219 if vnf_manage_iface_list: vnf["ip_address"] = ",".join(vnf_manage_iface_list)
1220
1221 #instance_nets
1222 #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"
1223 #from_text = "instance_nets join instance_scenarios on instance_nets.instance_scenario_id=instance_scenarios.uuid " + \
1224 # "join sce_nets on instance_scenarios.scenario_id=sce_nets.scenario_id"
1225 #where_text = "instance_nets.instance_scenario_id='"+ instance_dict['uuid'] + "'"
1226 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"\
1227 " FROM instance_nets" \
1228 " WHERE instance_scenario_id='%s' ORDER BY created_at" % instance_dict['uuid']
1229 self.cur.execute(cmd)
1230 instance_dict['nets'] = self.cur.fetchall()
1231
1232 af.convert_datetime2str(instance_dict)
1233 af.convert_str2boolean(instance_dict, ('public','shared','external') )
1234 return 1, instance_dict
1235 except (mdb.Error, AttributeError), e:
1236 print "nfvo_db.get_instance_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
1237 r,c = self.format_error(e)
1238 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1239
1240 def delete_instance_scenario(self, instance_id, tenant_id=None):
1241 '''Deletes a instance_Scenario, filtering by one or serveral of the tenant, uuid or name
1242 instance_id is the uuid or the name if it is not a valid uuid format
1243 Only one instance_scenario must mutch the filtering or an error is returned
1244 '''
1245 for retry_ in range(0,2):
1246 try:
1247 with self.con:
1248 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1249
1250 #instance table
1251 where_list=[]
1252 if tenant_id is not None: where_list.append( "tenant_id='" + tenant_id +"'" )
1253 if af.check_valid_uuid(instance_id):
1254 where_list.append( "uuid='" + instance_id +"'" )
1255 else:
1256 where_list.append( "name='" + instance_id +"'" )
1257 where_text = " AND ".join(where_list)
1258 self.cur.execute("SELECT * FROM instance_scenarios WHERE "+ where_text)
1259 rows = self.cur.fetchall()
1260 if self.cur.rowcount==0:
1261 return -HTTP_Bad_Request, "No instance scenario found with this criteria " + where_text
1262 elif self.cur.rowcount>1:
1263 return -HTTP_Bad_Request, "More than one instance scenario found with this criteria " + where_text
1264 instance_uuid = rows[0]["uuid"]
1265 instance_name = rows[0]["name"]
1266
1267 #sce_vnfs
1268 self.cur.execute("DELETE FROM instance_scenarios WHERE uuid='" + instance_uuid + "'")
1269
1270 return 1, instance_uuid + " " + instance_name
1271 except (mdb.Error, AttributeError), e:
1272 print "nfvo_db.delete_instance_scenario DB Exception %d: %s" % (e.args[0], e.args[1])
1273 r,c = self.format_error(e, "delete", "No dependences can avoid deleting!!!!")
1274 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1275
1276 def new_instance_scenario(self, instance_scenario_dict, tenant_id):
1277 #return self.new_row('vnfs', vnf_dict, None, tenant_id, True, True)
1278 return self._new_row_internal('instance_scenarios', instance_scenario_dict, tenant_id, add_uuid=True, root_uuid=None, log=True)
1279
1280 def update_instance_scenario(self, instance_scenario_dict):
1281 #TODO:
1282 return
1283
1284 def new_instance_vnf(self, instance_vnf_dict, tenant_id, instance_scenario_id = None):
1285 #return self.new_row('vms', vm_dict, tenant_id, True, True)
1286 return self._new_row_internal('instance_vnfs', instance_vnf_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
1287
1288 def update_instance_vnf(self, instance_vnf_dict):
1289 #TODO:
1290 return
1291
1292 def delete_instance_vnf(self, instance_vnf_id):
1293 #TODO:
1294 return
1295
1296 def new_instance_vm(self, instance_vm_dict, tenant_id, instance_scenario_id = None):
1297 #return self.new_row('vms', vm_dict, tenant_id, True, True)
1298 return self._new_row_internal('instance_vms', instance_vm_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
1299
1300 def update_instance_vm(self, instance_vm_dict):
1301 #TODO:
1302 return
1303
1304 def delete_instance_vm(self, instance_vm_id):
1305 #TODO:
1306 return
1307
1308 def new_instance_net(self, instance_net_dict, tenant_id, instance_scenario_id = None):
1309 return self._new_row_internal('instance_nets', instance_net_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
1310
1311 def update_instance_net(self, instance_net_dict):
1312 #TODO:
1313 return
1314
1315 def delete_instance_net(self, instance_net_id):
1316 #TODO:
1317 return
1318
1319 def new_instance_interface(self, instance_interface_dict, tenant_id, instance_scenario_id = None):
1320 return self._new_row_internal('instance_interfaces', instance_interface_dict, tenant_id, add_uuid=True, root_uuid=instance_scenario_id, log=True)
1321
1322 def update_instance_interface(self, instance_interface_dict):
1323 #TODO:
1324 return
1325
1326 def delete_instance_interface(self, instance_interface_dict):
1327 #TODO:
1328 return
1329
1330 def update_datacenter_nets(self, datacenter_id, new_net_list=[]):
1331 ''' Removes the old and adds the new net list at datacenter list for one datacenter.
1332 Attribute
1333 datacenter_id: uuid of the datacenter to act upon
1334 table: table where to insert
1335 new_net_list: the new values to be inserted. If empty it only deletes the existing nets
1336 Return: (Inserted items, Deleted items) if OK, (-Error, text) if error
1337 '''
1338 for retry_ in range(0,2):
1339 created_time = time.time()
1340 try:
1341 with self.con:
1342 self.cur = self.con.cursor()
1343 cmd="DELETE FROM datacenter_nets WHERE datacenter_id='%s'" % datacenter_id
1344 print cmd
1345 self.cur.execute(cmd)
1346 deleted = self.cur.rowcount
1347 for new_net in new_net_list:
1348 created_time += 0.00001
1349 self._new_row_internal('datacenter_nets', new_net, tenant_id=None, add_uuid=True, created_time=created_time)
1350 return len (new_net_list), deleted
1351 except (mdb.Error, AttributeError), e:
1352 print "nfvo_db.update_datacenter_nets DB Exception %d: %s" % (e.args[0], e.args[1])
1353 r,c = self.format_error(e)
1354 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1355