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