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