1 # -*- coding: utf-8 -*-
4 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
5 # This file is part of openmano
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
12 # http://www.apache.org/licenses/LICENSE-2.0
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
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact with: nfvlabs@tid.es
25 Base class for openmano database manipulation
27 __author__
="Alfonso Tierno"
28 __date__
="$4-Apr-2016 10:05:01$"
38 from jsonschema
import validate
as js_v
, exceptions
as js_e
40 HTTP_Bad_Request
= 400
41 HTTP_Unauthorized
= 401
43 HTTP_Method_Not_Allowed
= 405
44 HTTP_Request_Timeout
= 408
46 HTTP_Service_Unavailable
= 503
47 HTTP_Internal_Server_Error
= 500
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}$"}
55 except js_e
.ValidationError
:
57 js_v(uuid
, id_schema2
)
59 except js_e
.ValidationError
:
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
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:
76 _convert_datetime2str(v
)
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
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
87 if type(data
) is dict:
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
:
93 value
=str(data
["bandwidth"])
95 pos
= value
.find("bps")
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])
101 value
= int(data
["bandwidth"])
102 if value
% 1000 == 0: data
["bandwidth"]=str(value
/1000) + " Gbps"
103 else: data
["bandwidth"]=str(value
) + " Mbps"
106 logger
.error("convert_bandwidth exception for type '%s' data '%s'", type(data
["bandwidth"]), data
["bandwidth"])
108 if type(data
) is tuple or type(data
) is list:
110 if type(k
) is dict or type(k
) is tuple or type(k
) is list:
111 _convert_bandwidth(k
, reverse
, logger
)
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
117 'data': dictionary variable to be checked. None or empty is considered valid
118 'items': tuple of keys to convert
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
)
127 if type(data
[k
]) is str:
128 if data
[k
]=="false" or data
[k
]=="False" or data
[k
]=="0": data
[k
]=False
129 elif data
[k
]=="true" or data
[k
]=="True" or data
[k
]=="1": data
[k
]=True
130 elif type(data
[k
]) is int:
131 if data
[k
]==0: data
[k
]=False
132 elif data
[k
]==1: data
[k
]=True
133 if type(data
) is tuple or type(data
) is list:
135 if type(k
) is dict or type(k
) is tuple or type(k
) is list:
136 _convert_str2boolean(k
, items
)
138 class db_base_Exception(Exception):
139 '''Common Exception for all database exceptions'''
141 def __init__(self
, message
, http_code
=HTTP_Bad_Request
):
142 Exception.__init
__(self
, message
)
143 self
.http_code
= http_code
146 tables_with_created_field
=()
148 def __init__(self
, host
=None, user
=None, passwd
=None, database
=None, log_name
='db', log_level
=None):
152 self
.database
= database
154 self
.log_level
=log_level
155 self
.logger
= logging
.getLogger(log_name
)
157 self
.logger
.setLevel( getattr(logging
, log_level
) )
159 def connect(self
, host
=None, user
=None, passwd
=None, database
=None):
160 '''Connect to specific data base.
161 The first time a valid host, user, passwd and database must be provided,
162 Following calls can skip this parameters
165 if host
: self
.host
= host
166 if user
: self
.user
= user
167 if passwd
: self
.passwd
= passwd
168 if database
: self
.database
= database
170 self
.con
= mdb
.connect(self
.host
, self
.user
, self
.passwd
, self
.database
)
171 self
.logger
.debug("DB: connected to '%s' at '%s@%s'", self
.database
, self
.user
, self
.host
)
172 except mdb
.Error
as e
:
173 raise db_base_Exception("Cannot connect to DataBase '{}' at '{}@{}' Error {}: {}".format(
174 self
.database
, self
.user
, self
.host
, e
.args
[0], e
.args
[1]),
175 http_code
= HTTP_Unauthorized
)
177 def get_db_version(self
):
178 ''' Obtain the database schema version.
179 Return: (negative, text) if error or version 0.0 where schema_version table is missing
180 (version_int, version_text) if ok
182 cmd
= "SELECT version_int,version FROM schema_version"
187 self
.cur
= self
.con
.cursor()
188 self
.logger
.debug(cmd
)
189 self
.cur
.execute(cmd
)
190 rows
= self
.cur
.fetchall()
191 highest_version_int
=0
193 for row
in rows
: #look for the latest version
194 if row
[0]>highest_version_int
:
195 highest_version_int
, highest_version
= row
[0:2]
196 return highest_version_int
, highest_version
197 except (mdb
.Error
, AttributeError) as e
:
198 #self.logger.error("get_db_version DB Exception %d: %s. Command %s",e.args[0], e.args[1], cmd)
199 self
._format
_error
(e
, tries
)
202 def disconnect(self
):
203 '''disconnect from specific data base'''
207 except mdb
.Error
as e
:
208 self
.logger
.error("while disconnecting from DB: Error %d: %s",e
.args
[0], e
.args
[1])
210 except AttributeError as e
: #self.con not defined
211 if e
[0][-5:] == "'con'":
212 self
.logger
.warn("while disconnecting from DB: Error %d: %s",e
.args
[0], e
.args
[1])
217 def _format_error(self
, e
, tries
=1, command
=None, extra
=None):
218 '''Creates a text error base on the produced exception
221 retry: in case of timeout, if reconnecting to database and retry, or raise and exception
222 cmd: database command that produce the exception
223 command: if the intention is update or delete
224 extra: extra information to add to some commands
226 HTTP error in negative, formatted error text
228 if isinstance(e
,AttributeError ):
229 raise db_base_Exception("DB Exception " + str(e
), HTTP_Internal_Server_Error
)
230 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
232 self
.logger
.warn("DB Exception '%s'. Retry", str(e
))
237 raise db_base_Exception("Database connection timeout Try Again", HTTP_Request_Timeout
)
239 fk
=e
.args
[1].find("foreign key constraint fails")
241 if command
=="update":
242 raise db_base_Exception("tenant_id '{}' not found.".format(extra
), HTTP_Not_Found
)
243 elif command
=="delete":
244 raise db_base_Exception("Resource is not free. There are {} that prevent deleting it.".format(extra
), HTTP_Conflict
)
245 de
= e
.args
[1].find("Duplicate entry")
246 fk
= e
.args
[1].find("for key")
247 uk
= e
.args
[1].find("Unknown column")
248 wc
= e
.args
[1].find("in 'where clause'")
249 fl
= e
.args
[1].find("in 'field list'")
250 #print de, fk, uk, wc,fl
252 if fk
>=0: #error 1062
253 raise db_base_Exception("Value {} already in use for {}".format(e
.args
[1][de
+15:fk
], e
.args
[1][fk
+7:]), HTTP_Conflict
)
256 raise db_base_Exception("Field {} can not be used for filtering".format(e
.args
[1][uk
+14:wc
]), HTTP_Bad_Request
)
258 raise db_base_Exception("Field {} does not exist".format(e
.args
[1][uk
+14:wc
]), HTTP_Bad_Request
)
259 raise db_base_Exception("Database internal Error {}: {}".format(e
.args
[0], e
.args
[1]), HTTP_Internal_Server_Error
)
261 def __str2db_format(self
, data
):
262 '''Convert string data to database format.
263 If data is None it returns the 'Null' text,
264 otherwise it returns the text surrounded by quotes ensuring internal quotes are escaped.
268 elif isinstance(data
[1], str):
269 return json
.dumps(data
)
271 return json
.dumps(str(data
))
273 def __tuple2db_format_set(self
, data
):
274 '''Compose the needed text for a SQL SET, parameter 'data' is a pair tuple (A,B),
275 and it returns the text 'A="B"', where A is a field of a table and B is the value
276 If B is None it returns the 'A=Null' text, without surrounding Null by quotes
277 If B is not None it returns the text "A='B'" or 'A="B"' where B is surrounded by quotes,
278 and it ensures internal quotes of B are escaped.
281 return str(data
[0]) + "=Null"
282 elif isinstance(data
[1], str):
283 return str(data
[0]) + '=' + json
.dumps(data
[1])
285 return str(data
[0]) + '=' + json
.dumps(str(data
[1]))
287 def __tuple2db_format_where(self
, data
):
288 '''Compose the needed text for a SQL WHERE, parameter 'data' is a pair tuple (A,B),
289 and it returns the text 'A="B"', where A is a field of a table and B is the value
290 If B is None it returns the 'A is Null' text, without surrounding Null by quotes
291 If B is not None it returns the text "A='B'" or 'A="B"' where B is surrounded by quotes,
292 and it ensures internal quotes of B are escaped.
295 return str(data
[0]) + " is Null"
296 elif isinstance(data
[1], str):
297 return str(data
[0]) + '=' + json
.dumps(data
[1])
299 return str(data
[0]) + '=' + json
.dumps(str(data
[1]))
301 def __tuple2db_format_where_not(self
, data
):
302 '''Compose the needed text for a SQL WHERE(not). parameter 'data' is a pair tuple (A,B),
303 and it returns the text 'A<>"B"', where A is a field of a table and B is the value
304 If B is None it returns the 'A is not Null' text, without surrounding Null by quotes
305 If B is not None it returns the text "A<>'B'" or 'A<>"B"' where B is surrounded by quotes,
306 and it ensures internal quotes of B are escaped.
309 return str(data
[0]) + " is not Null"
310 elif isinstance(data
[1], str):
311 return str(data
[0]) + '<>' + json
.dumps(data
[1])
313 return str(data
[0]) + '<>' + json
.dumps(str(data
[1]))
315 def __remove_quotes(self
, data
):
316 '''remove single quotes ' of any string content of data dictionary'''
317 for k
,v
in data
.items():
320 data
[k
] = data
[k
].replace("'","_")
322 def _update_rows(self
, table
, UPDATE
, WHERE
, modified_time
=0):
323 ''' Update one or several rows into a table.
325 UPDATE: dictionary with the key: value to change
326 table: table where to update
327 WHERE: dictionary of elements to update
328 Return: the number of updated rows, exception if error
331 values
= ",".join(map(self
.__tuple
2db
_format
_set
, UPDATE
.iteritems() ))
333 values
+= ",modified_at={:f}".format(modified_time
)
334 cmd
= "UPDATE " + table
+" SET " + values
+\
335 " WHERE " + " and ".join(map(self
.__tuple
2db
_format
_where
, WHERE
.iteritems() ))
336 self
.logger
.debug(cmd
)
337 self
.cur
.execute(cmd
)
338 return self
.cur
.rowcount
340 def _new_row_internal(self
, table
, INSERT
, add_uuid
=False, root_uuid
=None, created_time
=0):
341 ''' Add one row into a table. It DOES NOT begin or end the transaction, so self.con.cursor must be created
343 INSERT: dictionary with the key:value to insert
344 table: table where to insert
345 add_uuid: if True, it will create an uuid key entry at INSERT if not provided
346 created_time: time to add to the created_time column
347 It checks presence of uuid and add one automatically otherwise
352 #create uuid if not provided
353 if 'uuid' not in INSERT
:
354 uuid
= INSERT
['uuid'] = str(myUuid
.uuid1()) # create_uuid
356 uuid
= str(INSERT
['uuid'])
360 #defining root_uuid if not provided
361 if root_uuid
is None:
364 created_at
= created_time
366 created_at
=time
.time()
368 cmd
= "INSERT INTO uuids (uuid, root_uuid, used_at, created_at) VALUES ('{:s}','{:s}','{:s}', {:f})".format(uuid
, root_uuid
, table
, created_at
)
369 self
.logger
.debug(cmd
)
370 self
.cur
.execute(cmd
)
372 cmd
= "INSERT INTO " + table
+" SET " + \
373 ",".join(map(self
.__tuple
2db
_format
_set
, INSERT
.iteritems() ))
375 cmd
+= ",created_at=%f" % created_time
376 self
.logger
.debug(cmd
)
377 self
.cur
.execute(cmd
)
381 def _get_rows(self
,table
,uuid
):
382 cmd
= "SELECT * FROM {} WHERE uuid='{}'".format(str(table
), str(uuid
))
383 self
.logger
.debug(cmd
)
384 self
.cur
.execute(cmd
)
385 rows
= self
.cur
.fetchall()
388 def new_row(self
, table
, INSERT
, add_uuid
=False, created_time
=0):
389 ''' Add one row into a table.
391 INSERT: dictionary with the key: value to insert
392 table: table where to insert
393 tenant_id: only useful for logs. If provided, logs will use this tenant_id
394 add_uuid: if True, it will create an uuid key entry at INSERT if not provided
395 It checks presence of uuid and add one automatically otherwise
396 Return: (result, uuid) where result can be 0 if error, or 1 if ok
398 if table
in self
.tables_with_created_field
and created_time
==0:
399 created_time
=time
.time()
404 self
.cur
= self
.con
.cursor()
405 return self
._new
_row
_internal
(table
, INSERT
, add_uuid
, None, created_time
)
407 except (mdb
.Error
, AttributeError) as e
:
408 self
._format
_error
(e
, tries
)
411 def update_rows(self
, table
, UPDATE
, WHERE
, modified_time
=0):
412 ''' Update one or several rows into a table.
414 UPDATE: dictionary with the key: value to change
415 table: table where to update
416 WHERE: dictionary of elements to update
417 Return: (result, descriptive text) where result indicates the number of updated files
419 if table
in self
.tables_with_created_field
and modified_time
==0:
420 modified_time
=time
.time()
425 self
.cur
= self
.con
.cursor()
426 return self
._update
_rows
(table
, UPDATE
, WHERE
)
428 except (mdb
.Error
, AttributeError) as e
:
429 self
._format
_error
(e
, tries
)
432 def delete_row_by_id(self
, table
, uuid
):
438 self
.cur
= self
.con
.cursor()
439 cmd
= "DELETE FROM {} WHERE uuid = '{}'".format(table
, uuid
)
440 self
.logger
.debug(cmd
)
441 self
.cur
.execute(cmd
)
442 deleted
= self
.cur
.rowcount
445 self
.cur
= self
.con
.cursor()
446 cmd
= "DELETE FROM uuids WHERE root_uuid = '{}'".format(uuid
)
447 self
.logger
.debug(cmd
)
448 self
.cur
.execute(cmd
)
450 except (mdb
.Error
, AttributeError) as e
:
451 self
._format
_error
(e
, tries
, "delete", "dependencies")
454 def delete_row(self
, **sql_dict
):
455 ''' Deletes rows from a table.
456 Attribute sql_dir: dictionary with the following key: value
457 'FROM': string of table name (Mandatory)
458 'WHERE': dict of key:values, translated to key=value AND ... (Optional)
459 'WHERE_NOT': dict of key:values, translated to key<>value AND ... (Optional)
460 if value is None, it is translated to key is not null
461 'LIMIT': limit of number of rows (Optional)
462 Return: the number of deleted or exception if error
465 from_
= "FROM " + str(sql_dict
['FROM'])
466 #print 'from_', from_
467 if 'WHERE' in sql_dict
and len(sql_dict
['WHERE']) > 0:
469 where_
= "WHERE " + " AND ".join(map(self
.__tuple
2db
_format
_where
, w
.iteritems()))
471 if 'WHERE_NOT' in sql_dict
and len(sql_dict
['WHERE_NOT']) > 0:
472 w
=sql_dict
['WHERE_NOT']
473 where_2
= " AND ".join(map(self
.__tuple
2db
_format
_where
_not
, w
.iteritems()))
474 if len(where_
)==0: where_
= "WHERE " + where_2
475 else: where_
= where_
+ " AND " + where_2
476 #print 'where_', where_
477 limit_
= "LIMIT " + str(sql_dict
['LIMIT']) if 'LIMIT' in sql_dict
else ""
478 #print 'limit_', limit_
479 cmd
= " ".join( ("DELETE", from_
, where_
, limit_
) )
484 self
.cur
= self
.con
.cursor()
485 self
.logger
.debug(cmd
)
486 self
.cur
.execute(cmd
)
487 deleted
= self
.cur
.rowcount
489 except (mdb
.Error
, AttributeError) as e
:
490 self
._format
_error
(e
, tries
)
493 def get_rows_by_id(self
, table
, uuid
):
494 '''get row from a table based on uuid'''
499 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
500 cmd
="SELECT * FROM {} where uuid='{}'".format(str(table
), str(uuid
))
501 self
.logger
.debug(cmd
)
502 self
.cur
.execute(cmd
)
503 rows
= self
.cur
.fetchall()
505 except (mdb
.Error
, AttributeError) as e
:
506 self
._format
_error
(e
, tries
)
509 def get_rows(self
, **sql_dict
):
510 ''' Obtain rows from a table.
511 Attribute sql_dir: dictionary with the following key: value
512 'SELECT': list or tuple of fields to retrieve) (by default all)
513 'FROM': string of table name (Mandatory)
514 'WHERE': dict of key:values, translated to key=value (key is null) AND ... (Optional)
515 'WHERE_NOT': dict of key:values, translated to key<>value (key is not null) AND ... (Optional)
516 'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
517 'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional)
518 'LIMIT': limit of number of rows (Optional)
519 'ORDER_BY': list or tuple of fields to order
520 Return: a list with dictionaries at each row
523 select_
= "SELECT " + ("*" if 'SELECT' not in sql_dict
else ",".join(map(str,sql_dict
['SELECT'])) )
524 #print 'select_', select_
525 from_
= "FROM " + str(sql_dict
['FROM'])
526 #print 'from_', from_
529 w
=sql_dict
.get('WHERE')
531 where_and
= " AND ".join(map(self
.__tuple
2db
_format
_where
, w
.iteritems() ))
532 w
=sql_dict
.get('WHERE_NOT')
534 if where_and
: where_and
+= " AND "
535 where_and
+= " AND ".join(map(self
.__tuple
2db
_format
_where
_not
, w
.iteritems() ) )
536 w
=sql_dict
.get('WHERE_OR')
538 where_or
= " OR ".join(map(self
.__tuple
2db
_format
_where
, w
.iteritems() ))
539 if where_and
and where_or
:
540 if sql_dict
.get("WHERE_AND_OR") == "AND":
541 where_
= "WHERE " + where_and
+ " AND (" + where_or
+ ")"
543 where_
= "WHERE (" + where_and
+ ") OR " + where_or
544 elif where_and
and not where_or
:
545 where_
= "WHERE " + where_and
546 elif not where_and
and where_or
:
547 where_
= "WHERE " + where_or
550 #print 'where_', where_
551 limit_
= "LIMIT " + str(sql_dict
['LIMIT']) if 'LIMIT' in sql_dict
else ""
552 order_
= "ORDER BY " + ",".join(map(str,sql_dict
['SELECT'])) if 'ORDER_BY' in sql_dict
else ""
554 #print 'limit_', limit_
555 cmd
= " ".join( (select_
, from_
, where_
, limit_
, order_
) )
560 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
561 self
.logger
.debug(cmd
)
562 self
.cur
.execute(cmd
)
563 rows
= self
.cur
.fetchall()
565 except (mdb
.Error
, AttributeError) as e
:
566 self
._format
_error
(e
, tries
)
569 def get_table_by_uuid_name(self
, table
, uuid_name
, error_item_text
=None, allow_serveral
=False, WHERE_OR
={}, WHERE_AND_OR
="OR"):
570 ''' Obtain One row from a table based on name or uuid.
572 table: string of table name
573 uuid_name: name or uuid. If not uuid format is found, it is considered a name
574 allow_severeral: if False return ERROR if more than one row are founded
575 error_item_text: in case of error it identifies the 'item' name for a proper output text
576 'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
577 'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional
578 Return: if allow_several==False, a dictionary with this row, or error if no item is found or more than one is found
579 if allow_several==True, a list of dictionaries with the row or rows, error if no item is found
582 if error_item_text
==None:
583 error_item_text
= table
584 what
= 'uuid' if af
.check_valid_uuid(uuid_name
) else 'name'
585 cmd
= " SELECT * FROM {} WHERE {}='{}'".format(table
, what
, uuid_name
)
587 where_or
= " OR ".join(map(self
.__tuple
2db
_format
_where
, WHERE_OR
.iteritems() ))
588 if WHERE_AND_OR
== "AND":
589 cmd
+= " AND (" + where_or
+ ")"
591 cmd
+= " OR " + where_or
598 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
599 self
.logger
.debug(cmd
)
600 self
.cur
.execute(cmd
)
601 number
= self
.cur
.rowcount
603 return -HTTP_Not_Found
, "No %s found with %s '%s'" %(error_item_text
, what
, uuid_name
)
604 elif number
>1 and not allow_serveral
:
605 return -HTTP_Bad_Request
, "More than one %s found with %s '%s'" %(error_item_text
, what
, uuid_name
)
607 rows
= self
.cur
.fetchall()
609 rows
= self
.cur
.fetchone()
611 except (mdb
.Error
, AttributeError) as e
:
612 self
._format
_error
(e
, tries
)
615 def get_uuid(self
, uuid
):
616 '''check in the database if this uuid is already present'''
617 for retry_
in range(0,2):
620 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
621 self
.cur
.execute("SELECT * FROM uuids where uuid='" + str(uuid
) + "'")
622 rows
= self
.cur
.fetchall()
623 return self
.cur
.rowcount
, rows
624 except (mdb
.Error
, AttributeError) as e
:
625 print "nfvo_db.get_uuid DB Exception %d: %s" % (e
.args
[0], e
.args
[1])
626 r
,c
= self
._format
_error
(e
)
627 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
629 def get_uuid_from_name(self
, table
, name
):
630 '''Searchs in table the name and returns the uuid
636 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
637 where_text
= "name='" + name
+"'"
638 self
.cur
.execute("SELECT * FROM " + table
+ " WHERE "+ where_text
)
639 rows
= self
.cur
.fetchall()
640 if self
.cur
.rowcount
==0:
641 return 0, "Name %s not found in table %s" %(name
, table
)
642 elif self
.cur
.rowcount
>1:
643 return self
.cur
.rowcount
, "More than one VNF with name %s found in table %s" %(name
, table
)
644 return self
.cur
.rowcount
, rows
[0]["uuid"]
645 except (mdb
.Error
, AttributeError) as e
:
646 self
._format
_error
(e
, tries
)