Merge "v0.4.61 fixed 37 Deploying multisite get properly the information from sites...
[osm/RO.git] / db_base.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 Base class for openmano database manipulation
26 '''
27 __author__="Alfonso Tierno"
28 __date__ ="$4-Apr-2016 10:05:01$"
29
30 import MySQLdb as mdb
31 import uuid as myUuid
32 import utils as af
33 import json
34 #import yaml
35 import time
36 import logging
37 import datetime
38 from jsonschema import validate as js_v, exceptions as js_e
39
40 HTTP_Bad_Request = 400
41 HTTP_Unauthorized = 401
42 HTTP_Not_Found = 404
43 HTTP_Method_Not_Allowed = 405
44 HTTP_Request_Timeout = 408
45 HTTP_Conflict = 409
46 HTTP_Service_Unavailable = 503
47 HTTP_Internal_Server_Error = 500
48
49 def _check_valid_uuid(uuid):
50 id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"}
51 id_schema2 = {"type" : "string", "pattern": "^[a-fA-F0-9]{32}$"}
52 try:
53 js_v(uuid, id_schema)
54 return True
55 except js_e.ValidationError:
56 try:
57 js_v(uuid, id_schema2)
58 return True
59 except js_e.ValidationError:
60 return False
61 return False
62
63 def _convert_datetime2str(var):
64 '''Converts a datetime variable to a string with the format '%Y-%m-%dT%H:%i:%s'
65 It enters recursively in the dict var finding this kind of variables
66 '''
67 if type(var) is dict:
68 for k,v in var.items():
69 if type(v) is datetime.datetime:
70 var[k]= v.strftime('%Y-%m-%dT%H:%M:%S')
71 elif type(v) is dict or type(v) is list or type(v) is tuple:
72 _convert_datetime2str(v)
73 if len(var) == 0: return True
74 elif type(var) is list or type(var) is tuple:
75 for v in var:
76 _convert_datetime2str(v)
77
78 def _convert_bandwidth(data, reverse=False):
79 '''Check the field bandwidth recursivelly and when found, it removes units and convert to number
80 It assumes that bandwidth is well formed
81 Attributes:
82 'data': dictionary bottle.FormsDict variable to be checked. None or empty is consideted valid
83 'reverse': by default convert form str to int (Mbps), if True it convert from number to units
84 Return:
85 None
86 '''
87 if type(data) is dict:
88 for k in data.keys():
89 if type(data[k]) is dict or type(data[k]) is tuple or type(data[k]) is list:
90 _convert_bandwidth(data[k], reverse)
91 if "bandwidth" in data:
92 try:
93 value=str(data["bandwidth"])
94 if not reverse:
95 pos = value.find("bps")
96 if pos>0:
97 if value[pos-1]=="G": data["bandwidth"] = int(data["bandwidth"][:pos-1]) * 1000
98 elif value[pos-1]=="k": data["bandwidth"]= int(data["bandwidth"][:pos-1]) / 1000
99 else: data["bandwidth"]= int(data["bandwidth"][:pos-1])
100 else:
101 value = int(data["bandwidth"])
102 if value % 1000 == 0: data["bandwidth"]=str(value/1000) + " Gbps"
103 else: data["bandwidth"]=str(value) + " Mbps"
104 except:
105 print "convert_bandwidth exception for type", type(data["bandwidth"]), " data", data["bandwidth"]
106 return
107 if type(data) is tuple or type(data) is list:
108 for k in data:
109 if type(k) is dict or type(k) is tuple or type(k) is list:
110 _convert_bandwidth(k, reverse)
111
112 def _convert_str2boolean(data, items):
113 '''Check recursively the content of data, and if there is an key contained in items, convert value from string to boolean
114 Done recursively
115 Attributes:
116 'data': dictionary variable to be checked. None or empty is considered valid
117 'items': tuple of keys to convert
118 Return:
119 None
120 '''
121 if type(data) is dict:
122 for k in data.keys():
123 if type(data[k]) is dict or type(data[k]) is tuple or type(data[k]) is list:
124 _convert_str2boolean(data[k], items)
125 if k in items:
126 if type(data[k]) is str:
127 if data[k]=="false" or data[k]=="False": data[k]=False
128 elif data[k]=="true" or data[k]=="True": data[k]=True
129 if type(data) is tuple or type(data) is list:
130 for k in data:
131 if type(k) is dict or type(k) is tuple or type(k) is list:
132 _convert_str2boolean(k, items)
133
134 class db_base_Exception(Exception):
135 '''Common Exception for all database exceptions'''
136
137 def __init__(self, message, http_code=HTTP_Bad_Request):
138 Exception.__init__(self, message)
139 self.http_code = http_code
140
141 class db_base():
142 tables_with_created_field=()
143
144 def __init__(self, host=None, user=None, passwd=None, database=None, log_name='db', log_level=None):
145 self.host = host
146 self.user = user
147 self.passwd = passwd
148 self.database = database
149 self.con = None
150 self.log_level=log_level
151 self.logger = logging.getLogger(log_name)
152 if self.log_level:
153 self.logger.setLevel( getattr(logging, log_level) )
154
155 def connect(self, host=None, user=None, passwd=None, database=None):
156 '''Connect to specific data base.
157 The first time a valid host, user, passwd and database must be provided,
158 Following calls can skip this parameters
159 '''
160 try:
161 if host: self.host = host
162 if user: self.user = user
163 if passwd: self.passwd = passwd
164 if database: self.database = database
165
166 self.con = mdb.connect(self.host, self.user, self.passwd, self.database)
167 print "DB: connected to %s@%s -> %s" % (self.user, self.host, self.database)
168 except mdb.Error, e:
169 raise db_base_Exception("Cannot connect to DB {}@{} -> {} Error {}: {}".format(self.user, self.host, self.database, e.args[0], e.args[1]),
170 code = HTTP_Internal_Server_Error )
171
172 def get_db_version(self):
173 ''' Obtain the database schema version.
174 Return: (negative, text) if error or version 0.0 where schema_version table is missing
175 (version_int, version_text) if ok
176 '''
177 cmd = "SELECT version_int,version FROM schema_version"
178 tries = 2
179 while tries:
180 try:
181 with self.con:
182 self.cur = self.con.cursor()
183 self.logger.debug(cmd)
184 self.cur.execute(cmd)
185 rows = self.cur.fetchall()
186 highest_version_int=0
187 highest_version=""
188 for row in rows: #look for the latest version
189 if row[0]>highest_version_int:
190 highest_version_int, highest_version = row[0:2]
191 return highest_version_int, highest_version
192 except (mdb.Error, AttributeError) as e:
193 #self.logger.error("get_db_version DB Exception %d: %s. Command %s",e.args[0], e.args[1], cmd)
194 self._format_error(e, tries)
195 tries -= 1
196
197 def disconnect(self):
198 '''disconnect from specific data base'''
199 try:
200 self.con.close()
201 self.con = None
202 except mdb.Error as e:
203 self.logger.error("while disconnecting from DB: Error %d: %s",e.args[0], e.args[1])
204 return
205 except AttributeError as e: #self.con not defined
206 if e[0][-5:] == "'con'":
207 self.logger.warn("while disconnecting from DB: Error %d: %s",e.args[0], e.args[1])
208 return
209 else:
210 raise
211
212 def _format_error(self, e, tries=1, command=None, extra=None):
213 '''Creates a text error base on the produced exception
214 Params:
215 e: mdb exception
216 retry: in case of timeout, if reconnecting to database and retry, or raise and exception
217 cmd: database command that produce the exception
218 command: if the intention is update or delete
219 extra: extra information to add to some commands
220 Return
221 HTTP error in negative, formatted error text
222 '''
223 if isinstance(e,AttributeError ):
224 raise db_base_Exception("DB Exception " + str(e), HTTP_Internal_Server_Error)
225 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
226 if tries>1:
227 self.logger.warn("DB Exception '%s'. Retry", str(e))
228 #reconnect
229 self.connect()
230 return
231 else:
232 raise db_base_Exception("Database connection timeout Try Again", HTTP_Request_Timeout)
233
234 fk=e.args[1].find("foreign key constraint fails")
235 if fk>=0:
236 if command=="update":
237 raise db_base_Exception("tenant_id '{}' not found.".format(extra), HTTP_Not_Found)
238 elif command=="delete":
239 raise db_base_Exception("Resource is not free. There are {} that prevent deleting it.".format(extra), HTTP_Conflict)
240 de = e.args[1].find("Duplicate entry")
241 fk = e.args[1].find("for key")
242 uk = e.args[1].find("Unknown column")
243 wc = e.args[1].find("in 'where clause'")
244 fl = e.args[1].find("in 'field list'")
245 #print de, fk, uk, wc,fl
246 if de>=0:
247 if fk>=0: #error 1062
248 raise db_base_Exception("Value {} already in use for {}".format(e.args[1][de+15:fk], e.args[1][fk+7:]), HTTP_Conflict)
249 if uk>=0:
250 if wc>=0:
251 raise db_base_Exception("Field {} can not be used for filtering".format(e.args[1][uk+14:wc]), HTTP_Bad_Request)
252 if fl>=0:
253 raise db_base_Exception("Field {} does not exist".format(e.args[1][uk+14:wc]), HTTP_Bad_Request)
254 raise db_base_Exception("Database internal Error {}: {}".format(e.args[0], e.args[1]), HTTP_Internal_Server_Error)
255
256 def __str2db_format(self, data):
257 '''Convert string data to database format.
258 If data is None it returns the 'Null' text,
259 otherwise it returns the text surrounded by quotes ensuring internal quotes are escaped.
260 '''
261 if data==None:
262 return 'Null'
263 else:
264 return json.dumps(str(data))
265
266 def __tuple2db_format_set(self, data):
267 '''Compose the needed text for a SQL SET, parameter 'data' is a pair tuple (A,B),
268 and it returns the text 'A="B"', where A is a field of a table and B is the value
269 If B is None it returns the 'A=Null' text, without surrounding Null by quotes
270 If B is not None it returns the text "A='B'" or 'A="B"' where B is surrounded by quotes,
271 and it ensures internal quotes of B are escaped.
272 '''
273 if data[1]==None:
274 return str(data[0]) + "=Null"
275 else:
276 return str(data[0]) + '=' + json.dumps(str(data[1]))
277
278 def __tuple2db_format_where(self, data):
279 '''Compose the needed text for a SQL WHERE, parameter 'data' is a pair tuple (A,B),
280 and it returns the text 'A="B"', where A is a field of a table and B is the value
281 If B is None it returns the 'A is Null' text, without surrounding Null by quotes
282 If B is not None it returns the text "A='B'" or 'A="B"' where B is surrounded by quotes,
283 and it ensures internal quotes of B are escaped.
284 '''
285 if data[1]==None:
286 return str(data[0]) + " is Null"
287
288 # if type(data[1]) is tuple: #this can only happen in a WHERE_OR clause
289 # text =[]
290 # for d in data[1]:
291 # if d==None:
292 # text.append(str(data[0]) + " is Null")
293 # continue
294 # out=str(d)
295 # if "'" not in out:
296 # text.append( str(data[0]) + "='" + out + "'" )
297 # elif '"' not in out:
298 # text.append( str(data[0]) + '="' + out + '"' )
299 # else:
300 # text.append( str(data[0]) + '=' + json.dumps(out) )
301 # return " OR ".join(text)
302
303 out=str(data[1])
304 return str(data[0]) + '=' + json.dumps(out)
305
306 def __tuple2db_format_where_not(self, data):
307 '''Compose the needed text for a SQL WHERE(not). parameter 'data' is a pair tuple (A,B),
308 and it returns the text 'A<>"B"', where A is a field of a table and B is the value
309 If B is None it returns the 'A is not Null' text, without surrounding Null by quotes
310 If B is not None it returns the text "A<>'B'" or 'A<>"B"' where B is surrounded by quotes,
311 and it ensures internal quotes of B are escaped.
312 '''
313 if data[1]==None:
314 return str(data[0]) + " is not Null"
315 out=str(data[1])
316 return str(data[0]) + '<>' + json.dumps(out)
317
318 def __remove_quotes(self, data):
319 '''remove single quotes ' of any string content of data dictionary'''
320 for k,v in data.items():
321 if type(v) == str:
322 if "'" in v:
323 data[k] = data[k].replace("'","_")
324
325 def _update_rows(self, table, UPDATE, WHERE, modified_time=0):
326 ''' Update one or several rows into a table.
327 Atributes
328 UPDATE: dictionary with the key: value to change
329 table: table where to update
330 WHERE: dictionary of elements to update
331 Return: the number of updated rows, exception if error
332 '''
333 #gettting uuid
334 values = ",".join(map(self.__tuple2db_format_set, UPDATE.iteritems() ))
335 if modified_time:
336 values += ",modified_at={:f}".format(modified_time)
337 cmd= "UPDATE " + table +" SET " + values +\
338 " WHERE " + " and ".join(map(self.__tuple2db_format_where, WHERE.iteritems() ))
339 self.logger.debug(cmd)
340 self.cur.execute(cmd)
341 return self.cur.rowcount
342
343 def _new_row_internal(self, table, INSERT, add_uuid=False, root_uuid=None, created_time=0):
344 ''' Add one row into a table. It DOES NOT begin or end the transaction, so self.con.cursor must be created
345 Attribute
346 INSERT: dictionary with the key:value to insert
347 table: table where to insert
348 add_uuid: if True, it will create an uuid key entry at INSERT if not provided
349 created_time: time to add to the created_time column
350 It checks presence of uuid and add one automatically otherwise
351 Return: uuid
352 '''
353
354 if add_uuid:
355 #create uuid if not provided
356 if 'uuid' not in INSERT:
357 uuid = INSERT['uuid'] = str(myUuid.uuid1()) # create_uuid
358 else:
359 uuid = str(INSERT['uuid'])
360 else:
361 uuid=None
362 if add_uuid:
363 #defining root_uuid if not provided
364 if root_uuid is None:
365 root_uuid = uuid
366 if created_time:
367 created_at = created_time
368 else:
369 created_at=time.time()
370 #inserting new uuid
371 cmd = "INSERT INTO uuids (uuid, root_uuid, used_at, created_at) VALUES ('{:s}','{:s}','{:s}', {:f})".format(uuid, root_uuid, table, created_at)
372 self.logger.debug(cmd)
373 self.cur.execute(cmd)
374 #insertion
375 cmd= "INSERT INTO " + table +" SET " + \
376 ",".join(map(self.__tuple2db_format_set, INSERT.iteritems() ))
377 if created_time:
378 cmd += ",created_at=%f" % created_time
379 self.logger.debug(cmd)
380 self.cur.execute(cmd)
381 self.cur.rowcount
382 return uuid
383
384 def _get_rows(self,table,uuid):
385 cmd = "SELECT * FROM {} WHERE uuid='{}'".format(str(table), str(uuid))
386 self.logger.debug(cmd)
387 self.cur.execute(cmd)
388 rows = self.cur.fetchall()
389 return rows
390
391 def new_row(self, table, INSERT, add_uuid=False, created_time=0):
392 ''' Add one row into a table.
393 Attribute
394 INSERT: dictionary with the key: value to insert
395 table: table where to insert
396 tenant_id: only useful for logs. If provided, logs will use this tenant_id
397 add_uuid: if True, it will create an uuid key entry at INSERT if not provided
398 It checks presence of uuid and add one automatically otherwise
399 Return: (result, uuid) where result can be 0 if error, or 1 if ok
400 '''
401 if table in self.tables_with_created_field and created_time==0:
402 created_time=time.time()
403 tries = 2
404 while tries:
405 try:
406 with self.con:
407 self.cur = self.con.cursor()
408 return self._new_row_internal(table, INSERT, add_uuid, None, created_time)
409
410 except (mdb.Error, AttributeError) as e:
411 self._format_error(e, tries)
412 tries -= 1
413
414 def update_rows(self, table, UPDATE, WHERE, modified_time=0):
415 ''' Update one or several rows into a table.
416 Atributes
417 UPDATE: dictionary with the key: value to change
418 table: table where to update
419 WHERE: dictionary of elements to update
420 Return: (result, descriptive text) where result indicates the number of updated files
421 '''
422 if table in self.tables_with_created_field and modified_time==0:
423 modified_time=time.time()
424 tries = 2
425 while tries:
426 try:
427 with self.con:
428 self.cur = self.con.cursor()
429 return self._update_rows(table, UPDATE, WHERE)
430
431 except (mdb.Error, AttributeError) as e:
432 self._format_error(e, tries)
433 tries -= 1
434
435 def delete_row_by_id(self, table, uuid):
436 tries = 2
437 while tries:
438 try:
439 with self.con:
440 #delete host
441 self.cur = self.con.cursor()
442 cmd = "DELETE FROM {} WHERE uuid = '{}'".format(table, uuid)
443 self.logger.debug(cmd)
444 self.cur.execute(cmd)
445 deleted = self.cur.rowcount
446 if deleted:
447 #delete uuid
448 self.cur = self.con.cursor()
449 cmd = "DELETE FROM uuids WHERE root_uuid = '{}'".format(uuid)
450 self.logger.debug(cmd)
451 self.cur.execute(cmd)
452 return deleted
453 except (mdb.Error, AttributeError) as e:
454 self._format_error(e, tries, "delete", "dependencies")
455 tries -= 1
456
457 def delete_row(self, **sql_dict):
458 ''' Deletes rows from a table.
459 Attribute sql_dir: dictionary with the following key: value
460 'FROM': string of table name (Mandatory)
461 'WHERE': dict of key:values, translated to key=value AND ... (Optional)
462 'WHERE_NOT': dict of key:values, translated to key<>value AND ... (Optional)
463 if value is None, it is translated to key is not null
464 'LIMIT': limit of number of rows (Optional)
465 Return: the number of deleted or exception if error
466 '''
467 #print sql_dict
468 from_ = "FROM " + str(sql_dict['FROM'])
469 #print 'from_', from_
470 if 'WHERE' in sql_dict and len(sql_dict['WHERE']) > 0:
471 w=sql_dict['WHERE']
472 where_ = "WHERE " + " AND ".join(map(self.__tuple2db_format_where, w.iteritems()))
473 else: where_ = ""
474 if 'WHERE_NOT' in sql_dict and len(sql_dict['WHERE_NOT']) > 0:
475 w=sql_dict['WHERE_NOT']
476 where_2 = " AND ".join(map(self.__tuple2db_format_where_not, w.iteritems()))
477 if len(where_)==0: where_ = "WHERE " + where_2
478 else: where_ = where_ + " AND " + where_2
479 #print 'where_', where_
480 limit_ = "LIMIT " + str(sql_dict['LIMIT']) if 'LIMIT' in sql_dict else ""
481 #print 'limit_', limit_
482 cmd = " ".join( ("DELETE", from_, where_, limit_) )
483 tries = 2
484 while tries:
485 try:
486 with self.con:
487 self.cur = self.con.cursor()
488 self.logger.debug(cmd)
489 self.cur.execute(cmd)
490 deleted = self.cur.rowcount
491 return deleted
492 except (mdb.Error, AttributeError) as e:
493 self._format_error(e, tries)
494 tries -= 1
495
496 def get_rows_by_id(self, table, uuid):
497 '''get row from a table based on uuid'''
498 tries = 2
499 while tries:
500 try:
501 with self.con:
502 self.cur = self.con.cursor(mdb.cursors.DictCursor)
503 cmd="SELECT * FROM {} where uuid='{}'".format(str(table), str(uuid))
504 self.logger.debug(cmd)
505 self.cur.execute(cmd)
506 rows = self.cur.fetchall()
507 return rows
508 except (mdb.Error, AttributeError) as e:
509 self._format_error(e, tries)
510 tries -= 1
511
512 def get_rows(self, **sql_dict):
513 ''' Obtain rows from a table.
514 Attribute sql_dir: dictionary with the following key: value
515 'SELECT': list or tuple of fields to retrieve) (by default all)
516 'FROM': string of table name (Mandatory)
517 'WHERE': dict of key:values, translated to key=value (key is null) AND ... (Optional)
518 'WHERE_NOT': dict of key:values, translated to key<>value (key is not null) AND ... (Optional)
519 'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
520 'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional)
521 'LIMIT': limit of number of rows (Optional)
522 'ORDER_BY': list or tuple of fields to order
523 Return: a list with dictionaries at each row
524 '''
525 #print sql_dict
526 select_= "SELECT " + ("*" if 'SELECT' not in sql_dict else ",".join(map(str,sql_dict['SELECT'])) )
527 #print 'select_', select_
528 from_ = "FROM " + str(sql_dict['FROM'])
529 #print 'from_', from_
530 where_and = ""
531 where_or = ""
532 w=sql_dict.get('WHERE')
533 if w:
534 where_and = " AND ".join(map(self.__tuple2db_format_where, w.iteritems() ))
535 w=sql_dict.get('WHERE_NOT')
536 if w:
537 if where_and: where_and += " AND "
538 where_and += " AND ".join(map(self.__tuple2db_format_where_not, w.iteritems() ) )
539 w=sql_dict.get('WHERE_OR')
540 if w:
541 where_or = " OR ".join(map(self.__tuple2db_format_where, w.iteritems() ))
542 if where_and and where_or:
543 if sql_dict.get("WHERE_AND_OR") == "AND":
544 where_ = "WHERE " + where_and + " AND (" + where_or + ")"
545 else:
546 where_ = "WHERE (" + where_and + ") OR " + where_or
547 elif where_and and not where_or:
548 where_ = "WHERE " + where_and
549 elif not where_and and where_or:
550 where_ = "WHERE " + where_or
551 else:
552 where_ = ""
553 #print 'where_', where_
554 limit_ = "LIMIT " + str(sql_dict['LIMIT']) if 'LIMIT' in sql_dict else ""
555 order_ = "ORDER BY " + ",".join(map(str,sql_dict['SELECT'])) if 'ORDER_BY' in sql_dict else ""
556
557 #print 'limit_', limit_
558 cmd = " ".join( (select_, from_, where_, limit_, order_) )
559 tries = 2
560 while tries:
561 try:
562 with self.con:
563 self.cur = self.con.cursor(mdb.cursors.DictCursor)
564 self.logger.debug(cmd)
565 self.cur.execute(cmd)
566 rows = self.cur.fetchall()
567 return rows
568 except (mdb.Error, AttributeError) as e:
569 self._format_error(e, tries)
570 tries -= 1
571
572 def get_table_by_uuid_name(self, table, uuid_name, error_item_text=None, allow_serveral=False, WHERE_OR={}, WHERE_AND_OR="OR"):
573 ''' Obtain One row from a table based on name or uuid.
574 Attribute:
575 table: string of table name
576 uuid_name: name or uuid. If not uuid format is found, it is considered a name
577 allow_severeral: if False return ERROR if more than one row are founded
578 error_item_text: in case of error it identifies the 'item' name for a proper output text
579 'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
580 'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional
581 Return: if allow_several==False, a dictionary with this row, or error if no item is found or more than one is found
582 if allow_several==True, a list of dictionaries with the row or rows, error if no item is found
583 '''
584
585 if error_item_text==None:
586 error_item_text = table
587 what = 'uuid' if af.check_valid_uuid(uuid_name) else 'name'
588 cmd = " SELECT * FROM {} WHERE {}='{}'".format(table, what, uuid_name)
589 if WHERE_OR:
590 where_or = " OR ".join(map(self.__tuple2db_format_where, WHERE_OR.iteritems() ))
591 if WHERE_AND_OR == "AND":
592 cmd += " AND (" + where_or + ")"
593 else:
594 cmd += " OR " + where_or
595
596
597 tries = 2
598 while tries:
599 try:
600 with self.con:
601 self.cur = self.con.cursor(mdb.cursors.DictCursor)
602 self.logger.debug(cmd)
603 self.cur.execute(cmd)
604 number = self.cur.rowcount
605 if number==0:
606 return -HTTP_Not_Found, "No %s found with %s '%s'" %(error_item_text, what, uuid_name)
607 elif number>1 and not allow_serveral:
608 return -HTTP_Bad_Request, "More than one %s found with %s '%s'" %(error_item_text, what, uuid_name)
609 if allow_serveral:
610 rows = self.cur.fetchall()
611 else:
612 rows = self.cur.fetchone()
613 return rows
614 except (mdb.Error, AttributeError) as e:
615 self._format_error(e, tries)
616 tries -= 1
617
618 def get_uuid(self, uuid):
619 '''check in the database if this uuid is already present'''
620 for retry_ in range(0,2):
621 try:
622 with self.con:
623 self.cur = self.con.cursor(mdb.cursors.DictCursor)
624 self.cur.execute("SELECT * FROM uuids where uuid='" + str(uuid) + "'")
625 rows = self.cur.fetchall()
626 return self.cur.rowcount, rows
627 except (mdb.Error, AttributeError) as e:
628 print "nfvo_db.get_uuid DB Exception %d: %s" % (e.args[0], e.args[1])
629 r,c = self._format_error(e)
630 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
631
632 def get_uuid_from_name(self, table, name):
633 '''Searchs in table the name and returns the uuid
634 '''
635 tries = 2
636 while tries:
637 try:
638 with self.con:
639 self.cur = self.con.cursor(mdb.cursors.DictCursor)
640 where_text = "name='" + name +"'"
641 self.cur.execute("SELECT * FROM " + table + " WHERE "+ where_text)
642 rows = self.cur.fetchall()
643 if self.cur.rowcount==0:
644 return 0, "Name %s not found in table %s" %(name, table)
645 elif self.cur.rowcount>1:
646 return self.cur.rowcount, "More than one VNF with name %s found in table %s" %(name, table)
647 return self.cur.rowcount, rows[0]["uuid"]
648 except (mdb.Error, AttributeError) as e:
649 self._format_error(e, tries)
650 tries -= 1
651