v0.4.7 remove folder utils moving files to parent to avoid an empty __utils.py__...
[osm/openvim.git] / vim_db.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 ##
5 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
6 # This file is part of openmano
7 # All Rights Reserved.
8 #
9 # Licensed under the Apache License, Version 2.0 (the "License"); you may
10 # not use this file except in compliance with the License. You may obtain
11 # a copy of the License at
12 #
13 # http://www.apache.org/licenses/LICENSE-2.0
14 #
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18 # License for the specific language governing permissions and limitations
19 # under the License.
20 #
21 # For those usages not covered by the Apache License, Version 2.0 please
22 # contact with: nfvlabs@tid.es
23 ##
24
25 '''
26 This module interact with the openvim database,
27 It implements general table management
28 and complex writings 'transactional' sures,
29 that is, or all is changed or nothing
30 '''
31
32 __author__="Alfonso Tierno"
33 __date__ ="$10-jul-2014 12:07:15$"
34
35 import MySQLdb as mdb
36 import uuid as myUuid
37 import auxiliary_functions as af
38 import json
39 import logging
40
41 HTTP_Bad_Request = 400
42 HTTP_Unauthorized = 401
43 HTTP_Not_Found = 404
44 HTTP_Method_Not_Allowed = 405
45 HTTP_Request_Timeout = 408
46 HTTP_Conflict = 409
47 HTTP_Service_Unavailable = 503
48 HTTP_Internal_Server_Error = 500
49
50
51 class vim_db():
52 def __init__(self, vlan_range, debug="ERROR"):
53 '''vlan_range must be a tuple (vlan_ini, vlan_end) with available vlan values for networks
54 every dataplane network contain a unique value, regardless of it is used or not
55 '''
56 #initialization
57 self.net_vlan_range = vlan_range
58 self.net_vlan_usedlist = None
59 self.net_vlan_lastused = self.net_vlan_range[0] -1
60 self.debug=debug
61 self.logger = logging.getLogger('vim.db')
62 self.logger.setLevel( getattr(logging, debug) )
63
64
65 def connect(self, host=None, user=None, passwd=None, database=None):
66 '''Connect to the concrete data base.
67 The first time a valid host, user, passwd and database must be provided,
68 Following calls can skip this parameters
69 '''
70 try:
71 if host is not None: self.host = host
72 if user is not None: self.user = user
73 if passwd is not None: self.passwd = passwd
74 if database is not None: self.database = database
75
76 self.con = mdb.connect(self.host, self.user, self.passwd, self.database)
77 self.logger.debug("connected to DB %s at %s@%s", self.database,self.user, self.host)
78 return 0
79 except mdb.Error as e:
80 self.logger.error("Cannot connect to DB %s at %s@%s Error %d: %s", self.database, self.user, self.host, e.args[0], e.args[1])
81 return -1
82
83 def get_db_version(self):
84 ''' Obtain the database schema version.
85 Return: (negative, text) if error or version 0.0 where schema_version table is missing
86 (version_int, version_text) if ok
87 '''
88 cmd = "SELECT version_int,version,openvim_ver FROM schema_version"
89 for retry_ in range(0,2):
90 try:
91 with self.con:
92 self.cur = self.con.cursor()
93 self.logger.debug(cmd)
94 self.cur.execute(cmd)
95 rows = self.cur.fetchall()
96 highest_version_int=0
97 highest_version=""
98 #print rows
99 for row in rows: #look for the latest version
100 if row[0]>highest_version_int:
101 highest_version_int, highest_version = row[0:2]
102 return highest_version_int, highest_version
103 except (mdb.Error, AttributeError) as e:
104 self.logger.error("get_db_version DB Exception %d: %s. Command %s",e.args[0], e.args[1], cmd)
105 r,c = self.format_error(e)
106 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
107
108 def disconnect(self):
109 '''disconnect from the data base'''
110 try:
111 self.con.close()
112 del self.con
113 except mdb.Error as e:
114 self.logger.error("while disconnecting from DB: Error %d: %s",e.args[0], e.args[1])
115 return -1
116 except AttributeError as e: #self.con not defined
117 if e[0][-5:] == "'con'": return -1, "Database internal error, no connection."
118 else: raise
119
120 def format_error(self, e, func, cmd, command=None, extra=None):
121 '''Creates a text error base on the produced exception
122 Params:
123 e: mdb exception
124 func: name of the function that makes the call, for logging purposes
125 cmd: database command that produce the exception
126 command: if the intention is update or delete
127 extra: extra information to add to some commands
128 Return
129 HTTP error in negative, formatted error text
130 '''
131
132 self.logger.error("%s DB Exception %s. Command %s",func, str(e), cmd)
133 if type(e[0]) is str:
134 if e[0][-5:] == "'con'": return -HTTP_Internal_Server_Error, "DB Exception, no connection."
135 else: raise
136 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
137 #reconnect
138 self.connect()
139 return -HTTP_Request_Timeout,"Database reconnection. Try Again"
140 fk=e.args[1].find("foreign key constraint fails")
141 if fk>=0:
142 if command=="update": return -HTTP_Bad_Request, "tenant_id %s not found." % extra
143 elif command=="delete": return -HTTP_Bad_Request, "Resource is not free. There are %s that prevent its deletion." % extra
144 de = e.args[1].find("Duplicate entry")
145 fk = e.args[1].find("for key")
146 uk = e.args[1].find("Unknown column")
147 wc = e.args[1].find("in 'where clause'")
148 fl = e.args[1].find("in 'field list'")
149 #print de, fk, uk, wc,fl
150 if de>=0:
151 if fk>=0: #error 1062
152 return -HTTP_Conflict, "Value %s already in use for %s" % (e.args[1][de+15:fk], e.args[1][fk+7:])
153 if uk>=0:
154 if wc>=0:
155 return -HTTP_Bad_Request, "Field %s can not be used for filtering" % e.args[1][uk+14:wc]
156 if fl>=0:
157 return -HTTP_Bad_Request, "Field %s does not exist" % e.args[1][uk+14:wc]
158 return -HTTP_Internal_Server_Error, "Database internal Error %d: %s" % (e.args[0], e.args[1])
159
160 def __data2db_format(self, data):
161 '''convert data to database format. If data is None it return the 'Null' text,
162 otherwise it return the text surrounded by quotes ensuring internal quotes are escaped'''
163 if data==None:
164 return 'Null'
165 out=str(data)
166 if "'" not in out:
167 return "'" + out + "'"
168 elif '"' not in out:
169 return '"' + out + '"'
170 else:
171 return json.dumps(out)
172
173 def __get_used_net_vlan(self):
174 #get used from database if needed
175 try:
176 cmd = "SELECT vlan FROM nets WHERE vlan>='%s' and (type='ptp' or type='data') ORDER BY vlan LIMIT 25" % self.net_vlan_lastused
177 with self.con:
178 self.cur = self.con.cursor()
179 self.logger.debug(cmd)
180 self.cur.execute(cmd)
181 vlan_tuple = self.cur.fetchall()
182 #convert a tuple of tuples in a list of numbers
183 self.net_vlan_usedlist = []
184 for k in vlan_tuple:
185 self.net_vlan_usedlist.append(k[0])
186 return 0
187 except (mdb.Error, AttributeError) as e:
188 return self.format_error(e, "get_free_net_vlan", cmd)
189
190 def get_free_net_vlan(self):
191 '''obtain a vlan not used in any net'''
192
193 while True:
194 self.logger.debug("net_vlan_lastused:%d net_vlan_range:%d-%d net_vlan_usedlist:%s",
195 self.net_vlan_lastused, self.net_vlan_range[0], self.net_vlan_range[1], str(self.net_vlan_usedlist))
196 self.net_vlan_lastused += 1
197 if self.net_vlan_lastused == self.net_vlan_range[1]:
198 #start from the begining
199 self.net_vlan_lastused = self.net_vlan_range[0]
200 self.net_vlan_usedlist = None
201 if self.net_vlan_usedlist is None \
202 or (len(self.net_vlan_usedlist)>0 and self.net_vlan_lastused >= self.net_vlan_usedlist[-1] and len(self.net_vlan_usedlist)==25):
203 r = self.__get_used_net_vlan()
204 if r<0: return r
205 self.logger.debug("new net_vlan_usedlist %s", str(self.net_vlan_usedlist))
206 if self.net_vlan_lastused in self.net_vlan_usedlist:
207 continue
208 else:
209 return self.net_vlan_lastused
210
211 def get_table(self, **sql_dict):
212 ''' Obtain rows from a table.
213 Atribure sql_dir: dictionary with the following key: value
214 'SELECT': [list of fields to retrieve] (by default all)
215 'FROM': string of table name (Mandatory)
216 'WHERE': dict of key:values, translated to key=value AND ... (Optional)
217 'WHERE_NOT': dict of key:values, translated to key!=value AND ... (Optional)
218 'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
219 'LIMIT': limit of number of rows (Optional)
220 Return: a list with dictionarys at each row
221 '''
222 #print sql_dict
223 select_= "SELECT " + ("*" if 'SELECT' not in sql_dict else ",".join(map(str,sql_dict['SELECT'])) )
224 #print 'select_', select_
225 from_ = "FROM " + str(sql_dict['FROM'])
226 #print 'from_', from_
227
228 where_and = None
229 where_or = None
230 if 'WHERE' in sql_dict and len(sql_dict['WHERE']) > 0:
231 w=sql_dict['WHERE']
232 where_and = " AND ".join(map( lambda x: str(x) + (" is Null" if w[x] is None else "='"+str(w[x])+"'"), w.keys()) )
233 if 'WHERE_NOT' in sql_dict and len(sql_dict['WHERE_NOT']) > 0:
234 w=sql_dict['WHERE_NOT']
235 where_and_not = " AND ".join(map( lambda x: str(x) + (" is not Null" if w[x] is None else "!='"+str(w[x])+"'"), w.keys()) )
236 if where_and:
237 where_and += " AND " + where_and_not
238 else:
239 where_and = where_and_not
240 if 'WHERE_OR' in sql_dict and len(sql_dict['WHERE_OR']) > 0:
241 w=sql_dict['WHERE_OR']
242 where_or = " OR ".join(map( lambda x: str(x) + (" is Null" if w[x] is None else "='"+str(w[x])+"'"), w.keys()) )
243
244 if where_and!=None and where_or!=None:
245 where_ = "WHERE (" + where_and + ") OR " + where_or
246 elif where_and!=None and where_or==None:
247 where_ = "WHERE " + where_and
248 elif where_and==None and where_or!=None:
249 where_ = "WHERE " + where_or
250 else:
251 where_ = ""
252 #print 'where_', where_
253 limit_ = "LIMIT " + str(sql_dict['LIMIT']) if 'LIMIT' in sql_dict else ""
254 #print 'limit_', limit_
255 cmd = " ".join( (select_, from_, where_, limit_) )
256 for retry_ in range(0,2):
257 try:
258 with self.con:
259 self.cur = self.con.cursor(mdb.cursors.DictCursor)
260 self.logger.debug(cmd)
261 self.cur.execute(cmd)
262 rows = self.cur.fetchall()
263 return self.cur.rowcount, rows
264 except (mdb.Error, AttributeError) as e:
265 r,c = self.format_error(e, "get_table", cmd)
266 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
267
268 def new_tenant(self, tenant_dict):
269 ''' Add one row into a table.
270 Attribure
271 tenant_dict: dictionary with the key: value to insert
272 It checks presence of uuid and add one automatically otherwise
273 Return: (result, uuid) where result can be 0 if error, or 1 if ok
274 '''
275 for retry_ in range(0,2):
276 cmd=""
277 inserted=-1
278 try:
279 #create uuid if not provided
280 if 'uuid' not in tenant_dict:
281 uuid = tenant_dict['uuid'] = str(myUuid.uuid1()) # create_uuid
282 else:
283 uuid = str(tenant_dict['uuid'])
284 #obtain tenant_id for logs
285 tenant_id = uuid
286 with self.con:
287 self.cur = self.con.cursor()
288 #inserting new uuid
289 cmd = "INSERT INTO uuids (uuid, used_at) VALUES ('%s','tenants')" % uuid
290 self.logger.debug(cmd)
291 self.cur.execute(cmd)
292 #insert tenant
293 cmd= "INSERT INTO tenants (" + \
294 ",".join(map(str, tenant_dict.keys() )) + ") VALUES(" + \
295 ",".join(map(lambda x: "Null" if x is None else "'"+str(x)+"'",tenant_dict.values() )) + ")"
296 self.logger.debug(cmd)
297 self.cur.execute(cmd)
298 inserted = self.cur.rowcount
299 ##inserting new log
300 #del tenant_dict['uuid'] # not interested for the log
301 #cmd = "INSERT INTO logs (related,level,tenant_id,uuid,description) VALUES ('tenants','debug','%s','%s',\"new tenant %s\")" % (uuid, tenant_id, str(tenant_dict))
302 #self.logger.debug(cmd)
303 #self.cur.execute(cmd)
304 #commit transaction
305 self.cur.close()
306 if inserted == 0: return 0, uuid
307 with self.con:
308 self.cur = self.con.cursor()
309 #adding public flavors
310 cmd = "INSERT INTO tenants_flavors(flavor_id,tenant_id) SELECT uuid as flavor_id,'"+ tenant_id + "' FROM flavors WHERE public = 'yes'"
311 self.logger.debug(cmd)
312 self.cur.execute(cmd)
313 self.logger.debug("attached public flavors: %s", str(self.cur.rowcount))
314 #rows = self.cur.fetchall()
315 #for row in rows:
316 # cmd = "INSERT INTO tenants_flavors(flavor_id,tenant_id) VALUES('%s','%s')" % (row[0], tenant_id)
317 # self.cur.execute(cmd )
318 #adding public images
319 cmd = "INSERT INTO tenants_images(image_id,tenant_id) SELECT uuid as image_id,'"+ tenant_id + "' FROM images WHERE public = 'yes'"
320 self.logger.debug(cmd)
321 self.cur.execute(cmd)
322 self.logger.debug("attached public images: %s", str(self.cur.rowcount))
323 return 1, uuid
324 except (mdb.Error, AttributeError) as e:
325 if inserted==1:
326 self.logger.warning("new_tenant DB Exception %d: %s. Command %s",e.args[0], e.args[1], cmd)
327 return 1, uuid
328 else:
329 r,c = self.format_error(e, "new_tenant", cmd)
330 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
331
332 def new_row(self, table, INSERT, add_uuid=False, log=False):
333 ''' Add one row into a table.
334 Atribure
335 INSERT: dictionary with the key: value to insert
336 table: table where to insert
337 add_uuid: if True, it will crated an uuid key entry at INSERT if not provided
338 It checks presence of uuid and add one automatically otherwise
339 Return: (result, uuid) where result can be 0 if error, or 1 if ok
340 '''
341 for retry_ in range(0,2):
342 cmd=""
343 try:
344 if add_uuid:
345 #create uuid if not provided
346 if 'uuid' not in INSERT:
347 uuid = INSERT['uuid'] = str(myUuid.uuid1()) # create_uuid
348 else:
349 uuid = str(INSERT['uuid'])
350 else:
351 uuid=None
352 with self.con:
353 self.cur = self.con.cursor()
354 if add_uuid:
355 #inserting new uuid
356 cmd = "INSERT INTO uuids (uuid, used_at) VALUES ('%s','%s')" % (uuid, table)
357 self.logger.debug(cmd)
358 self.cur.execute(cmd)
359 #insertion
360 cmd= "INSERT INTO " + table +" (" + \
361 ",".join(map(str, INSERT.keys() )) + ") VALUES(" + \
362 ",".join(map(lambda x: 'Null' if x is None else "'"+str(x)+"'", INSERT.values() )) + ")"
363 self.logger.debug(cmd)
364 self.cur.execute(cmd)
365 nb_rows = self.cur.rowcount
366 #inserting new log
367 #if nb_rows > 0 and log:
368 # if add_uuid: del INSERT['uuid']
369 # #obtain tenant_id for logs
370 # if 'tenant_id' in INSERT:
371 # tenant_id = INSERT['tenant_id']
372 # del INSERT['tenant_id']
373 # elif table == 'tenants':
374 # tenant_id = uuid
375 # else:
376 # tenant_id = None
377 # if uuid is None: uuid_k = uuid_v = ""
378 # else: uuid_k=",uuid"; uuid_v=",'" + str(uuid) + "'"
379 # if tenant_id is None: tenant_k = tenant_v = ""
380 # else: tenant_k=",tenant_id"; tenant_v=",'" + str(tenant_id) + "'"
381 # cmd = "INSERT INTO logs (related,level%s%s,description) VALUES ('%s','debug'%s%s,\"new %s %s\")" \
382 # % (uuid_k, tenant_k, table, uuid_v, tenant_v, table[:-1], str(INSERT))
383 # self.logger.debug(cmd)
384 # self.cur.execute(cmd)
385 return nb_rows, uuid
386
387 except (mdb.Error, AttributeError) as e:
388 r,c = self.format_error(e, "new_row", cmd)
389 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
390
391 def __remove_quotes(self, data):
392 '''remove single quotes ' of any string content of data dictionary'''
393 for k,v in data.items():
394 if type(v) == str:
395 if "'" in v:
396 data[k] = data[k].replace("'","_")
397
398 def _update_rows_internal(self, table, UPDATE, WHERE={}):
399 cmd= "UPDATE " + table +" SET " + \
400 ",".join(map(lambda x: str(x)+'='+ self.__data2db_format(UPDATE[x]), UPDATE.keys() ));
401 if WHERE:
402 cmd += " WHERE " + " and ".join(map(lambda x: str(x)+ (' is Null' if WHERE[x] is None else"='"+str(WHERE[x])+"'" ), WHERE.keys() ))
403 self.logger.debug(cmd)
404 self.cur.execute(cmd)
405 nb_rows = self.cur.rowcount
406 return nb_rows, None
407
408 def update_rows(self, table, UPDATE, WHERE={}, log=False):
409 ''' Update one or several rows into a table.
410 Atributes
411 UPDATE: dictionary with the key-new_value pairs to change
412 table: table to be modified
413 WHERE: dictionary to filter target rows, key-value
414 log: if true, a log entry is added at logs table
415 Return: (result, None) where result indicates the number of updated files
416 '''
417 for retry_ in range(0,2):
418 cmd=""
419 try:
420 #gettting uuid
421 uuid = WHERE.get('uuid')
422
423 with self.con:
424 self.cur = self.con.cursor()
425 cmd= "UPDATE " + table +" SET " + \
426 ",".join(map(lambda x: str(x)+'='+ self.__data2db_format(UPDATE[x]), UPDATE.keys() ));
427 if WHERE:
428 cmd += " WHERE " + " and ".join(map(lambda x: str(x)+ (' is Null' if WHERE[x] is None else"='"+str(WHERE[x])+"'" ), WHERE.keys() ))
429 self.logger.debug(cmd)
430 self.cur.execute(cmd)
431 nb_rows = self.cur.rowcount
432 #if nb_rows > 0 and log:
433 # #inserting new log
434 # if uuid is None: uuid_k = uuid_v = ""
435 # else: uuid_k=",uuid"; uuid_v=",'" + str(uuid) + "'"
436 # cmd = "INSERT INTO logs (related,level%s,description) VALUES ('%s','debug'%s,\"updating %d entry %s\")" \
437 # % (uuid_k, table, uuid_v, nb_rows, (str(UPDATE)).replace('"','-') )
438 # self.logger.debug(cmd)
439 # self.cur.execute(cmd)
440 return nb_rows, uuid
441 except (mdb.Error, AttributeError) as e:
442 r,c = self.format_error(e, "update_rows", cmd)
443 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
444
445 def get_host(self, host_id):
446 if af.check_valid_uuid(host_id):
447 where_filter="uuid='" + host_id + "'"
448 else:
449 where_filter="name='" + host_id + "'"
450 for retry_ in range(0,2):
451 cmd=""
452 try:
453 with self.con:
454 self.cur = self.con.cursor(mdb.cursors.DictCursor)
455 #get HOST
456 cmd = "SELECT uuid, user, name, ip_name, description, ranking, admin_state_up, DATE_FORMAT(created_at,'%Y-%m-%dT%H:%i:%s') as created_at \
457 FROM hosts WHERE " + where_filter
458 self.logger.debug(cmd)
459 self.cur.execute(cmd)
460 if self.cur.rowcount == 0 :
461 return 0, "host '" + str(host_id) +"'not found."
462 elif self.cur.rowcount > 1 :
463 return 0, "host '" + str(host_id) +"' matches more than one result."
464 host = self.cur.fetchone()
465 host_id = host['uuid']
466 #get numa
467 cmd = "SELECT id, numa_socket, hugepages, memory, admin_state_up FROM numas WHERE host_id = '" + str(host_id) + "'"
468 self.logger.debug(cmd)
469 self.cur.execute(cmd)
470 host['numas'] = self.cur.fetchall()
471 for numa in host['numas']:
472 #print "SELECT core_id, instance_id, status, thread_id, v_thread_id FROM resources_core WHERE numa_id = '" + str(numa['id']) + "'"
473 #get cores
474 cmd = "SELECT core_id, instance_id, status, thread_id, v_thread_id FROM resources_core WHERE numa_id = '" + str(numa['id']) + "'"
475 self.logger.debug(cmd)
476 self.cur.execute(cmd)
477 numa['cores'] = self.cur.fetchall()
478 for core in numa['cores']:
479 if core['instance_id'] == None: del core['instance_id'], core['v_thread_id']
480 if core['status'] == 'ok': del core['status']
481 #get used memory
482 cmd = "SELECT sum(consumed) as hugepages_consumed FROM resources_mem WHERE numa_id = '" + str(numa['id']) + "' GROUP BY numa_id"
483 self.logger.debug(cmd)
484 self.cur.execute(cmd)
485 used = self.cur.fetchone()
486 used_= int(used['hugepages_consumed']) if used != None else 0
487 numa['hugepages_consumed'] = used_
488 #get ports
489 #cmd = "CALL GetPortsFromNuma(%s)'" % str(numa['id'])
490 #self.cur.callproc('GetPortsFromNuma', (numa['id'],) )
491 #every time a Procedure is launched you need to close and open the cursor
492 #under Error 2014: Commands out of sync; you can't run this command now
493 #self.cur.close()
494 #self.cur = self.con.cursor(mdb.cursors.DictCursor)
495 cmd="SELECT Mbps, pci, status, Mbps_used, instance_id, if(id=root_id,'PF','VF') as type_,\
496 switch_port, switch_dpid, mac, source_name\
497 FROM resources_port WHERE numa_id=%d ORDER BY root_id, type_ DESC" % (numa['id'])
498 self.logger.debug(cmd)
499 self.cur.execute(cmd)
500 ifaces = self.cur.fetchall()
501 #The SQL query will ensure to have SRIOV interfaces from a port first
502 sriovs=[]
503 Mpbs_consumed = 0
504 numa['interfaces'] = []
505 for iface in ifaces:
506 if not iface["instance_id"]:
507 del iface["instance_id"]
508 if iface['status'] == 'ok':
509 del iface['status']
510 Mpbs_consumed += int(iface["Mbps_used"])
511 del iface["Mbps_used"]
512 if iface["type_"]=='PF':
513 if not iface["switch_dpid"]:
514 del iface["switch_dpid"]
515 if not iface["switch_port"]:
516 del iface["switch_port"]
517 if sriovs:
518 iface["sriovs"] = sriovs
519 if Mpbs_consumed:
520 iface["Mpbs_consumed"] = Mpbs_consumed
521 del iface["type_"]
522 numa['interfaces'].append(iface)
523 sriovs=[]
524 Mpbs_consumed = 0
525 else: #VF, SRIOV
526 del iface["switch_port"]
527 del iface["switch_dpid"]
528 del iface["type_"]
529 del iface["Mbps"]
530 sriovs.append(iface)
531
532 #delete internal field
533 del numa['id']
534 return 1, host
535 except (mdb.Error, AttributeError) as e:
536 r,c = self.format_error(e, "get_host", cmd)
537 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
538
539 def new_uuid(self):
540 max_retries=10
541 while max_retries>0:
542 uuid = str( myUuid.uuid1() )
543 if self.check_uuid(uuid)[0] == 0:
544 return uuid
545 max_retries-=1
546 return uuid
547
548 def check_uuid(self, uuid):
549 '''check in the database if this uuid is already present'''
550 try:
551 cmd = "SELECT * FROM uuids where uuid='" + str(uuid) + "'"
552 with self.con:
553 self.cur = self.con.cursor(mdb.cursors.DictCursor)
554 self.logger.debug(cmd)
555 self.cur.execute(cmd)
556 rows = self.cur.fetchall()
557 return self.cur.rowcount, rows
558 except (mdb.Error, AttributeError) as e:
559 return self.format_error(e, "check_uuid", cmd)
560
561 def __get_next_ids(self):
562 '''get next auto increment index of all table in the database'''
563 self.cur.execute("SELECT table_name,AUTO_INCREMENT FROM information_schema.tables WHERE AUTO_INCREMENT IS NOT NULL AND table_schema = DATABASE()")
564 rows = self.cur.fetchall()
565 return self.cur.rowcount, dict(rows)
566
567 def edit_host(self, host_id, host_dict):
568 #get next port index
569 for retry_ in range(0,2):
570 cmd=""
571 try:
572 with self.con:
573 self.cur = self.con.cursor()
574
575 #update table host
576 numa_list = host_dict.pop('numas', () )
577 if host_dict:
578 self._update_rows_internal("hosts", host_dict, {"uuid": host_id})
579
580 where = {"host_id": host_id}
581 for numa_dict in numa_list:
582 where["numa_socket"] = str(numa_dict.pop('numa_socket'))
583 interface_list = numa_dict.pop('interfaces', () )
584 if numa_dict:
585 self._update_rows_internal("numas", numa_dict, where)
586 for interface in interface_list:
587 source_name = str(interface.pop("source_name") )
588 if interface:
589 #get interface id from resources_port
590 cmd= "SELECT rp.id as id FROM resources_port as rp join numas as n on n.id=rp.numa_id join hosts as h on h.uuid=n.host_id " +\
591 "WHERE host_id='%s' and rp.source_name='%s'" %(host_id, source_name)
592 self.logger.debug(cmd)
593 self.cur.execute(cmd)
594 row = self.cur.fetchone()
595 if self.cur.rowcount<=0:
596 return -HTTP_Bad_Request, "Interface source_name='%s' from numa_socket='%s' not found" % (source_name, str(where["numa_socket"]))
597 interface_id = row[0]
598 self._update_rows_internal("resources_port", interface, {"root_id": interface_id})
599 return self.get_host(host_id)
600 except (mdb.Error, AttributeError) as e:
601 r,c = self.format_error(e, "edit_host", cmd)
602 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
603
604 def new_host(self, host_dict):
605 #get next port index
606 for retry_ in range(0,2):
607 cmd=""
608 try:
609 with self.con:
610 self.cur = self.con.cursor()
611
612 result, next_ids = self.__get_next_ids()
613 #print "next_ids: " + str(next_ids)
614 if result <= 0: return result, "Internal DataBase error getting next id of tables"
615
616 #create uuid if not provided
617 if 'uuid' not in host_dict:
618 uuid = host_dict['uuid'] = str(myUuid.uuid1()) # create_uuid
619 else: #check uuid is valid
620 uuid = str(host_dict['uuid'])
621 # result, data = self.check_uuid(uuid)
622 # if (result == 1):
623 # return -1, "UUID '%s' already in use" % uuid
624
625 #inserting new uuid
626 cmd = "INSERT INTO uuids (uuid, used_at) VALUES ('%s','hosts')" % uuid
627 self.logger.debug(cmd)
628 result = self.cur.execute(cmd)
629
630 #insert in table host
631 numa_list = host_dict.pop('numas', [])
632 #get nonhupages and nonisolated cpus
633 host_dict['RAM']=0
634 host_dict['cpus']=0
635 for numa in numa_list:
636 mem_numa = numa.get('memory', 0) - numa.get('hugepages',0)
637 if mem_numa>0:
638 host_dict['RAM'] += mem_numa
639 for core in numa.get("cores", []):
640 if "status" in core and core["status"]=="noteligible":
641 host_dict['cpus']+=1
642 host_dict['RAM']*=1024 # from GB to MB
643
644 keys = ",".join(host_dict.keys())
645 values = ",".join( map(lambda x: "Null" if x is None else "'"+str(x)+"'", host_dict.values() ) )
646 cmd = "INSERT INTO hosts (" + keys + ") VALUES (" + values + ")"
647 self.logger.debug(cmd)
648 result = self.cur.execute(cmd)
649 #if result != 1: return -1, "Database Error while inserting at hosts table"
650
651 #insert numas
652 nb_numas = nb_cores = nb_ifaces = 0
653 for numa_dict in numa_list:
654 nb_numas += 1
655 interface_list = numa_dict.pop('interfaces', [])
656 core_list = numa_dict.pop('cores', [])
657 numa_dict['id'] = next_ids['numas']; next_ids['numas'] += 1
658 numa_dict['host_id'] = uuid
659 keys = ",".join(numa_dict.keys())
660 values = ",".join( map(lambda x: "Null" if x is None else "'"+str(x)+"'", numa_dict.values() ) )
661 cmd = "INSERT INTO numas (" + keys + ") VALUES (" + values + ")"
662 self.logger.debug(cmd)
663 result = self.cur.execute(cmd)
664
665 #insert cores
666 for core_dict in core_list:
667 nb_cores += 1
668 core_dict['numa_id'] = numa_dict['id']
669 keys = ",".join(core_dict.keys())
670 values = ",".join( map(lambda x: "Null" if x is None else "'"+str(x)+"'", core_dict.values() ) )
671 cmd = "INSERT INTO resources_core (" + keys + ") VALUES (" + values + ")"
672 self.logger.debug(cmd)
673 result = self.cur.execute(cmd)
674
675 #insert ports
676 for port_dict in interface_list:
677 nb_ifaces += 1
678 sriov_list = port_dict.pop('sriovs', [])
679 port_dict['numa_id'] = numa_dict['id']
680 port_dict['id'] = port_dict['root_id'] = next_ids['resources_port']
681 next_ids['resources_port'] += 1
682 switch_port = port_dict.get('switch_port', None)
683 switch_dpid = port_dict.get('switch_dpid', None)
684 keys = ",".join(port_dict.keys())
685 values = ",".join( map(lambda x: "Null" if x is None else "'"+str(x)+"'", port_dict.values() ) )
686 cmd = "INSERT INTO resources_port (" + keys + ") VALUES (" + values + ")"
687 self.logger.debug(cmd)
688 result = self.cur.execute(cmd)
689
690 #insert sriovs into port table
691 for sriov_dict in sriov_list:
692 sriov_dict['switch_port'] = switch_port
693 sriov_dict['switch_dpid'] = switch_dpid
694 sriov_dict['numa_id'] = port_dict['numa_id']
695 sriov_dict['Mbps'] = port_dict['Mbps']
696 sriov_dict['root_id'] = port_dict['id']
697 sriov_dict['id'] = next_ids['resources_port']
698 if "vlan" in sriov_dict:
699 del sriov_dict["vlan"]
700 next_ids['resources_port'] += 1
701 keys = ",".join(sriov_dict.keys())
702 values = ",".join( map(lambda x: "Null" if x is None else "'"+str(x)+"'", sriov_dict.values() ) )
703 cmd = "INSERT INTO resources_port (" + keys + ") VALUES (" + values + ")"
704 self.logger.debug(cmd)
705 result = self.cur.execute(cmd)
706
707 #inserting new log
708 #cmd = "INSERT INTO logs (related,level,uuid,description) VALUES ('hosts','debug','%s','new host: %d numas, %d theads, %d ifaces')" % (uuid, nb_numas, nb_cores, nb_ifaces)
709 #self.logger.debug(cmd)
710 #result = self.cur.execute(cmd)
711
712 #inseted ok
713 with self.con:
714 self.cur = self.con.cursor()
715 self.logger.debug("callproc('UpdateSwitchPort', () )")
716 self.cur.callproc('UpdateSwitchPort', () )
717
718 self.logger.debug("getting host '%s'",str(host_dict['uuid']))
719 return self.get_host(host_dict['uuid'])
720 except (mdb.Error, AttributeError) as e:
721 r,c = self.format_error(e, "new_host", cmd)
722 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
723
724 def new_flavor(self, flavor_dict, tenant_id ):
725 '''Add new flavor into the database. Create uuid if not provided
726 Atributes
727 flavor_dict: flavor dictionary with the key: value to insert. Must be valid flavors columns
728 tenant_id: if not 'any', it matches this flavor/tenant inserting at tenants_flavors table
729 Return: (result, data) where result can be
730 negative: error at inserting. data contain text
731 1, inserted, data contain inserted uuid flavor
732 '''
733 for retry_ in range(0,2):
734 cmd=""
735 try:
736 with self.con:
737 self.cur = self.con.cursor()
738
739 #create uuid if not provided
740 if 'uuid' not in flavor_dict:
741 uuid = flavor_dict['uuid'] = str(myUuid.uuid1()) # create_uuid
742 else: #check uuid is valid
743 uuid = str(flavor_dict['uuid'])
744 # result, data = self.check_uuid(uuid)
745 # if (result == 1):
746 # return -1, "UUID '%s' already in use" % uuid
747
748 #inserting new uuid
749 cmd = "INSERT INTO uuids (uuid, used_at) VALUES ('%s','flavors')" % uuid
750 self.logger.debug(cmd)
751 self.cur.execute(cmd)
752
753 #insert in table flavor
754 keys = ",".join(flavor_dict.keys())
755 values = ",".join( map(lambda x: "Null" if x is None else "'"+str(x)+"'", flavor_dict.values() ) )
756 cmd = "INSERT INTO flavors (" + keys + ") VALUES (" + values + ")"
757 self.logger.debug(cmd)
758 self.cur.execute(cmd)
759 #if result != 1: return -1, "Database Error while inserting at flavors table"
760
761 #insert tenants_flavors
762 if tenant_id != 'any':
763 cmd = "INSERT INTO tenants_flavors (tenant_id,flavor_id) VALUES ('%s','%s')" % (tenant_id, uuid)
764 self.logger.debug(cmd)
765 self.cur.execute(cmd)
766
767 #inserting new log
768 #del flavor_dict['uuid']
769 #if 'extended' in flavor_dict: del flavor_dict['extended'] #remove two many information
770 #cmd = "INSERT INTO logs (related,level,uuid, tenant_id, description) VALUES ('flavors','debug','%s','%s',\"new flavor: %s\")" \
771 # % (uuid, tenant_id, str(flavor_dict))
772 #self.logger.debug(cmd)
773 #self.cur.execute(cmd)
774
775 #inseted ok
776 return 1, uuid
777 except (mdb.Error, AttributeError) as e:
778 r,c = self.format_error(e, "new_flavor", cmd, "update", tenant_id)
779 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
780
781 def new_image(self, image_dict, tenant_id):
782 '''Add new image into the database. Create uuid if not provided
783 Atributes
784 image_dict: image dictionary with the key: value to insert. Must be valid images columns
785 tenant_id: if not 'any', it matches this image/tenant inserting at tenants_images table
786 Return: (result, data) where result can be
787 negative: error at inserting. data contain text
788 1, inserted, data contain inserted uuid image
789 '''
790 for retry_ in range(0,2):
791 cmd=""
792 try:
793 with self.con:
794 self.cur = self.con.cursor()
795
796 #create uuid if not provided
797 if 'uuid' not in image_dict:
798 uuid = image_dict['uuid'] = str(myUuid.uuid1()) # create_uuid
799 else: #check uuid is valid
800 uuid = str(image_dict['uuid'])
801 # result, data = self.check_uuid(uuid)
802 # if (result == 1):
803 # return -1, "UUID '%s' already in use" % uuid
804
805 #inserting new uuid
806 cmd = "INSERT INTO uuids (uuid, used_at) VALUES ('%s','images')" % uuid
807 self.logger.debug(cmd)
808 self.cur.execute(cmd)
809
810 #insert in table image
811 keys = ",".join(image_dict.keys())
812 values = ",".join( map(lambda x: "Null" if x is None else "'"+str(x)+"'", image_dict.values() ) )
813 cmd = "INSERT INTO images (" + keys + ") VALUES (" + values + ")"
814 self.logger.debug(cmd)
815 self.cur.execute(cmd)
816 #if result != 1: return -1, "Database Error while inserting at images table"
817
818 #insert tenants_images
819 if tenant_id != 'any':
820 cmd = "INSERT INTO tenants_images (tenant_id,image_id) VALUES ('%s','%s')" % (tenant_id, uuid)
821 self.logger.debug(cmd)
822 self.cur.execute(cmd)
823
824 ##inserting new log
825 #cmd = "INSERT INTO logs (related,level,uuid, tenant_id, description) VALUES ('images','debug','%s','%s',\"new image: %s path: %s\")" % (uuid, tenant_id, image_dict['name'], image_dict['path'])
826 #self.logger.debug(cmd)
827 #self.cur.execute(cmd)
828
829 #inseted ok
830 return 1, uuid
831 except (mdb.Error, AttributeError) as e:
832 r,c = self.format_error(e, "new_image", cmd, "update", tenant_id)
833 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
834
835 def delete_image_flavor(self, item_type, item_id, tenant_id):
836 '''deletes an image or flavor from database
837 item_type must be a 'image' or 'flavor'
838 item_id is the uuid
839 tenant_id is the asociated tenant, can be 'any' with means all
840 If tenan_id is not any, it deletes from tenants_images/flavors,
841 which means this image/flavor is used by this tenant, and if success,
842 it tries to delete from images/flavors in case this is not public,
843 that only will success if image is private and not used by other tenants
844 If tenant_id is any, it tries to delete from both tables at the same transaction
845 so that image/flavor is completely deleted from all tenants or nothing
846 '''
847 for retry_ in range(0,2):
848 deleted = -1
849 deleted_item = -1
850 result = (-HTTP_Internal_Server_Error, "internal error")
851 cmd=""
852 try:
853 with self.con:
854 self.cur = self.con.cursor()
855 cmd = "DELETE FROM tenants_%ss WHERE %s_id = '%s'" % (item_type, item_type, item_id)
856 if tenant_id != 'any':
857 cmd += " AND tenant_id = '%s'" % tenant_id
858 self.logger.debug(cmd)
859 self.cur.execute(cmd)
860 deleted = self.cur.rowcount
861 if tenant_id == 'any': #delete from images/flavors in the SAME transaction
862 cmd = "DELETE FROM %ss WHERE uuid = '%s'" % (item_type, item_id)
863 self.logger.debug(cmd)
864 self.cur.execute(cmd)
865 deleted = self.cur.rowcount
866 if deleted>=1:
867 #delete uuid
868 cmd = "DELETE FROM uuids WHERE uuid = '%s'" % item_id
869 self.logger.debug(cmd)
870 self.cur.execute(cmd)
871 ##inserting new log
872 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) \
873 # VALUES ('%ss','debug','%s','%s','delete %s completely')" % \
874 # (item_type, item_id, tenant_id, item_type)
875 #self.logger.debug(cmd)
876 #self.cur.execute(cmd)
877 return deleted, "%s '%s' completely deleted" % (item_type, item_id)
878 return 0, "%s '%s' not found" % (item_type, item_id)
879
880 if deleted == 1:
881 ##inserting new log
882 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) \
883 # VALUES ('%ss','debug','%s','%s','delete %s reference for this tenant')" % \
884 # (item_type, item_id, tenant_id, item_type)
885 #self.logger.debug(cmd)
886 #self.cur.execute(cmd)
887
888 #commit transaction
889 self.cur.close()
890 #if tenant!=any delete from images/flavors in OTHER transaction. If fails is because dependencies so that not return error
891 if deleted==1:
892 with self.con:
893 self.cur = self.con.cursor()
894
895 #delete image/flavor if not public
896 cmd = "DELETE FROM %ss WHERE uuid = '%s' AND public = 'no'" % (item_type, item_id)
897 self.logger.debug(cmd)
898 self.cur.execute(cmd)
899 deleted_item = self.cur.rowcount
900 if deleted_item == 1:
901 #delete uuid
902 cmd = "DELETE FROM uuids WHERE uuid = '%s'" % item_id
903 self.logger.debug(cmd)
904 self.cur.execute(cmd)
905 ##inserting new log
906 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) \
907 # VALUES ('%ss','debug','%s','%s','delete %s completely')" % \
908 # (item_type, item_id, tenant_id, item_type)
909 #self.logger.debug(cmd)
910 #self.cur.execute(cmd)
911 except (mdb.Error, AttributeError) as e:
912 #print "delete_%s DB Exception %d: %s" % (item_type, e.args[0], e.args[1])
913 if deleted <0:
914 result = self.format_error(e, "delete_"+item_type, cmd, "delete", "servers")
915 finally:
916 if deleted==1:
917 return 1, "%s '%s' from tenant '%s' %sdeleted" % \
918 (item_type, item_id, tenant_id, "completely " if deleted_item==1 else "")
919 elif deleted==0:
920 return 0, "%s '%s' from tenant '%s' not found" % (item_type, item_id, tenant_id)
921 else:
922 if result[0]!=-HTTP_Request_Timeout or retry_==1: return result
923
924 def delete_row(self, table, uuid):
925 for retry_ in range(0,2):
926 cmd=""
927 try:
928 with self.con:
929 #delete host
930 self.cur = self.con.cursor()
931 cmd = "DELETE FROM %s WHERE uuid = '%s'" % (table, uuid)
932 self.logger.debug(cmd)
933 self.cur.execute(cmd)
934 deleted = self.cur.rowcount
935 if deleted == 1:
936 #delete uuid
937 if table == 'tenants': tenant_str=uuid
938 else: tenant_str='Null'
939 self.cur = self.con.cursor()
940 cmd = "DELETE FROM uuids WHERE uuid = '%s'" % uuid
941 self.logger.debug(cmd)
942 self.cur.execute(cmd)
943 ##inserting new log
944 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) VALUES ('%s','debug','%s','%s','delete %s')" % (table, uuid, tenant_str, table[:-1])
945 #self.logger.debug(cmd)
946 #self.cur.execute(cmd)
947 return deleted, table[:-1] + " '%s' %s" %(uuid, "deleted" if deleted==1 else "not found")
948 except (mdb.Error, AttributeError) as e:
949 r,c = self.format_error(e, "delete_row", cmd, "delete", 'instances' if table=='hosts' or table=='tenants' else 'dependencies')
950 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
951
952 def delete_row_by_key(self, table, key, value):
953 for retry_ in range(0,2):
954 cmd=""
955 try:
956 with self.con:
957 #delete host
958 self.cur = self.con.cursor()
959 cmd = "DELETE FROM %s" % (table)
960 if key!=None:
961 if value!=None:
962 cmd += " WHERE %s = '%s'" % (key, value)
963 else:
964 cmd += " WHERE %s is null" % (key)
965 else: #delete all
966 pass
967 self.logger.debug(cmd)
968 self.cur.execute(cmd)
969 deleted = self.cur.rowcount
970 if deleted < 1:
971 return -1, 'Not found'
972 #delete uuid
973 return 0, deleted
974 except (mdb.Error, AttributeError) as e:
975 r,c = self.format_error(e, "delete_row_by_key", cmd, "delete", 'instances' if table=='hosts' or table=='tenants' else 'dependencies')
976 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
977
978 def delete_row_by_dict(self, **sql_dict):
979 ''' Deletes rows from a table.
980 Attribute sql_dir: dictionary with the following key: value
981 'FROM': string of table name (Mandatory)
982 'WHERE': dict of key:values, translated to key=value AND ... (Optional)
983 'WHERE_NOT': dict of key:values, translated to key<>value AND ... (Optional)
984 'WHERE_NOTNULL': (list or tuple of items that must not be null in a where ... (Optional)
985 'LIMIT': limit of number of rows (Optional)
986 Return: the (number of items deleted, descriptive test) if ok; (negative, descriptive text) if error
987 '''
988 #print sql_dict
989 from_ = "FROM " + str(sql_dict['FROM'])
990 #print 'from_', from_
991 if 'WHERE' in sql_dict and len(sql_dict['WHERE']) > 0:
992 w=sql_dict['WHERE']
993 where_ = "WHERE " + " AND ".join(map( lambda x: str(x) + (" is Null" if w[x] is None else "='"+str(w[x])+"'"), w.keys()) )
994 else: where_ = ""
995 if 'WHERE_NOT' in sql_dict and len(sql_dict['WHERE_NOT']) > 0:
996 w=sql_dict['WHERE_NOT']
997 where_2 = " AND ".join(map( lambda x: str(x) + (" is not Null" if w[x] is None else "<>'"+str(w[x])+"'"), w.keys()) )
998 if len(where_)==0: where_ = "WHERE " + where_2
999 else: where_ = where_ + " AND " + where_2
1000 if 'WHERE_NOTNULL' in sql_dict and len(sql_dict['WHERE_NOTNULL']) > 0:
1001 w=sql_dict['WHERE_NOTNULL']
1002 where_2 = " AND ".join(map( lambda x: str(x) + " is not Null", w) )
1003 if len(where_)==0: where_ = "WHERE " + where_2
1004 else: where_ = where_ + " AND " + where_2
1005 #print 'where_', where_
1006 limit_ = "LIMIT " + str(sql_dict['LIMIT']) if 'LIMIT' in sql_dict else ""
1007 #print 'limit_', limit_
1008 cmd = " ".join( ("DELETE", from_, where_, limit_) )
1009 self.logger.debug(cmd)
1010 for retry_ in range(0,2):
1011 try:
1012 with self.con:
1013 #delete host
1014 self.cur = self.con.cursor()
1015 self.cur.execute(cmd)
1016 deleted = self.cur.rowcount
1017 return deleted, "%d deleted from %s" % (deleted, sql_dict['FROM'][:-1] )
1018 except (mdb.Error, AttributeError) as e:
1019 r,c = self.format_error(e, "delete_row_by_dict", cmd, "delete", 'dependencies')
1020 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1021
1022
1023 def get_instance(self, instance_id):
1024 for retry_ in range(0,2):
1025 cmd=""
1026 try:
1027 with self.con:
1028 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1029 #get INSTANCE
1030 cmd = "SELECT uuid, name, description, progress, host_id, flavor_id, image_id, status, last_error, tenant_id, ram, vcpus, created_at \
1031 FROM instances WHERE uuid = '" + str(instance_id) +"'"
1032 self.logger.debug(cmd)
1033 self.cur.execute(cmd)
1034 if self.cur.rowcount == 0 : return 0, "instance '" + str(instance_id) +"'not found."
1035 instance = self.cur.fetchone()
1036 #get networks
1037 cmd = "SELECT uuid as iface_id, net_id, mac as mac_address, ip_address, name, Mbps as bandwidth, vpci, model \
1038 FROM ports WHERE type = 'instance:bridge' AND instance_id = '" + instance_id + "'"
1039 self.logger.debug(cmd)
1040 self.cur.execute(cmd)
1041 if self.cur.rowcount > 0 :
1042 instance['networks'] = self.cur.fetchall()
1043
1044 #get extended
1045 extended = {}
1046 #get devices
1047 cmd = "SELECT type, vpci, image_id, xml,dev FROM instance_devices WHERE instance_id = '%s' " % str(instance_id)
1048 self.logger.debug(cmd)
1049 self.cur.execute(cmd)
1050 if self.cur.rowcount > 0 :
1051 extended['devices'] = self.cur.fetchall()
1052 #get numas
1053 numas = []
1054 cmd = "SELECT id, numa_socket as source FROM numas WHERE host_id = '" + str(instance['host_id']) + "'"
1055 self.logger.debug(cmd)
1056 self.cur.execute(cmd)
1057 host_numas = self.cur.fetchall()
1058 #print 'host_numas', host_numas
1059 for k in host_numas:
1060 numa_id = str(k['id'])
1061 numa_dict ={}
1062 #get memory
1063 cmd = "SELECT consumed FROM resources_mem WHERE instance_id = '%s' AND numa_id = '%s'" % ( instance_id, numa_id)
1064 self.logger.debug(cmd)
1065 self.cur.execute(cmd)
1066 if self.cur.rowcount > 0:
1067 mem_dict = self.cur.fetchone()
1068 numa_dict['memory'] = mem_dict['consumed']
1069 #get full cores
1070 cursor2 = self.con.cursor()
1071 cmd = "SELECT core_id, paired, MIN(v_thread_id) as v1, MAX(v_thread_id) as v2, COUNT(instance_id) as nb, MIN(thread_id) as t1, MAX(thread_id) as t2 FROM resources_core WHERE instance_id = '%s' AND numa_id = '%s' GROUP BY core_id,paired" % ( str(instance_id), numa_id)
1072 self.logger.debug(cmd)
1073 cursor2.execute(cmd)
1074 core_list = []; core_source = []
1075 paired_list = []; paired_source = []
1076 thread_list = []; thread_source = []
1077 if cursor2.rowcount > 0:
1078 cores = cursor2.fetchall()
1079 for core in cores:
1080 if core[4] == 2: #number of used threads from core
1081 if core[3] == core[2]: #only one thread asigned to VM, so completely core
1082 core_list.append(core[2])
1083 core_source.append(core[5])
1084 elif core[1] == 'Y':
1085 paired_list.append(core[2:4])
1086 paired_source.append(core[5:7])
1087 else:
1088 thread_list.extend(core[2:4])
1089 thread_source.extend(core[5:7])
1090
1091 else:
1092 thread_list.append(core[2])
1093 thread_source.append(core[5])
1094 if len(core_list) > 0:
1095 numa_dict['cores'] = len(core_list)
1096 numa_dict['cores-id'] = core_list
1097 numa_dict['cores-source'] = core_source
1098 if len(paired_list) > 0:
1099 numa_dict['paired-threads'] = len(paired_list)
1100 numa_dict['paired-threads-id'] = paired_list
1101 numa_dict['paired-threads-source'] = paired_source
1102 if len(thread_list) > 0:
1103 numa_dict['threads'] = len(thread_list)
1104 numa_dict['threads-id'] = thread_list
1105 numa_dict['threads-source'] = thread_source
1106
1107 #get dedicated ports and SRIOV
1108 cmd = "SELECT port_id as iface_id, p.vlan as vlan, p.mac as mac_address, net_id, if(model='PF','yes',if(model='VF','no','yes:sriov')) as dedicated,\
1109 rp.Mbps as bandwidth, name, vpci, pci as source \
1110 FROM resources_port as rp join ports as p on port_id=uuid WHERE p.instance_id = '%s' AND numa_id = '%s' and p.type='instance:data'" % (instance_id, numa_id)
1111 self.logger.debug(cmd)
1112 self.cur.execute(cmd)
1113 if self.cur.rowcount > 0:
1114 numa_dict['interfaces'] = self.cur.fetchall()
1115 #print 'interfaces', numa_dict
1116
1117 if len(numa_dict) > 0 :
1118 numa_dict['source'] = k['source'] #numa socket
1119 numas.append(numa_dict)
1120
1121 if len(numas) > 0 : extended['numas'] = numas
1122 if len(extended) > 0 : instance['extended'] = extended
1123 af.DeleteNone(instance)
1124 return 1, instance
1125 except (mdb.Error, AttributeError) as e:
1126 r,c = self.format_error(e, "get_instance", cmd)
1127 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1128
1129 def get_numas(self, requirements, prefered_host_id=None, only_of_ports=True):
1130 '''Obtain a valid NUMA/HOST for deployment a VM
1131 requirements: contain requirement regarding:
1132 requirements['ram']: Non huge page memory in MB; 0 to skip
1133 requirements['vcpus']: Non isolated cpus; 0 to skip
1134 requirements['numa']: Requiremets to be fixed in ONE Numa node
1135 requirements['numa']['memory']: Huge page memory in GB at ; 0 for any
1136 requirements['numa']['proc_req_type']: Type of processor, cores or threads
1137 requirements['numa']['proc_req_nb']: Number of isolated cpus
1138 requirements['numa']['port_list']: Physical NIC ports list ; [] for any
1139 requirements['numa']['sriov_list']: Virtual function NIC ports list ; [] for any
1140 prefered_host_id: if not None return this host if it match
1141 only_of_ports: if True only those ports conected to the openflow (of) are valid,
1142 that is, with switch_port information filled; if False, all NIC ports are valid.
1143 Return a valid numa and host
1144 '''
1145
1146 for retry_ in range(0,2):
1147 cmd=""
1148 try:
1149 with self.con:
1150 # #Find numas of prefered host
1151 # prefered_numas = ()
1152 # if prefered_host_id != None:
1153 # self.cur = self.con.cursor()
1154 # self.cur.execute("SELECT id FROM numas WHERE host_id='%s'" + prefered_host_id)
1155 # prefered_numas = self.cur.fetchall()
1156 # self.cur.close()
1157
1158 #Find valid host for the ram and vcpus
1159 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1160 cmd = "CALL GetHostByMemCpu(%s, %s)" % (str(requirements['ram']), str(requirements['vcpus']))
1161 self.logger.debug(cmd)
1162 self.cur.callproc('GetHostByMemCpu', (str(requirements['ram']), str(requirements['vcpus'])) )
1163 valid_hosts = self.cur.fetchall()
1164 self.cur.close()
1165 self.cur = self.con.cursor()
1166 match_found = False
1167 if len(valid_hosts)<=0:
1168 error_text = 'No room at data center. Can not find a host with %s MB memory and %s cpus available' % (str(requirements['ram']), str(requirements['vcpus']))
1169 #self.logger.debug(error_text)
1170 return -1, error_text
1171
1172 #elif req_numa != None:
1173 #Find valid numa nodes for memory requirements
1174 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1175 cmd = "CALL GetNumaByMemory(%s)" % str(requirements['numa']['memory'])
1176 self.logger.debug(cmd)
1177 self.cur.callproc('GetNumaByMemory', (requirements['numa']['memory'],) )
1178 valid_for_memory = self.cur.fetchall()
1179 self.cur.close()
1180 self.cur = self.con.cursor()
1181 if len(valid_for_memory)<=0:
1182 error_text = 'No room at data center. Can not find a host with %s GB Hugepages memory available' % str(requirements['numa']['memory'])
1183 #self.logger.debug(error_text)
1184 return -1, error_text
1185
1186 #Find valid numa nodes for processor requirements
1187 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1188 if requirements['numa']['proc_req_type'] == 'threads':
1189 cpu_requirement_text='cpu-threads'
1190 cmd = "CALL GetNumaByThread(%s)" % str(requirements['numa']['proc_req_nb'])
1191 self.logger.debug(cmd)
1192 self.cur.callproc('GetNumaByThread', (requirements['numa']['proc_req_nb'],) )
1193 else:
1194 cpu_requirement_text='cpu-cores'
1195 cmd = "CALL GetNumaByCore(%s)" % str(requirements['numa']['proc_req_nb'])
1196 self.logger.debug(cmd)
1197 self.cur.callproc('GetNumaByCore', (requirements['numa']['proc_req_nb'],) )
1198 valid_for_processor = self.cur.fetchall()
1199 self.cur.close()
1200 self.cur = self.con.cursor()
1201 if len(valid_for_processor)<=0:
1202 error_text = 'No room at data center. Can not find a host with %s %s available' % (str(requirements['numa']['proc_req_nb']),cpu_requirement_text)
1203 #self.logger.debug(error_text)
1204 return -1, error_text
1205
1206 #Find the numa nodes that comply for memory and processor requirements
1207 #sorting from less to more memory capacity
1208 valid_numas = []
1209 for m_numa in valid_for_memory:
1210 numa_valid_for_processor = False
1211 for p_numa in valid_for_processor:
1212 if m_numa['numa_id'] == p_numa['numa_id']:
1213 numa_valid_for_processor = True
1214 break
1215 numa_valid_for_host = False
1216 prefered_numa = False
1217 for p_host in valid_hosts:
1218 if m_numa['host_id'] == p_host['uuid']:
1219 numa_valid_for_host = True
1220 if p_host['uuid'] == prefered_host_id:
1221 prefered_numa = True
1222 break
1223 if numa_valid_for_host and numa_valid_for_processor:
1224 if prefered_numa:
1225 valid_numas.insert(0, m_numa['numa_id'])
1226 else:
1227 valid_numas.append(m_numa['numa_id'])
1228 if len(valid_numas)<=0:
1229 error_text = 'No room at data center. Can not find a host with %s MB hugepages memory and %s %s available in the same numa' %\
1230 (requirements['numa']['memory'], str(requirements['numa']['proc_req_nb']),cpu_requirement_text)
1231 #self.logger.debug(error_text)
1232 return -1, error_text
1233
1234 # print 'Valid numas list: '+str(valid_numas)
1235
1236 #Find valid numa nodes for interfaces requirements
1237 #For each valid numa we will obtain the number of available ports and check if these are valid
1238 match_found = False
1239 for numa_id in valid_numas:
1240 # print 'Checking '+str(numa_id)
1241 match_found = False
1242 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1243 if only_of_ports:
1244 cmd="CALL GetAvailablePorts(%s)" % str(numa_id)
1245 self.logger.debug(cmd)
1246 self.cur.callproc('GetAvailablePorts', (numa_id,) )
1247 else:
1248 cmd="CALL GetAllAvailablePorts(%s)" % str(numa_id)
1249 self.logger.debug(cmd)
1250 self.cur.callproc('GetAllAvailablePorts', (numa_id,) )
1251 available_ports = self.cur.fetchall()
1252 self.cur.close()
1253 self.cur = self.con.cursor()
1254
1255 #Set/reset reservations
1256 for port in available_ports:
1257 port['Mbps_reserved'] = 0
1258 port['SRIOV_reserved'] = 0
1259
1260 #Try to allocate physical ports
1261 physical_ports_found = True
1262 for iface in requirements['numa']['port_list']:
1263 # print '\t\tchecking iface: '+str(iface)
1264 portFound = False
1265 for port in available_ports:
1266 # print '\t\t\tfor port: '+str(port)
1267 #If the port is not empty continue
1268 if port['Mbps_free'] != port['Mbps'] or port['Mbps_reserved'] != 0:
1269 # print '\t\t\t\t Not empty port'
1270 continue;
1271 #If the port speed is not enough continue
1272 if port['Mbps'] < iface['bandwidth']:
1273 # print '\t\t\t\t Not enough speed'
1274 continue;
1275
1276 #Otherwise this is a valid port
1277 port['Mbps_reserved'] = port['Mbps']
1278 port['SRIOV_reserved'] = 0
1279 iface['port_id'] = port['port_id']
1280 iface['vlan'] = None
1281 iface['mac'] = port['mac']
1282 iface['switch_port'] = port['switch_port']
1283 # print '\t\t\t\t Dedicated port found '+str(port['port_id'])
1284 portFound = True
1285 break;
1286
1287 #if all ports have been checked and no match has been found
1288 #this is not a valid numa
1289 if not portFound:
1290 # print '\t\t\t\t\tAll ports have been checked and no match has been found for numa '+str(numa_id)+'\n\n'
1291 physical_ports_found = False
1292 break
1293
1294 #if there is no match continue checking the following numa
1295 if not physical_ports_found:
1296 continue
1297
1298 #Try to allocate SR-IOVs
1299 sriov_ports_found = True
1300 for iface in requirements['numa']['sriov_list']:
1301 # print '\t\tchecking iface: '+str(iface)
1302 portFound = False
1303 for port in available_ports:
1304 # print '\t\t\tfor port: '+str(port)
1305 #If there are not available SR-IOVs continue
1306 if port['availableSRIOV'] - port['SRIOV_reserved'] <= 0:
1307 # print '\t\t\t\t Not enough SR-IOV'
1308 continue;
1309 #If the port free speed is not enough continue
1310 if port['Mbps_free'] - port['Mbps_reserved'] < iface['bandwidth']:
1311 # print '\t\t\t\t Not enough speed'
1312 continue;
1313
1314 #Otherwise this is a valid port
1315 port['Mbps_reserved'] += iface['bandwidth']
1316 port['SRIOV_reserved'] += 1
1317 # print '\t\t\t\t SR-IOV found '+str(port['port_id'])
1318 iface['port_id'] = port['port_id']
1319 iface['vlan'] = None
1320 iface['mac'] = port['mac']
1321 iface['switch_port'] = port['switch_port']
1322 portFound = True
1323 break;
1324
1325 #if all ports have been checked and no match has been found
1326 #this is not a valid numa
1327 if not portFound:
1328 # print '\t\t\t\t\tAll ports have been checked and no match has been found for numa '+str(numa_id)+'\n\n'
1329 sriov_ports_found = False
1330 break
1331
1332 #if there is no match continue checking the following numa
1333 if not sriov_ports_found:
1334 continue
1335
1336
1337 if sriov_ports_found and physical_ports_found:
1338 match_found = True
1339 break
1340
1341 if not match_found:
1342 error_text = 'No room at data center. Can not find a host with the required hugepages, vcpus and interfaces'
1343 #self.logger.debug(error_text)
1344 return -1, error_text
1345
1346 #self.logger.debug('Full match found in numa %s', str(numa_id))
1347
1348 for numa in valid_for_processor:
1349 if numa_id==numa['numa_id']:
1350 host_id=numa['host_id']
1351 break
1352 return 0, {'numa_id':numa_id, 'host_id': host_id, }
1353 except (mdb.Error, AttributeError) as e:
1354 r,c = self.format_error(e, "get_numas", cmd)
1355 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1356
1357 def new_instance(self, instance_dict, nets, ports_to_free):
1358 for retry_ in range(0,2):
1359 cmd=""
1360 try:
1361 with self.con:
1362 self.cur = self.con.cursor()
1363
1364 #create uuid if not provided
1365 if 'uuid' not in instance_dict:
1366 uuid = instance_dict['uuid'] = str(myUuid.uuid1()) # create_uuid
1367 else: #check uuid is valid
1368 uuid = str(instance_dict['uuid'])
1369
1370
1371 #inserting new uuid
1372 cmd = "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'instances')" % (uuid, uuid)
1373 self.logger.debug(cmd)
1374 self.cur.execute(cmd)
1375
1376 #insert in table instance
1377 extended = instance_dict.pop('extended', None);
1378 bridgedifaces = instance_dict.pop('bridged-ifaces', () );
1379
1380 keys = ",".join(instance_dict.keys())
1381 values = ",".join( map(lambda x: "Null" if x is None else "'"+str(x)+"'", instance_dict.values() ) )
1382 cmd = "INSERT INTO instances (" + keys + ") VALUES (" + values + ")"
1383 self.logger.debug(cmd)
1384 self.cur.execute(cmd)
1385 #if result != 1: return -1, "Database Error while inserting at instances table"
1386
1387 #insert resources
1388 nb_bridge_ifaces = nb_cores = nb_ifaces = nb_numas = 0
1389 #insert bridged_ifaces
1390 for iface in bridgedifaces:
1391 #generate and insert a iface uuid
1392 iface['uuid'] = str(myUuid.uuid1()) # create_uuid
1393 cmd = "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'ports')" % (iface['uuid'], uuid)
1394 self.logger.debug(cmd)
1395 self.cur.execute(cmd)
1396 #insert iface
1397 iface['instance_id'] = uuid
1398 iface['type'] = 'instance:bridge'
1399 if 'name' not in iface: iface['name']="br"+str(nb_bridge_ifaces)
1400 iface['Mbps']=iface.pop('bandwidth', None)
1401 if 'mac_address' not in iface:
1402 iface['mac'] = af.gen_random_mac()
1403 else:
1404 iface['mac'] = iface['mac_address']
1405 del iface['mac_address']
1406 #iface['mac']=iface.pop('mac_address', None) #for leaving mac generation to libvirt
1407 keys = ",".join(iface.keys())
1408 values = ",".join( map(lambda x: "Null" if x is None else "'"+str(x)+"'", iface.values() ) )
1409 cmd = "INSERT INTO ports (" + keys + ") VALUES (" + values + ")"
1410 self.logger.debug(cmd)
1411 self.cur.execute(cmd)
1412 nb_bridge_ifaces += 1
1413
1414 if extended is not None:
1415 if 'numas' not in extended or extended['numas'] is None: extended['numas'] = ()
1416 for numa in extended['numas']:
1417 nb_numas += 1
1418 #cores
1419 if 'cores' not in numa or numa['cores'] is None: numa['cores'] = ()
1420 for core in numa['cores']:
1421 nb_cores += 1
1422 cmd = "UPDATE resources_core SET instance_id='%s'%s%s WHERE id='%s'" \
1423 % (uuid, \
1424 (",v_thread_id='" + str(core['vthread']) + "'") if 'vthread' in core else '', \
1425 (",paired='" + core['paired'] + "'") if 'paired' in core else '', \
1426 core['id'] )
1427 self.logger.debug(cmd)
1428 self.cur.execute(cmd)
1429 #interfaces
1430 if 'interfaces' not in numa or numa['interfaces'] is None: numa['interfaces'] = ()
1431 for iface in numa['interfaces']:
1432 #generate and insert an uuid; iface[id]=iface_uuid; iface[uuid]= net_id
1433 iface['id'] = str(myUuid.uuid1()) # create_uuid
1434 cmd = "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'ports')" % (iface['id'], uuid)
1435 self.logger.debug(cmd)
1436 self.cur.execute(cmd)
1437 nb_ifaces += 1
1438 mbps_=("'"+str(iface['Mbps_used'])+"'") if 'Mbps_used' in iface and iface['Mbps_used'] is not None else "Mbps"
1439 if iface["dedicated"]=="yes":
1440 iface_model="PF"
1441 elif iface["dedicated"]=="yes:sriov":
1442 iface_model="VFnotShared"
1443 elif iface["dedicated"]=="no":
1444 iface_model="VF"
1445 #else error
1446 INSERT=(iface['mac_address'], iface['switch_port'], iface.get('vlan',None), 'instance:data', iface['Mbps_used'], iface['id'],
1447 uuid, instance_dict['tenant_id'], iface.get('name',None), iface.get('vpci',None), iface.get('uuid',None), iface_model )
1448 cmd = "INSERT INTO ports (mac,switch_port,vlan,type,Mbps,uuid,instance_id,tenant_id,name,vpci,net_id, model) " + \
1449 " VALUES (" + ",".join(map(lambda x: 'Null' if x is None else "'"+str(x)+"'", INSERT )) + ")"
1450 self.logger.debug(cmd)
1451 self.cur.execute(cmd)
1452 if 'uuid' in iface:
1453 nets.append(iface['uuid'])
1454
1455 #discover if this port is not used by anyone
1456 cmd = "SELECT source_name, mac FROM ( SELECT root_id, count(instance_id) as used FROM resources_port" \
1457 " WHERE root_id=(SELECT root_id from resources_port WHERE id='%s')"\
1458 " GROUP BY root_id ) AS A JOIN resources_port as B ON A.root_id=B.id AND A.used=0" % iface['port_id']
1459 self.logger.debug(cmd)
1460 self.cur.execute(cmd)
1461 ports_to_free += self.cur.fetchall()
1462
1463 cmd = "UPDATE resources_port SET instance_id='%s', port_id='%s',Mbps_used=%s WHERE id='%s'" \
1464 % (uuid, iface['id'], mbps_, iface['port_id'])
1465 #if Mbps_used not suply, set the same value of 'Mpbs', that is the total
1466 self.logger.debug(cmd)
1467 self.cur.execute(cmd)
1468 #memory
1469 if 'memory' in numa and numa['memory'] is not None and numa['memory']>0:
1470 cmd = "INSERT INTO resources_mem (numa_id, instance_id, consumed) VALUES ('%s','%s','%s')" % (numa['numa_id'], uuid, numa['memory'])
1471 self.logger.debug(cmd)
1472 self.cur.execute(cmd)
1473 if 'devices' not in extended or extended['devices'] is None: extended['devices'] = ()
1474 for device in extended['devices']:
1475 if 'vpci' in device: vpci = "'" + device['vpci'] + "'"
1476 else: vpci = 'Null'
1477 if 'image_id' in device: image_id = "'" + device['image_id'] + "'"
1478 else: image_id = 'Null'
1479 if 'xml' in device: xml = "'" + device['xml'] + "'"
1480 else: xml = 'Null'
1481 if 'dev' in device: dev = "'" + device['dev'] + "'"
1482 else: dev = 'Null'
1483 cmd = "INSERT INTO instance_devices (type, instance_id, image_id, vpci, xml, dev) VALUES ('%s','%s', %s, %s, %s, %s)" % \
1484 (device['type'], uuid, image_id, vpci, xml, dev)
1485 self.logger.debug(cmd)
1486 self.cur.execute(cmd)
1487 ##inserting new log
1488 #cmd = "INSERT INTO logs (related,level,uuid,description) VALUES ('instances','debug','%s','new instance: %d numas, %d theads, %d ifaces %d bridge_ifaces')" % (uuid, nb_numas, nb_cores, nb_ifaces, nb_bridge_ifaces)
1489 #self.logger.debug(cmd)
1490 #self.cur.execute(cmd)
1491
1492 #inseted ok
1493 return 1, uuid
1494 except (mdb.Error, AttributeError) as e:
1495 r,c = self.format_error(e, "new_instance", cmd)
1496 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1497
1498 def delete_instance(self, instance_id, tenant_id, net_list, ports_to_free, logcause="requested by http"):
1499 for retry_ in range(0,2):
1500 cmd=""
1501 try:
1502 with self.con:
1503 self.cur = self.con.cursor()
1504 #get INSTANCE
1505 cmd = "SELECT uuid FROM instances WHERE uuid='%s' AND tenant_id='%s'" % (instance_id, tenant_id)
1506 self.logger.debug(cmd)
1507 self.cur.execute(cmd)
1508 if self.cur.rowcount == 0 : return 0, "instance %s not found in tenant %s" % (instance_id, tenant_id)
1509
1510 #delete bridged ifaces, instace_devices, resources_mem; done by database: it is automatic by Database; FOREIGN KEY DELETE CASCADE
1511
1512 #get nets afected
1513 cmd = "SELECT DISTINCT net_id from ports WHERE instance_id = '%s' AND net_id is not Null AND type='instance:data'" % instance_id
1514 self.logger.debug(cmd)
1515 self.cur.execute(cmd)
1516 net_list__ = self.cur.fetchall()
1517 for net in net_list__:
1518 net_list.append(net[0])
1519
1520 #get dataplane interfaces releases by this VM; both PF and VF with no other VF
1521 cmd="SELECT source_name, mac FROM (SELECT root_id, count(instance_id) as used FROM resources_port WHERE instance_id='%s' GROUP BY root_id ) AS A" % instance_id \
1522 + " JOIN (SELECT root_id, count(instance_id) as used FROM resources_port GROUP BY root_id) AS B ON A.root_id=B.root_id AND A.used=B.used"\
1523 + " JOIN resources_port as C ON A.root_id=C.id"
1524 # cmd = "SELECT DISTINCT root_id FROM resources_port WHERE instance_id = '%s'" % instance_id
1525 self.logger.debug(cmd)
1526 self.cur.execute(cmd)
1527 ports_to_free += self.cur.fetchall()
1528
1529 #update resources port
1530 cmd = "UPDATE resources_port SET instance_id=Null, port_id=Null, Mbps_used='0' WHERE instance_id = '%s'" % instance_id
1531 self.logger.debug(cmd)
1532 self.cur.execute(cmd)
1533
1534 # #filter dataplane ports used by this VM that now are free
1535 # for port in ports_list__:
1536 # cmd = "SELECT mac, count(instance_id) FROM resources_port WHERE root_id = '%s'" % port[0]
1537 # self.logger.debug(cmd)
1538 # self.cur.execute(cmd)
1539 # mac_list__ = self.cur.fetchone()
1540 # if mac_list__ and mac_list__[1]==0:
1541 # ports_to_free.append(mac_list__[0])
1542
1543
1544 #update resources core
1545 cmd = "UPDATE resources_core SET instance_id=Null, v_thread_id=Null, paired='N' WHERE instance_id = '%s'" % instance_id
1546 self.logger.debug(cmd)
1547 self.cur.execute(cmd)
1548
1549 #delete all related uuids
1550 cmd = "DELETE FROM uuids WHERE root_uuid='%s'" % instance_id
1551 self.logger.debug(cmd)
1552 self.cur.execute(cmd)
1553
1554 ##insert log
1555 #cmd = "INSERT INTO logs (related,level,uuid,description) VALUES ('instances','debug','%s','delete instance %s')" % (instance_id, logcause)
1556 #self.logger.debug(cmd)
1557 #self.cur.execute(cmd)
1558
1559 #delete instance
1560 cmd = "DELETE FROM instances WHERE uuid='%s' AND tenant_id='%s'" % (instance_id, tenant_id)
1561 self.cur.execute(cmd)
1562 return 1, "instance %s from tenant %s DELETED" % (instance_id, tenant_id)
1563
1564 except (mdb.Error, AttributeError) as e:
1565 r,c = self.format_error(e, "delete_instance", cmd)
1566 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1567
1568 def get_ports(self, WHERE):
1569 ''' Obtain ports using the WHERE filtering.
1570 Attributes:
1571 'where_': dict of key:values, translated to key=value AND ... (Optional)
1572 Return: a list with dictionarys at each row
1573 '''
1574 for retry_ in range(0,2):
1575 cmd=""
1576 try:
1577 with self.con:
1578
1579 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1580 select_ = "SELECT uuid,'ACTIVE' as status,admin_state_up,name,net_id,\
1581 tenant_id,type,mac,vlan,switch_port,instance_id,Mbps FROM ports "
1582
1583 if WHERE is None or len(WHERE) == 0: where_ = ""
1584 else:
1585 where_ = "WHERE " + " AND ".join(map( lambda x: str(x) + (" is Null" if WHERE[x] is None else "='"+str(WHERE[x])+"'"), WHERE.keys()) )
1586 limit_ = "LIMIT 100"
1587 cmd = " ".join( (select_, where_, limit_) )
1588 # print "SELECT multiple de instance_ifaces, iface_uuid, external_ports" #print cmd
1589 self.logger.debug(cmd)
1590 self.cur.execute(cmd)
1591 ports = self.cur.fetchall()
1592 if self.cur.rowcount>0: af.DeleteNone(ports)
1593 return self.cur.rowcount, ports
1594 # return self.get_table(FROM=from_, SELECT=select_,WHERE=where_,LIMIT=100)
1595 except (mdb.Error, AttributeError) as e:
1596 r,c = self.format_error(e, "get_ports", cmd)
1597 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1598
1599 def check_target_net(self, net_id, tenant_id, port_type):
1600 '''check if valid attachement of a port into a target net
1601 Attributes:
1602 net_id: target net uuid
1603 tenant_id: client where tenant belongs. Not used in this version
1604 port_type: string with the option 'instance:bridge', 'instance:data', 'external'
1605 Return:
1606 (0,net_dict) if ok, where net_dict contain 'uuid','type','vlan', ...
1607 (negative,string-error) if error
1608 '''
1609 for retry_ in range(0,2):
1610 cmd=""
1611 try:
1612 with self.con:
1613 self.cur = self.con.cursor(mdb.cursors.DictCursor)
1614 cmd = "SELECT * FROM nets WHERE uuid='%s'" % net_id
1615 self.logger.debug(cmd)
1616 self.cur.execute(cmd)
1617 if self.cur.rowcount == 0 : return -1, "network_id %s does not match any net" % net_id
1618 net = self.cur.fetchone()
1619 break
1620
1621 except (mdb.Error, AttributeError) as e:
1622 r,c = self.format_error(e, "check_target_net", cmd)
1623 if r!=-HTTP_Request_Timeout or retry_==1: return r,c
1624 #check permissions
1625 if tenant_id is not None and tenant_id is not "admin":
1626 if net['tenant_id']==tenant_id and net['shared']=='false':
1627 return -1, "needed admin privileges to attach to the net %s" % net_id
1628 #check types
1629 if (net['type'] in ('p2p','data') and 'port_type' == 'instance:bridge') or \
1630 (net['type'] in ('bridge_data','bridge_man') and 'port_type' != 'instance:bridge') :
1631 return -1, "can not attach a port of type %s into a net of type %s" % (port_type, net['type'])
1632 if net['type'] == 'ptp':
1633 #look how many
1634 nb_ports, data = self.get_ports( {'net_id':net_id} )
1635 if nb_ports<0:
1636 return -1, data
1637 else:
1638 if net['provider']:
1639 nb_ports +=1
1640 if nb_ports >=2:
1641 return -1, "net of type p2p already contain two ports attached. No room for another"
1642
1643 return 0, net
1644
1645 if __name__ == "__main__":
1646 print "Hello World"