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