2 # -*- coding: utf-8 -*-
5 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
6 # This file is part of openvim
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
13 # http://www.apache.org/licenses/LICENSE-2.0
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
21 # For those usages not covered by the Apache License, Version 2.0 please
22 # contact with: nfvlabs@tid.es
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
32 __author__
="Alfonso Tierno"
33 __date__
="$10-jul-2014 12:07:15$"
37 import auxiliary_functions
as af
40 from netaddr
import IPNetwork
, IPSet
, IPRange
, all_matching_cidrs
42 HTTP_Bad_Request
= 400
43 HTTP_Unauthorized
= 401
45 HTTP_Method_Not_Allowed
= 405
46 HTTP_Request_Timeout
= 408
48 HTTP_Service_Unavailable
= 503
49 HTTP_Internal_Server_Error
= 500
53 def __init__(self
, vlan_range
, debug
="ERROR"):
54 '''vlan_range must be a tuple (vlan_ini, vlan_end) with available vlan values for networks
55 every dataplane network contain a unique value, regardless of it is used or not
58 self
.net_vlan_range
= vlan_range
59 self
.net_vlan_usedlist
= None
60 self
.net_vlan_lastused
= self
.net_vlan_range
[0] -1
62 self
.logger
= logging
.getLogger('vim.db')
63 self
.logger
.setLevel( getattr(logging
, debug
) )
66 def connect(self
, host
=None, user
=None, passwd
=None, database
=None):
67 '''Connect to the concrete data base.
68 The first time a valid host, user, passwd and database must be provided,
69 Following calls can skip this parameters
72 if host
is not None: self
.host
= host
73 if user
is not None: self
.user
= user
74 if passwd
is not None: self
.passwd
= passwd
75 if database
is not None: self
.database
= database
77 self
.con
= mdb
.connect(self
.host
, self
.user
, self
.passwd
, self
.database
)
78 self
.logger
.debug("connected to DB %s at %s@%s", self
.database
,self
.user
, self
.host
)
80 except mdb
.Error
as e
:
81 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])
84 def get_db_version(self
):
85 ''' Obtain the database schema version.
86 Return: (negative, text) if error or version 0.0 where schema_version table is missing
87 (version_int, version_text) if ok
89 cmd
= "SELECT version_int,version,openvim_ver FROM schema_version"
90 for retry_
in range(0,2):
93 self
.cur
= self
.con
.cursor()
94 self
.logger
.debug(cmd
)
96 rows
= self
.cur
.fetchall()
100 for row
in rows
: #look for the latest version
101 if row
[0]>highest_version_int
:
102 highest_version_int
, highest_version
= row
[0:2]
103 return highest_version_int
, highest_version
104 except (mdb
.Error
, AttributeError) as e
:
105 self
.logger
.error("get_db_version DB Exception %d: %s. Command %s",e
.args
[0], e
.args
[1], cmd
)
106 r
,c
= self
.format_error(e
)
107 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
109 def disconnect(self
):
110 '''disconnect from the data base'''
114 except mdb
.Error
as e
:
115 self
.logger
.error("while disconnecting from DB: Error %d: %s",e
.args
[0], e
.args
[1])
117 except AttributeError as e
: #self.con not defined
118 if e
[0][-5:] == "'con'": return -1, "Database internal error, no connection."
121 def format_error(self
, e
, func
, cmd
, command
=None, extra
=None):
122 '''Creates a text error base on the produced exception
125 func: name of the function that makes the call, for logging purposes
126 cmd: database command that produce the exception
127 command: if the intention is update or delete
128 extra: extra information to add to some commands
130 HTTP error in negative, formatted error text
133 self
.logger
.error("%s DB Exception %s. Command %s",func
, str(e
), cmd
)
134 if type(e
[0]) is str:
135 if e
[0][-5:] == "'con'": return -HTTP_Internal_Server_Error
, "DB Exception, no connection."
137 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
140 return -HTTP_Request_Timeout
,"Database reconnection. Try Again"
141 fk
=e
.args
[1].find("foreign key constraint fails")
143 if command
=="update": return -HTTP_Bad_Request
, "tenant_id %s not found." % extra
144 elif command
=="delete": return -HTTP_Bad_Request
, "Resource is not free. There are %s that prevent its deletion." % extra
145 de
= e
.args
[1].find("Duplicate entry")
146 fk
= e
.args
[1].find("for key")
147 uk
= e
.args
[1].find("Unknown column")
148 wc
= e
.args
[1].find("in 'where clause'")
149 fl
= e
.args
[1].find("in 'field list'")
150 #print de, fk, uk, wc,fl
152 if fk
>=0: #error 1062
153 return -HTTP_Conflict
, "Value %s already in use for %s" % (e
.args
[1][de
+15:fk
], e
.args
[1][fk
+7:])
156 return -HTTP_Bad_Request
, "Field %s can not be used for filtering" % e
.args
[1][uk
+14:wc
]
158 return -HTTP_Bad_Request
, "Field %s does not exist" % e
.args
[1][uk
+14:wc
]
159 return -HTTP_Internal_Server_Error
, "Database internal Error %d: %s" % (e
.args
[0], e
.args
[1])
161 def __data2db_format(self
, data
):
162 '''convert data to database format. If data is None it return the 'Null' text,
163 otherwise it return the text surrounded by quotes ensuring internal quotes are escaped'''
168 return "'" + out
+ "'"
170 return '"' + out
+ '"'
172 return json
.dumps(out
)
174 def __get_used_net_vlan(self
):
175 #get used from database if needed
177 cmd
= "SELECT vlan FROM nets WHERE vlan>='%s' ORDER BY vlan LIMIT 25" % self
.net_vlan_lastused
179 self
.cur
= self
.con
.cursor()
180 self
.logger
.debug(cmd
)
181 self
.cur
.execute(cmd
)
182 vlan_tuple
= self
.cur
.fetchall()
183 #convert a tuple of tuples in a list of numbers
184 self
.net_vlan_usedlist
= []
186 self
.net_vlan_usedlist
.append(k
[0])
188 except (mdb
.Error
, AttributeError) as e
:
189 return self
.format_error(e
, "get_free_net_vlan", cmd
)
191 def get_free_net_vlan(self
):
192 '''obtain a vlan not used in any net'''
195 self
.logger
.debug("net_vlan_lastused:%d net_vlan_range:%d-%d net_vlan_usedlist:%s",
196 self
.net_vlan_lastused
, self
.net_vlan_range
[0], self
.net_vlan_range
[1], str(self
.net_vlan_usedlist
))
197 self
.net_vlan_lastused
+= 1
198 if self
.net_vlan_lastused
== self
.net_vlan_range
[1]:
199 #start from the begining
200 self
.net_vlan_lastused
= self
.net_vlan_range
[0]
201 self
.net_vlan_usedlist
= None
202 if self
.net_vlan_usedlist
is None \
203 or (len(self
.net_vlan_usedlist
)>0 and self
.net_vlan_lastused
>= self
.net_vlan_usedlist
[-1] and len(self
.net_vlan_usedlist
)==25):
204 r
= self
.__get
_used
_net
_vlan
()
206 self
.logger
.debug("new net_vlan_usedlist %s", str(self
.net_vlan_usedlist
))
207 if self
.net_vlan_lastused
in self
.net_vlan_usedlist
:
210 return self
.net_vlan_lastused
212 def get_table(self
, **sql_dict
):
213 ''' Obtain rows from a table.
214 Atribure sql_dir: dictionary with the following key: value
215 'SELECT': [list of fields to retrieve] (by default all)
216 'FROM': string of table name (Mandatory)
217 'WHERE': dict of key:values, translated to key=value AND ... (Optional)
218 'WHERE_NOT': dict of key:values, translated to key!=value AND ... (Optional)
219 'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
220 'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional)
221 'LIMIT': limit of number of rows (Optional)
222 'DISTINCT': make a select distinct to remove repeated elements
223 Return: a list with dictionarys at each row
227 if sql_dict
.get("DISTINCT"):
228 select_
+= "DISTINCT "
229 select_
+= ("*" if not sql_dict
.get('SELECT') else ",".join(map(str,sql_dict
['SELECT'])) )
230 #print 'select_', select_
231 from_
= "FROM " + str(sql_dict
['FROM'])
232 #print 'from_', from_
236 w
= sql_dict
.get('WHERE')
238 where_and
= " AND ".join(map( lambda x
: str(x
) + (" is Null" if w
[x
] is None else "='"+str(w
[x
])+"'"), w
.keys()) )
239 w
= sql_dict
.get('WHERE_NOT')
241 where_and_not
= " AND ".join(map( lambda x
: str(x
) + (" is not Null" if w
[x
] is None else "!='"+str(w
[x
])+"'"), w
.keys()) )
243 where_and
+= " AND " + where_and_not
245 where_and
= where_and_not
246 w
= sql_dict
.get('WHERE_OR')
248 where_or
= " OR ".join(map( lambda x
: str(x
) + (" is Null" if w
[x
] is None else "='"+str(w
[x
])+"'"), w
.keys()) )
250 if where_and
!=None and where_or
!=None:
251 if sql_dict
.get("WHERE_AND_OR") == "AND":
252 where_
= "WHERE " + where_and
+ " AND (" + where_or
+ ")"
254 where_
= "WHERE (" + where_and
+ ") OR " + where_or
255 elif where_and
!=None and where_or
==None:
256 where_
= "WHERE " + where_and
257 elif where_and
==None and where_or
!=None:
258 where_
= "WHERE " + where_or
261 #print 'where_', where_
262 limit_
= "LIMIT " + str(sql_dict
['LIMIT']) if sql_dict
.get("LIMIT") else ""
263 #print 'limit_', limit_
264 cmd
= " ".join( (select_
, from_
, where_
, limit_
) )
265 for retry_
in range(0,2):
268 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
269 self
.logger
.debug(cmd
)
270 self
.cur
.execute(cmd
)
271 rows
= self
.cur
.fetchall()
272 return self
.cur
.rowcount
, rows
273 except (mdb
.Error
, AttributeError) as e
:
274 r
,c
= self
.format_error(e
, "get_table", cmd
)
275 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
277 def new_tenant(self
, tenant_dict
):
278 ''' Add one row into a table.
280 tenant_dict: dictionary with the key: value to insert
281 It checks presence of uuid and add one automatically otherwise
282 Return: (result, uuid) where result can be 0 if error, or 1 if ok
284 for retry_
in range(0,2):
288 #create uuid if not provided
289 if 'uuid' not in tenant_dict
:
290 uuid
= tenant_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
292 uuid
= str(tenant_dict
['uuid'])
293 #obtain tenant_id for logs
296 self
.cur
= self
.con
.cursor()
298 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','tenants')" % uuid
299 self
.logger
.debug(cmd
)
300 self
.cur
.execute(cmd
)
302 cmd
= "INSERT INTO tenants (" + \
303 ",".join(map(str, tenant_dict
.keys() )) + ") VALUES(" + \
304 ",".join(map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'",tenant_dict
.values() )) + ")"
305 self
.logger
.debug(cmd
)
306 self
.cur
.execute(cmd
)
307 inserted
= self
.cur
.rowcount
309 #del tenant_dict['uuid'] # not interested for the log
310 #cmd = "INSERT INTO logs (related,level,tenant_id,uuid,description) VALUES ('tenants','debug','%s','%s',\"new tenant %s\")" % (uuid, tenant_id, str(tenant_dict))
311 #self.logger.debug(cmd)
312 #self.cur.execute(cmd)
315 if inserted
== 0: return 0, uuid
317 self
.cur
= self
.con
.cursor()
318 #adding public flavors
319 cmd
= "INSERT INTO tenants_flavors(flavor_id,tenant_id) SELECT uuid as flavor_id,'"+ tenant_id
+ "' FROM flavors WHERE public = 'yes'"
320 self
.logger
.debug(cmd
)
321 self
.cur
.execute(cmd
)
322 self
.logger
.debug("attached public flavors: %s", str(self
.cur
.rowcount
))
323 #rows = self.cur.fetchall()
325 # cmd = "INSERT INTO tenants_flavors(flavor_id,tenant_id) VALUES('%s','%s')" % (row[0], tenant_id)
326 # self.cur.execute(cmd )
327 #adding public images
328 cmd
= "INSERT INTO tenants_images(image_id,tenant_id) SELECT uuid as image_id,'"+ tenant_id
+ "' FROM images WHERE public = 'yes'"
329 self
.logger
.debug(cmd
)
330 self
.cur
.execute(cmd
)
331 self
.logger
.debug("attached public images: %s", str(self
.cur
.rowcount
))
333 except (mdb
.Error
, AttributeError) as e
:
335 self
.logger
.warning("new_tenant DB Exception %d: %s. Command %s",e
.args
[0], e
.args
[1], cmd
)
338 r
,c
= self
.format_error(e
, "new_tenant", cmd
)
339 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
341 def new_row(self
, table
, INSERT
, add_uuid
=False, log
=False):
342 ''' Add one row into a table.
344 INSERT: dictionary with the key: value to insert
345 table: table where to insert
346 add_uuid: if True, it will crated an uuid key entry at INSERT if not provided
347 It checks presence of uuid and add one automatically otherwise
348 Return: (result, uuid) where result can be 0 if error, or 1 if ok
350 for retry_
in range(0,2):
354 #create uuid if not provided
355 if 'uuid' not in INSERT
:
356 uuid
= INSERT
['uuid'] = str(myUuid
.uuid1()) # create_uuid
358 uuid
= str(INSERT
['uuid'])
362 self
.cur
= self
.con
.cursor()
365 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','%s')" % (uuid
, table
)
366 self
.logger
.debug(cmd
)
367 self
.cur
.execute(cmd
)
369 cmd
= "INSERT INTO " + table
+" (" + \
370 ",".join(map(str, INSERT
.keys() )) + ") VALUES(" + \
371 ",".join(map(lambda x
: 'Null' if x
is None else "'"+str(x
)+"'", INSERT
.values() )) + ")"
372 self
.logger
.debug(cmd
)
373 self
.cur
.execute(cmd
)
374 nb_rows
= self
.cur
.rowcount
376 #if nb_rows > 0 and log:
377 # if add_uuid: del INSERT['uuid']
378 # #obtain tenant_id for logs
379 # if 'tenant_id' in INSERT:
380 # tenant_id = INSERT['tenant_id']
381 # del INSERT['tenant_id']
382 # elif table == 'tenants':
386 # if uuid is None: uuid_k = uuid_v = ""
387 # else: uuid_k=",uuid"; uuid_v=",'" + str(uuid) + "'"
388 # if tenant_id is None: tenant_k = tenant_v = ""
389 # else: tenant_k=",tenant_id"; tenant_v=",'" + str(tenant_id) + "'"
390 # cmd = "INSERT INTO logs (related,level%s%s,description) VALUES ('%s','debug'%s%s,\"new %s %s\")" \
391 # % (uuid_k, tenant_k, table, uuid_v, tenant_v, table[:-1], str(INSERT))
392 # self.logger.debug(cmd)
393 # self.cur.execute(cmd)
396 except (mdb
.Error
, AttributeError) as e
:
397 r
,c
= self
.format_error(e
, "new_row", cmd
)
398 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
400 def __remove_quotes(self
, data
):
401 '''remove single quotes ' of any string content of data dictionary'''
402 for k
,v
in data
.items():
405 data
[k
] = data
[k
].replace("'","_")
407 def _update_rows_internal(self
, table
, UPDATE
, WHERE
={}):
408 cmd
= "UPDATE " + table
+" SET " + \
409 ",".join(map(lambda x
: str(x
)+'='+ self
.__data
2db
_format
(UPDATE
[x
]), UPDATE
.keys() ));
411 cmd
+= " WHERE " + " and ".join(map(lambda x
: str(x
)+ (' is Null' if WHERE
[x
] is None else"='"+str(WHERE
[x
])+"'" ), WHERE
.keys() ))
412 self
.logger
.debug(cmd
)
413 self
.cur
.execute(cmd
)
414 nb_rows
= self
.cur
.rowcount
417 def update_rows(self
, table
, UPDATE
, WHERE
={}, log
=False):
418 ''' Update one or several rows into a table.
420 UPDATE: dictionary with the key-new_value pairs to change
421 table: table to be modified
422 WHERE: dictionary to filter target rows, key-value
423 log: if true, a log entry is added at logs table
424 Return: (result, None) where result indicates the number of updated files
426 for retry_
in range(0,2):
430 uuid
= WHERE
.get('uuid')
433 self
.cur
= self
.con
.cursor()
434 cmd
= "UPDATE " + table
+" SET " + \
435 ",".join(map(lambda x
: str(x
)+'='+ self
.__data
2db
_format
(UPDATE
[x
]), UPDATE
.keys() ));
437 cmd
+= " WHERE " + " and ".join(map(lambda x
: str(x
)+ (' is Null' if WHERE
[x
] is None else"='"+str(WHERE
[x
])+"'" ), WHERE
.keys() ))
438 self
.logger
.debug(cmd
)
439 self
.cur
.execute(cmd
)
440 nb_rows
= self
.cur
.rowcount
441 #if nb_rows > 0 and log:
443 # if uuid is None: uuid_k = uuid_v = ""
444 # else: uuid_k=",uuid"; uuid_v=",'" + str(uuid) + "'"
445 # cmd = "INSERT INTO logs (related,level%s,description) VALUES ('%s','debug'%s,\"updating %d entry %s\")" \
446 # % (uuid_k, table, uuid_v, nb_rows, (str(UPDATE)).replace('"','-') )
447 # self.logger.debug(cmd)
448 # self.cur.execute(cmd)
450 except (mdb
.Error
, AttributeError) as e
:
451 r
,c
= self
.format_error(e
, "update_rows", cmd
)
452 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
454 def get_host(self
, host_id
):
455 if af
.check_valid_uuid(host_id
):
456 where_filter
="uuid='" + host_id
+ "'"
458 where_filter
="name='" + host_id
+ "'"
459 for retry_
in range(0,2):
463 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
465 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 \
466 FROM hosts WHERE " + where_filter
467 self
.logger
.debug(cmd
)
468 self
.cur
.execute(cmd
)
469 if self
.cur
.rowcount
== 0 :
470 return 0, "host '" + str(host_id
) +"'not found."
471 elif self
.cur
.rowcount
> 1 :
472 return 0, "host '" + str(host_id
) +"' matches more than one result."
473 host
= self
.cur
.fetchone()
474 host_id
= host
['uuid']
476 cmd
= "SELECT id, numa_socket, hugepages, memory, admin_state_up FROM numas WHERE host_id = '" + str(host_id
) + "'"
477 self
.logger
.debug(cmd
)
478 self
.cur
.execute(cmd
)
479 host
['numas'] = self
.cur
.fetchall()
480 for numa
in host
['numas']:
481 #print "SELECT core_id, instance_id, status, thread_id, v_thread_id FROM resources_core WHERE numa_id = '" + str(numa['id']) + "'"
483 cmd
= "SELECT core_id, instance_id, status, thread_id, v_thread_id FROM resources_core WHERE numa_id = '" + str(numa
['id']) + "'"
484 self
.logger
.debug(cmd
)
485 self
.cur
.execute(cmd
)
486 numa
['cores'] = self
.cur
.fetchall()
487 for core
in numa
['cores']:
488 if core
['instance_id'] == None: del core
['instance_id'], core
['v_thread_id']
489 if core
['status'] == 'ok': del core
['status']
491 cmd
= "SELECT sum(consumed) as hugepages_consumed FROM resources_mem WHERE numa_id = '" + str(numa
['id']) + "' GROUP BY numa_id"
492 self
.logger
.debug(cmd
)
493 self
.cur
.execute(cmd
)
494 used
= self
.cur
.fetchone()
495 used_
= int(used
['hugepages_consumed']) if used
!= None else 0
496 numa
['hugepages_consumed'] = used_
498 #cmd = "CALL GetPortsFromNuma(%s)'" % str(numa['id'])
499 #self.cur.callproc('GetPortsFromNuma', (numa['id'],) )
500 #every time a Procedure is launched you need to close and open the cursor
501 #under Error 2014: Commands out of sync; you can't run this command now
503 #self.cur = self.con.cursor(mdb.cursors.DictCursor)
504 cmd
="SELECT Mbps, pci, status, Mbps_used, instance_id, if(id=root_id,'PF','VF') as type_,\
505 switch_port, switch_dpid, mac, source_name\
506 FROM resources_port WHERE numa_id=%d ORDER BY root_id, type_ DESC" % (numa
['id'])
507 self
.logger
.debug(cmd
)
508 self
.cur
.execute(cmd
)
509 ifaces
= self
.cur
.fetchall()
510 #The SQL query will ensure to have SRIOV interfaces from a port first
513 numa
['interfaces'] = []
515 if not iface
["instance_id"]:
516 del iface
["instance_id"]
517 if iface
['status'] == 'ok':
519 Mpbs_consumed
+= int(iface
["Mbps_used"])
520 del iface
["Mbps_used"]
521 if iface
["type_"]=='PF':
522 if not iface
["switch_dpid"]:
523 del iface
["switch_dpid"]
524 if not iface
["switch_port"]:
525 del iface
["switch_port"]
527 iface
["sriovs"] = sriovs
529 iface
["Mpbs_consumed"] = Mpbs_consumed
531 numa
['interfaces'].append(iface
)
535 del iface
["switch_port"]
536 del iface
["switch_dpid"]
541 #delete internal field
544 except (mdb
.Error
, AttributeError) as e
:
545 r
,c
= self
.format_error(e
, "get_host", cmd
)
546 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
551 uuid
= str( myUuid
.uuid1() )
552 if self
.check_uuid(uuid
)[0] == 0:
557 def check_uuid(self
, uuid
):
558 '''check in the database if this uuid is already present'''
560 cmd
= "SELECT * FROM uuids where uuid='" + str(uuid
) + "'"
562 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
563 self
.logger
.debug(cmd
)
564 self
.cur
.execute(cmd
)
565 rows
= self
.cur
.fetchall()
566 return self
.cur
.rowcount
, rows
567 except (mdb
.Error
, AttributeError) as e
:
568 return self
.format_error(e
, "check_uuid", cmd
)
570 def __get_next_ids(self
):
571 '''get next auto increment index of all table in the database'''
572 self
.cur
.execute("SELECT table_name,AUTO_INCREMENT FROM information_schema.tables WHERE AUTO_INCREMENT IS NOT NULL AND table_schema = DATABASE()")
573 rows
= self
.cur
.fetchall()
574 return self
.cur
.rowcount
, dict(rows
)
576 def edit_host(self
, host_id
, host_dict
):
578 for retry_
in range(0,2):
582 self
.cur
= self
.con
.cursor()
585 numa_list
= host_dict
.pop('numas', () )
587 self
._update
_rows
_internal
("hosts", host_dict
, {"uuid": host_id
})
589 where
= {"host_id": host_id
}
590 for numa_dict
in numa_list
:
591 where
["numa_socket"] = str(numa_dict
.pop('numa_socket'))
592 interface_list
= numa_dict
.pop('interfaces', () )
594 self
._update
_rows
_internal
("numas", numa_dict
, where
)
595 for interface
in interface_list
:
596 source_name
= str(interface
.pop("source_name") )
598 #get interface id from resources_port
599 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 " +\
600 "WHERE host_id='%s' and rp.source_name='%s'" %(host_id
, source_name
)
601 self
.logger
.debug(cmd
)
602 self
.cur
.execute(cmd
)
603 row
= self
.cur
.fetchone()
604 if self
.cur
.rowcount
<=0:
605 return -HTTP_Bad_Request
, "Interface source_name='%s' from numa_socket='%s' not found" % (source_name
, str(where
["numa_socket"]))
606 interface_id
= row
[0]
607 self
._update
_rows
_internal
("resources_port", interface
, {"root_id": interface_id
})
608 return self
.get_host(host_id
)
609 except (mdb
.Error
, AttributeError) as e
:
610 r
,c
= self
.format_error(e
, "edit_host", cmd
)
611 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
613 def new_host(self
, host_dict
):
615 for retry_
in range(0,2):
619 self
.cur
= self
.con
.cursor()
621 result
, next_ids
= self
.__get
_next
_ids
()
622 #print "next_ids: " + str(next_ids)
623 if result
<= 0: return result
, "Internal DataBase error getting next id of tables"
625 #create uuid if not provided
626 if 'uuid' not in host_dict
:
627 uuid
= host_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
628 else: #check uuid is valid
629 uuid
= str(host_dict
['uuid'])
630 # result, data = self.check_uuid(uuid)
632 # return -1, "UUID '%s' already in use" % uuid
635 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','hosts')" % uuid
636 self
.logger
.debug(cmd
)
637 result
= self
.cur
.execute(cmd
)
639 #insert in table host
640 numa_list
= host_dict
.pop('numas', [])
641 #get nonhupages and nonisolated cpus
644 for numa
in numa_list
:
645 mem_numa
= numa
.get('memory', 0) - numa
.get('hugepages',0)
647 host_dict
['RAM'] += mem_numa
648 for core
in numa
.get("cores", []):
649 if "status" in core
and core
["status"]=="noteligible":
651 host_dict
['RAM']*=1024 # from GB to MB
653 keys
= ",".join(host_dict
.keys())
654 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", host_dict
.values() ) )
655 cmd
= "INSERT INTO hosts (" + keys
+ ") VALUES (" + values
+ ")"
656 self
.logger
.debug(cmd
)
657 result
= self
.cur
.execute(cmd
)
658 #if result != 1: return -1, "Database Error while inserting at hosts table"
661 nb_numas
= nb_cores
= nb_ifaces
= 0
662 for numa_dict
in numa_list
:
664 interface_list
= numa_dict
.pop('interfaces', [])
665 core_list
= numa_dict
.pop('cores', [])
666 numa_dict
['id'] = next_ids
['numas']; next_ids
['numas'] += 1
667 numa_dict
['host_id'] = uuid
668 keys
= ",".join(numa_dict
.keys())
669 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", numa_dict
.values() ) )
670 cmd
= "INSERT INTO numas (" + keys
+ ") VALUES (" + values
+ ")"
671 self
.logger
.debug(cmd
)
672 result
= self
.cur
.execute(cmd
)
675 for core_dict
in core_list
:
677 core_dict
['numa_id'] = numa_dict
['id']
678 keys
= ",".join(core_dict
.keys())
679 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", core_dict
.values() ) )
680 cmd
= "INSERT INTO resources_core (" + keys
+ ") VALUES (" + values
+ ")"
681 self
.logger
.debug(cmd
)
682 result
= self
.cur
.execute(cmd
)
685 for port_dict
in interface_list
:
687 sriov_list
= port_dict
.pop('sriovs', [])
688 port_dict
['numa_id'] = numa_dict
['id']
689 port_dict
['id'] = port_dict
['root_id'] = next_ids
['resources_port']
690 next_ids
['resources_port'] += 1
691 switch_port
= port_dict
.get('switch_port', None)
692 switch_dpid
= port_dict
.get('switch_dpid', None)
693 keys
= ",".join(port_dict
.keys())
694 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", port_dict
.values() ) )
695 cmd
= "INSERT INTO resources_port (" + keys
+ ") VALUES (" + values
+ ")"
696 self
.logger
.debug(cmd
)
697 result
= self
.cur
.execute(cmd
)
699 #insert sriovs into port table
700 for sriov_dict
in sriov_list
:
701 sriov_dict
['switch_port'] = switch_port
702 sriov_dict
['switch_dpid'] = switch_dpid
703 sriov_dict
['numa_id'] = port_dict
['numa_id']
704 sriov_dict
['Mbps'] = port_dict
['Mbps']
705 sriov_dict
['root_id'] = port_dict
['id']
706 sriov_dict
['id'] = next_ids
['resources_port']
707 if "vlan" in sriov_dict
:
708 del sriov_dict
["vlan"]
709 next_ids
['resources_port'] += 1
710 keys
= ",".join(sriov_dict
.keys())
711 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", sriov_dict
.values() ) )
712 cmd
= "INSERT INTO resources_port (" + keys
+ ") VALUES (" + values
+ ")"
713 self
.logger
.debug(cmd
)
714 result
= self
.cur
.execute(cmd
)
717 #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)
718 #self.logger.debug(cmd)
719 #result = self.cur.execute(cmd)
723 self
.cur
= self
.con
.cursor()
724 self
.logger
.debug("callproc('UpdateSwitchPort', () )")
725 self
.cur
.callproc('UpdateSwitchPort', () )
727 self
.logger
.debug("getting host '%s'",str(host_dict
['uuid']))
728 return self
.get_host(host_dict
['uuid'])
729 except (mdb
.Error
, AttributeError) as e
:
730 r
,c
= self
.format_error(e
, "new_host", cmd
)
731 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
733 def new_flavor(self
, flavor_dict
, tenant_id
):
734 '''Add new flavor into the database. Create uuid if not provided
736 flavor_dict: flavor dictionary with the key: value to insert. Must be valid flavors columns
737 tenant_id: if not 'any', it matches this flavor/tenant inserting at tenants_flavors table
738 Return: (result, data) where result can be
739 negative: error at inserting. data contain text
740 1, inserted, data contain inserted uuid flavor
742 for retry_
in range(0,2):
746 self
.cur
= self
.con
.cursor()
748 #create uuid if not provided
749 if 'uuid' not in flavor_dict
:
750 uuid
= flavor_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
751 else: #check uuid is valid
752 uuid
= str(flavor_dict
['uuid'])
753 # result, data = self.check_uuid(uuid)
755 # return -1, "UUID '%s' already in use" % uuid
758 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','flavors')" % uuid
759 self
.logger
.debug(cmd
)
760 self
.cur
.execute(cmd
)
762 #insert in table flavor
763 keys
= ",".join(flavor_dict
.keys())
764 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", flavor_dict
.values() ) )
765 cmd
= "INSERT INTO flavors (" + keys
+ ") VALUES (" + values
+ ")"
766 self
.logger
.debug(cmd
)
767 self
.cur
.execute(cmd
)
768 #if result != 1: return -1, "Database Error while inserting at flavors table"
770 #insert tenants_flavors
771 if tenant_id
!= 'any':
772 cmd
= "INSERT INTO tenants_flavors (tenant_id,flavor_id) VALUES ('%s','%s')" % (tenant_id
, uuid
)
773 self
.logger
.debug(cmd
)
774 self
.cur
.execute(cmd
)
777 #del flavor_dict['uuid']
778 #if 'extended' in flavor_dict: del flavor_dict['extended'] #remove two many information
779 #cmd = "INSERT INTO logs (related,level,uuid, tenant_id, description) VALUES ('flavors','debug','%s','%s',\"new flavor: %s\")" \
780 # % (uuid, tenant_id, str(flavor_dict))
781 #self.logger.debug(cmd)
782 #self.cur.execute(cmd)
786 except (mdb
.Error
, AttributeError) as e
:
787 r
,c
= self
.format_error(e
, "new_flavor", cmd
, "update", tenant_id
)
788 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
790 def new_image(self
, image_dict
, tenant_id
):
791 '''Add new image into the database. Create uuid if not provided
793 image_dict: image dictionary with the key: value to insert. Must be valid images columns
794 tenant_id: if not 'any', it matches this image/tenant inserting at tenants_images table
795 Return: (result, data) where result can be
796 negative: error at inserting. data contain text
797 1, inserted, data contain inserted uuid image
799 for retry_
in range(0,2):
803 self
.cur
= self
.con
.cursor()
805 #create uuid if not provided
806 if 'uuid' not in image_dict
:
807 uuid
= image_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
808 else: #check uuid is valid
809 uuid
= str(image_dict
['uuid'])
810 # result, data = self.check_uuid(uuid)
812 # return -1, "UUID '%s' already in use" % uuid
815 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','images')" % uuid
816 self
.logger
.debug(cmd
)
817 self
.cur
.execute(cmd
)
819 #insert in table image
820 keys
= ",".join(image_dict
.keys())
821 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", image_dict
.values() ) )
822 cmd
= "INSERT INTO images (" + keys
+ ") VALUES (" + values
+ ")"
823 self
.logger
.debug(cmd
)
824 self
.cur
.execute(cmd
)
825 #if result != 1: return -1, "Database Error while inserting at images table"
827 #insert tenants_images
828 if tenant_id
!= 'any':
829 cmd
= "INSERT INTO tenants_images (tenant_id,image_id) VALUES ('%s','%s')" % (tenant_id
, uuid
)
830 self
.logger
.debug(cmd
)
831 self
.cur
.execute(cmd
)
834 #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'])
835 #self.logger.debug(cmd)
836 #self.cur.execute(cmd)
840 except (mdb
.Error
, AttributeError) as e
:
841 r
,c
= self
.format_error(e
, "new_image", cmd
, "update", tenant_id
)
842 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
844 def delete_image_flavor(self
, item_type
, item_id
, tenant_id
):
845 '''deletes an image or flavor from database
846 item_type must be a 'image' or 'flavor'
848 tenant_id is the asociated tenant, can be 'any' with means all
849 If tenan_id is not any, it deletes from tenants_images/flavors,
850 which means this image/flavor is used by this tenant, and if success,
851 it tries to delete from images/flavors in case this is not public,
852 that only will success if image is private and not used by other tenants
853 If tenant_id is any, it tries to delete from both tables at the same transaction
854 so that image/flavor is completely deleted from all tenants or nothing
856 for retry_
in range(0,2):
859 result
= (-HTTP_Internal_Server_Error
, "internal error")
863 self
.cur
= self
.con
.cursor()
864 cmd
= "DELETE FROM tenants_%ss WHERE %s_id = '%s'" % (item_type
, item_type
, item_id
)
865 if tenant_id
!= 'any':
866 cmd
+= " AND tenant_id = '%s'" % tenant_id
867 self
.logger
.debug(cmd
)
868 self
.cur
.execute(cmd
)
869 deleted
= self
.cur
.rowcount
870 if tenant_id
== 'any': #delete from images/flavors in the SAME transaction
871 cmd
= "DELETE FROM %ss WHERE uuid = '%s'" % (item_type
, item_id
)
872 self
.logger
.debug(cmd
)
873 self
.cur
.execute(cmd
)
874 deleted
= self
.cur
.rowcount
877 cmd
= "DELETE FROM uuids WHERE uuid = '%s'" % item_id
878 self
.logger
.debug(cmd
)
879 self
.cur
.execute(cmd
)
881 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) \
882 # VALUES ('%ss','debug','%s','%s','delete %s completely')" % \
883 # (item_type, item_id, tenant_id, item_type)
884 #self.logger.debug(cmd)
885 #self.cur.execute(cmd)
886 return deleted
, "%s '%s' completely deleted" % (item_type
, item_id
)
887 return 0, "%s '%s' not found" % (item_type
, item_id
)
891 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) \
892 # VALUES ('%ss','debug','%s','%s','delete %s reference for this tenant')" % \
893 # (item_type, item_id, tenant_id, item_type)
894 #self.logger.debug(cmd)
895 #self.cur.execute(cmd)
899 #if tenant!=any delete from images/flavors in OTHER transaction. If fails is because dependencies so that not return error
902 self
.cur
= self
.con
.cursor()
904 #delete image/flavor if not public
905 cmd
= "DELETE FROM %ss WHERE uuid = '%s' AND public = 'no'" % (item_type
, item_id
)
906 self
.logger
.debug(cmd
)
907 self
.cur
.execute(cmd
)
908 deleted_item
= self
.cur
.rowcount
909 if deleted_item
== 1:
911 cmd
= "DELETE FROM uuids WHERE uuid = '%s'" % item_id
912 self
.logger
.debug(cmd
)
913 self
.cur
.execute(cmd
)
915 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) \
916 # VALUES ('%ss','debug','%s','%s','delete %s completely')" % \
917 # (item_type, item_id, tenant_id, item_type)
918 #self.logger.debug(cmd)
919 #self.cur.execute(cmd)
920 except (mdb
.Error
, AttributeError) as e
:
921 #print "delete_%s DB Exception %d: %s" % (item_type, e.args[0], e.args[1])
923 result
= self
.format_error(e
, "delete_"+item_type
, cmd
, "delete", "servers")
926 return 1, "%s '%s' from tenant '%s' %sdeleted" % \
927 (item_type
, item_id
, tenant_id
, "completely " if deleted_item
==1 else "")
929 return 0, "%s '%s' from tenant '%s' not found" % (item_type
, item_id
, tenant_id
)
931 if result
[0]!=-HTTP_Request_Timeout
or retry_
==1: return result
933 def delete_row(self
, table
, uuid
):
934 for retry_
in range(0,2):
939 self
.cur
= self
.con
.cursor()
940 cmd
= "DELETE FROM %s WHERE uuid = '%s'" % (table
, uuid
)
941 self
.logger
.debug(cmd
)
942 self
.cur
.execute(cmd
)
943 deleted
= self
.cur
.rowcount
946 if table
== 'tenants': tenant_str
=uuid
947 else: tenant_str
='Null'
948 self
.cur
= self
.con
.cursor()
949 cmd
= "DELETE FROM uuids WHERE uuid = '%s'" % uuid
950 self
.logger
.debug(cmd
)
951 self
.cur
.execute(cmd
)
953 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) VALUES ('%s','debug','%s','%s','delete %s')" % (table, uuid, tenant_str, table[:-1])
954 #self.logger.debug(cmd)
955 #self.cur.execute(cmd)
956 return deleted
, table
[:-1] + " '%s' %s" %(uuid
, "deleted" if deleted
==1 else "not found")
957 except (mdb
.Error
, AttributeError) as e
:
958 r
,c
= self
.format_error(e
, "delete_row", cmd
, "delete", 'instances' if table
=='hosts' or table
=='tenants' else 'dependencies')
959 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
961 def delete_row_by_key(self
, table
, key
, value
):
962 for retry_
in range(0,2):
967 self
.cur
= self
.con
.cursor()
968 cmd
= "DELETE FROM %s" % (table
)
971 cmd
+= " WHERE %s = '%s'" % (key
, value
)
973 cmd
+= " WHERE %s is null" % (key
)
976 self
.logger
.debug(cmd
)
977 self
.cur
.execute(cmd
)
978 deleted
= self
.cur
.rowcount
980 return -1, 'Not found'
983 except (mdb
.Error
, AttributeError) as e
:
984 r
,c
= self
.format_error(e
, "delete_row_by_key", cmd
, "delete", 'instances' if table
=='hosts' or table
=='tenants' else 'dependencies')
985 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
987 def delete_row_by_dict(self
, **sql_dict
):
988 ''' Deletes rows from a table.
989 Attribute sql_dir: dictionary with the following key: value
990 'FROM': string of table name (Mandatory)
991 'WHERE': dict of key:values, translated to key=value AND ... (Optional)
992 'WHERE_NOT': dict of key:values, translated to key<>value AND ... (Optional)
993 'WHERE_NOTNULL': (list or tuple of items that must not be null in a where ... (Optional)
994 'LIMIT': limit of number of rows (Optional)
995 Return: the (number of items deleted, descriptive test) if ok; (negative, descriptive text) if error
998 from_
= "FROM " + str(sql_dict
['FROM'])
999 #print 'from_', from_
1000 if 'WHERE' in sql_dict
and len(sql_dict
['WHERE']) > 0:
1002 where_
= "WHERE " + " AND ".join(map( lambda x
: str(x
) + (" is Null" if w
[x
] is None else "='"+str(w
[x
])+"'"), w
.keys()) )
1004 if 'WHERE_NOT' in sql_dict
and len(sql_dict
['WHERE_NOT']) > 0:
1005 w
=sql_dict
['WHERE_NOT']
1006 where_2
= " AND ".join(map( lambda x
: str(x
) + (" is not Null" if w
[x
] is None else "<>'"+str(w
[x
])+"'"), w
.keys()) )
1007 if len(where_
)==0: where_
= "WHERE " + where_2
1008 else: where_
= where_
+ " AND " + where_2
1009 if 'WHERE_NOTNULL' in sql_dict
and len(sql_dict
['WHERE_NOTNULL']) > 0:
1010 w
=sql_dict
['WHERE_NOTNULL']
1011 where_2
= " AND ".join(map( lambda x
: str(x
) + " is not Null", w
) )
1012 if len(where_
)==0: where_
= "WHERE " + where_2
1013 else: where_
= where_
+ " AND " + where_2
1014 #print 'where_', where_
1015 limit_
= "LIMIT " + str(sql_dict
['LIMIT']) if 'LIMIT' in sql_dict
else ""
1016 #print 'limit_', limit_
1017 cmd
= " ".join( ("DELETE", from_
, where_
, limit_
) )
1018 self
.logger
.debug(cmd
)
1019 for retry_
in range(0,2):
1023 self
.cur
= self
.con
.cursor()
1024 self
.cur
.execute(cmd
)
1025 deleted
= self
.cur
.rowcount
1026 return deleted
, "%d deleted from %s" % (deleted
, sql_dict
['FROM'][:-1] )
1027 except (mdb
.Error
, AttributeError) as e
:
1028 r
,c
= self
.format_error(e
, "delete_row_by_dict", cmd
, "delete", 'dependencies')
1029 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1032 def get_instance(self
, instance_id
):
1033 for retry_
in range(0,2):
1037 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1039 cmd
= "SELECT uuid, name, description, progress, host_id, flavor_id, image_id, status, last_error, "\
1040 "tenant_id, ram, vcpus, created_at FROM instances WHERE uuid='{}'".format(instance_id
)
1041 self
.logger
.debug(cmd
)
1042 self
.cur
.execute(cmd
)
1043 if self
.cur
.rowcount
== 0 : return 0, "instance '" + str(instance_id
) +"'not found."
1044 instance
= self
.cur
.fetchone()
1046 cmd
= "SELECT uuid as iface_id, net_id, mac as mac_address, ip_address, name, Mbps as bandwidth, "\
1047 "vpci, model FROM ports WHERE (type='instance:bridge' or type='instance:ovs') AND "\
1048 "instance_id= '{}'".format(instance_id
)
1049 self
.logger
.debug(cmd
)
1050 self
.cur
.execute(cmd
)
1051 if self
.cur
.rowcount
> 0 :
1052 instance
['networks'] = self
.cur
.fetchall()
1057 cmd
= "SELECT type, vpci, image_id, xml,dev FROM instance_devices WHERE instance_id = '%s' " % str(instance_id
)
1058 self
.logger
.debug(cmd
)
1059 self
.cur
.execute(cmd
)
1060 if self
.cur
.rowcount
> 0 :
1061 extended
['devices'] = self
.cur
.fetchall()
1064 cmd
= "SELECT id, numa_socket as source FROM numas WHERE host_id = '" + str(instance
['host_id']) + "'"
1065 self
.logger
.debug(cmd
)
1066 self
.cur
.execute(cmd
)
1067 host_numas
= self
.cur
.fetchall()
1068 #print 'host_numas', host_numas
1069 for k
in host_numas
:
1070 numa_id
= str(k
['id'])
1073 cmd
= "SELECT consumed FROM resources_mem WHERE instance_id = '%s' AND numa_id = '%s'" % ( instance_id
, numa_id
)
1074 self
.logger
.debug(cmd
)
1075 self
.cur
.execute(cmd
)
1076 if self
.cur
.rowcount
> 0:
1077 mem_dict
= self
.cur
.fetchone()
1078 numa_dict
['memory'] = mem_dict
['consumed']
1080 cursor2
= self
.con
.cursor()
1081 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
)
1082 self
.logger
.debug(cmd
)
1083 cursor2
.execute(cmd
)
1084 core_list
= []; core_source
= []
1085 paired_list
= []; paired_source
= []
1086 thread_list
= []; thread_source
= []
1087 if cursor2
.rowcount
> 0:
1088 cores
= cursor2
.fetchall()
1090 if core
[4] == 2: #number of used threads from core
1091 if core
[3] == core
[2]: #only one thread asigned to VM, so completely core
1092 core_list
.append(core
[2])
1093 core_source
.append(core
[5])
1094 elif core
[1] == 'Y':
1095 paired_list
.append(core
[2:4])
1096 paired_source
.append(core
[5:7])
1098 thread_list
.extend(core
[2:4])
1099 thread_source
.extend(core
[5:7])
1102 thread_list
.append(core
[2])
1103 thread_source
.append(core
[5])
1104 if len(core_list
) > 0:
1105 numa_dict
['cores'] = len(core_list
)
1106 numa_dict
['cores-id'] = core_list
1107 numa_dict
['cores-source'] = core_source
1108 if len(paired_list
) > 0:
1109 numa_dict
['paired-threads'] = len(paired_list
)
1110 numa_dict
['paired-threads-id'] = paired_list
1111 numa_dict
['paired-threads-source'] = paired_source
1112 if len(thread_list
) > 0:
1113 numa_dict
['threads'] = len(thread_list
)
1114 numa_dict
['threads-id'] = thread_list
1115 numa_dict
['threads-source'] = thread_source
1117 #get dedicated ports and SRIOV
1118 cmd
= "SELECT port_id as iface_id, p.vlan as vlan, p.mac as mac_address, net_id, if(model='PF',\
1119 'yes',if(model='VF','no','yes:sriov')) as dedicated, rp.Mbps as bandwidth, name, vpci, \
1121 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
)
1122 self
.logger
.debug(cmd
)
1123 self
.cur
.execute(cmd
)
1124 if self
.cur
.rowcount
> 0:
1125 numa_dict
['interfaces'] = self
.cur
.fetchall()
1126 #print 'interfaces', numa_dict
1128 if len(numa_dict
) > 0 :
1129 numa_dict
['source'] = k
['source'] #numa socket
1130 numas
.append(numa_dict
)
1132 if len(numas
) > 0 : extended
['numas'] = numas
1133 if len(extended
) > 0 : instance
['extended'] = extended
1134 af
.DeleteNone(instance
)
1136 except (mdb
.Error
, AttributeError) as e
:
1137 r
,c
= self
.format_error(e
, "get_instance", cmd
)
1138 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1140 def get_numas(self
, requirements
, prefered_host_id
=None, only_of_ports
=True):
1141 '''Obtain a valid NUMA/HOST for deployment a VM
1142 requirements: contain requirement regarding:
1143 requirements['ram']: Non huge page memory in MB; 0 to skip
1144 requirements['vcpus']: Non isolated cpus; 0 to skip
1145 requirements['numa']: Requiremets to be fixed in ONE Numa node
1146 requirements['numa']['memory']: Huge page memory in GB at ; 0 for any
1147 requirements['numa']['proc_req_type']: Type of processor, cores or threads
1148 requirements['numa']['proc_req_nb']: Number of isolated cpus
1149 requirements['numa']['port_list']: Physical NIC ports list ; [] for any
1150 requirements['numa']['sriov_list']: Virtual function NIC ports list ; [] for any
1151 prefered_host_id: if not None return this host if it match
1152 only_of_ports: if True only those ports conected to the openflow (of) are valid,
1153 that is, with switch_port information filled; if False, all NIC ports are valid.
1154 Return a valid numa and host
1157 for retry_
in range(0,2):
1161 # #Find numas of prefered host
1162 # prefered_numas = ()
1163 # if prefered_host_id != None:
1164 # self.cur = self.con.cursor()
1165 # self.cur.execute("SELECT id FROM numas WHERE host_id='%s'" + prefered_host_id)
1166 # prefered_numas = self.cur.fetchall()
1169 #Find valid host for the ram and vcpus
1170 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1171 cmd
= "CALL GetHostByMemCpu(%s, %s)" % (str(requirements
['ram']), str(requirements
['vcpus']))
1172 self
.logger
.debug(cmd
)
1173 self
.cur
.callproc('GetHostByMemCpu', (str(requirements
['ram']), str(requirements
['vcpus'])) )
1174 valid_hosts
= self
.cur
.fetchall()
1176 self
.cur
= self
.con
.cursor()
1178 if len(valid_hosts
)<=0:
1179 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']))
1180 #self.logger.debug(error_text)
1181 return -1, error_text
1183 #elif req_numa != None:
1184 #Find valid numa nodes for memory requirements
1185 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1186 cmd
= "CALL GetNumaByMemory(%s)" % str(requirements
['numa']['memory'])
1187 self
.logger
.debug(cmd
)
1188 self
.cur
.callproc('GetNumaByMemory', (requirements
['numa']['memory'],) )
1189 valid_for_memory
= self
.cur
.fetchall()
1191 self
.cur
= self
.con
.cursor()
1192 if len(valid_for_memory
)<=0:
1193 error_text
= 'No room at data center. Can not find a host with %s GB Hugepages memory available' % str(requirements
['numa']['memory'])
1194 #self.logger.debug(error_text)
1195 return -1, error_text
1197 #Find valid numa nodes for processor requirements
1198 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1199 if requirements
['numa']['proc_req_type'] == 'threads':
1200 cpu_requirement_text
='cpu-threads'
1201 cmd
= "CALL GetNumaByThread(%s)" % str(requirements
['numa']['proc_req_nb'])
1202 self
.logger
.debug(cmd
)
1203 self
.cur
.callproc('GetNumaByThread', (requirements
['numa']['proc_req_nb'],) )
1205 cpu_requirement_text
='cpu-cores'
1206 cmd
= "CALL GetNumaByCore(%s)" % str(requirements
['numa']['proc_req_nb'])
1207 self
.logger
.debug(cmd
)
1208 self
.cur
.callproc('GetNumaByCore', (requirements
['numa']['proc_req_nb'],) )
1209 valid_for_processor
= self
.cur
.fetchall()
1211 self
.cur
= self
.con
.cursor()
1212 if len(valid_for_processor
)<=0:
1213 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
)
1214 #self.logger.debug(error_text)
1215 return -1, error_text
1217 #Find the numa nodes that comply for memory and processor requirements
1218 #sorting from less to more memory capacity
1220 for m_numa
in valid_for_memory
:
1221 numa_valid_for_processor
= False
1222 for p_numa
in valid_for_processor
:
1223 if m_numa
['numa_id'] == p_numa
['numa_id']:
1224 numa_valid_for_processor
= True
1226 numa_valid_for_host
= False
1227 prefered_numa
= False
1228 for p_host
in valid_hosts
:
1229 if m_numa
['host_id'] == p_host
['uuid']:
1230 numa_valid_for_host
= True
1231 if p_host
['uuid'] == prefered_host_id
:
1232 prefered_numa
= True
1234 if numa_valid_for_host
and numa_valid_for_processor
:
1236 valid_numas
.insert(0, m_numa
['numa_id'])
1238 valid_numas
.append(m_numa
['numa_id'])
1239 if len(valid_numas
)<=0:
1240 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' %\
1241 (requirements
['numa']['memory'], str(requirements
['numa']['proc_req_nb']),cpu_requirement_text
)
1242 #self.logger.debug(error_text)
1243 return -1, error_text
1245 # print 'Valid numas list: '+str(valid_numas)
1247 #Find valid numa nodes for interfaces requirements
1248 #For each valid numa we will obtain the number of available ports and check if these are valid
1250 for numa_id
in valid_numas
:
1251 # print 'Checking '+str(numa_id)
1253 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1255 cmd
="CALL GetAvailablePorts(%s)" % str(numa_id
)
1256 self
.logger
.debug(cmd
)
1257 self
.cur
.callproc('GetAvailablePorts', (numa_id
,) )
1259 cmd
="CALL GetAllAvailablePorts(%s)" % str(numa_id
)
1260 self
.logger
.debug(cmd
)
1261 self
.cur
.callproc('GetAllAvailablePorts', (numa_id
,) )
1262 available_ports
= self
.cur
.fetchall()
1264 self
.cur
= self
.con
.cursor()
1266 #Set/reset reservations
1267 for port
in available_ports
:
1268 port
['Mbps_reserved'] = 0
1269 port
['SRIOV_reserved'] = 0
1271 #Try to allocate physical ports
1272 physical_ports_found
= True
1273 for iface
in requirements
['numa']['port_list']:
1274 # print '\t\tchecking iface: '+str(iface)
1276 for port
in available_ports
:
1277 # print '\t\t\tfor port: '+str(port)
1278 #If the port is not empty continue
1279 if port
['Mbps_free'] != port
['Mbps'] or port
['Mbps_reserved'] != 0:
1280 # print '\t\t\t\t Not empty port'
1282 #If the port speed is not enough continue
1283 if port
['Mbps'] < iface
['bandwidth']:
1284 # print '\t\t\t\t Not enough speed'
1287 #Otherwise this is a valid port
1288 port
['Mbps_reserved'] = port
['Mbps']
1289 port
['SRIOV_reserved'] = 0
1290 iface
['port_id'] = port
['port_id']
1291 iface
['vlan'] = None
1292 iface
['mac'] = port
['mac']
1293 iface
['switch_port'] = port
['switch_port']
1294 # print '\t\t\t\t Dedicated port found '+str(port['port_id'])
1298 #if all ports have been checked and no match has been found
1299 #this is not a valid numa
1301 # print '\t\t\t\t\tAll ports have been checked and no match has been found for numa '+str(numa_id)+'\n\n'
1302 physical_ports_found
= False
1305 #if there is no match continue checking the following numa
1306 if not physical_ports_found
:
1309 #Try to allocate SR-IOVs
1310 sriov_ports_found
= True
1311 for iface
in requirements
['numa']['sriov_list']:
1312 # print '\t\tchecking iface: '+str(iface)
1314 for port
in available_ports
:
1315 # print '\t\t\tfor port: '+str(port)
1316 #If there are not available SR-IOVs continue
1317 if port
['availableSRIOV'] - port
['SRIOV_reserved'] <= 0:
1318 # print '\t\t\t\t Not enough SR-IOV'
1320 #If the port free speed is not enough continue
1321 if port
['Mbps_free'] - port
['Mbps_reserved'] < iface
['bandwidth']:
1322 # print '\t\t\t\t Not enough speed'
1325 #Otherwise this is a valid port
1326 port
['Mbps_reserved'] += iface
['bandwidth']
1327 port
['SRIOV_reserved'] += 1
1328 # print '\t\t\t\t SR-IOV found '+str(port['port_id'])
1329 iface
['port_id'] = port
['port_id']
1330 iface
['vlan'] = None
1331 iface
['mac'] = port
['mac']
1332 iface
['switch_port'] = port
['switch_port']
1336 #if all ports have been checked and no match has been found
1337 #this is not a valid numa
1339 # print '\t\t\t\t\tAll ports have been checked and no match has been found for numa '+str(numa_id)+'\n\n'
1340 sriov_ports_found
= False
1343 #if there is no match continue checking the following numa
1344 if not sriov_ports_found
:
1348 if sriov_ports_found
and physical_ports_found
:
1353 error_text
= 'No room at data center. Can not find a host with the required hugepages, vcpus and interfaces'
1354 #self.logger.debug(error_text)
1355 return -1, error_text
1357 #self.logger.debug('Full match found in numa %s', str(numa_id))
1359 for numa
in valid_for_processor
:
1360 if numa_id
==numa
['numa_id']:
1361 host_id
=numa
['host_id']
1363 return 0, {'numa_id':numa_id
, 'host_id': host_id
, }
1364 except (mdb
.Error
, AttributeError) as e
:
1365 r
,c
= self
.format_error(e
, "get_numas", cmd
)
1366 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1368 def new_instance(self
, instance_dict
, nets
, ports_to_free
):
1369 for retry_
in range(0,2):
1373 self
.cur
= self
.con
.cursor()
1375 #create uuid if not provided
1376 if 'uuid' not in instance_dict
:
1377 uuid
= instance_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
1378 else: #check uuid is valid
1379 uuid
= str(instance_dict
['uuid'])
1383 cmd
= "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'instances')" % (uuid
, uuid
)
1384 self
.logger
.debug(cmd
)
1385 self
.cur
.execute(cmd
)
1387 #insert in table instance
1388 extended
= instance_dict
.pop('extended', None);
1389 bridgedifaces
= instance_dict
.pop('bridged-ifaces', () );
1391 keys
= ",".join(instance_dict
.keys())
1392 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", instance_dict
.values() ) )
1393 cmd
= "INSERT INTO instances (" + keys
+ ") VALUES (" + values
+ ")"
1394 self
.logger
.debug(cmd
)
1395 self
.cur
.execute(cmd
)
1396 #if result != 1: return -1, "Database Error while inserting at instances table"
1399 nb_bridge_ifaces
= nb_cores
= nb_ifaces
= nb_numas
= 0
1400 #insert bridged_ifaces
1402 for iface
in bridgedifaces
:
1403 #generate and insert a iface uuid
1404 if 'enable_dhcp' in iface
and iface
['enable_dhcp']:
1405 dhcp_first_ip
= iface
["dhcp_first_ip"]
1406 del iface
["dhcp_first_ip"]
1407 dhcp_last_ip
= iface
["dhcp_last_ip"]
1408 del iface
["dhcp_last_ip"]
1409 dhcp_cidr
= iface
["cidr"]
1411 del iface
["enable_dhcp"]
1412 used_dhcp_ips
= self
._get
_dhcp
_ip
_used
_list
(iface
["net_id"])
1413 iface
["ip_address"] = self
.get_free_ip_from_range(dhcp_first_ip
, dhcp_last_ip
,
1414 dhcp_cidr
, used_dhcp_ips
)
1416 iface
['uuid'] = str(myUuid
.uuid1()) # create_uuid
1417 cmd
= "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'ports')" % (iface
['uuid'], uuid
)
1418 self
.logger
.debug(cmd
)
1419 self
.cur
.execute(cmd
)
1421 iface
['instance_id'] = uuid
1422 # iface['type'] = 'instance:bridge'
1423 if 'name' not in iface
: iface
['name']="br"+str(nb_bridge_ifaces
)
1424 iface
['Mbps']=iface
.pop('bandwidth', None)
1425 if 'mac_address' not in iface
:
1426 iface
['mac'] = af
.gen_random_mac()
1428 iface
['mac'] = iface
['mac_address']
1429 del iface
['mac_address']
1430 #iface['mac']=iface.pop('mac_address', None) #for leaving mac generation to libvirt
1431 keys
= ",".join(iface
.keys())
1432 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", iface
.values() ) )
1433 cmd
= "INSERT INTO ports (" + keys
+ ") VALUES (" + values
+ ")"
1434 self
.logger
.debug(cmd
)
1435 self
.cur
.execute(cmd
)
1436 nb_bridge_ifaces
+= 1
1438 if extended
is not None:
1439 if 'numas' not in extended
or extended
['numas'] is None: extended
['numas'] = ()
1440 for numa
in extended
['numas']:
1443 if 'cores' not in numa
or numa
['cores'] is None: numa
['cores'] = ()
1444 for core
in numa
['cores']:
1446 cmd
= "UPDATE resources_core SET instance_id='%s'%s%s WHERE id='%s'" \
1448 (",v_thread_id='" + str(core
['vthread']) + "'") if 'vthread' in core
else '', \
1449 (",paired='" + core
['paired'] + "'") if 'paired' in core
else '', \
1451 self
.logger
.debug(cmd
)
1452 self
.cur
.execute(cmd
)
1454 if 'interfaces' not in numa
or numa
['interfaces'] is None: numa
['interfaces'] = ()
1455 for iface
in numa
['interfaces']:
1456 #generate and insert an uuid; iface[id]=iface_uuid; iface[uuid]= net_id
1457 iface
['id'] = str(myUuid
.uuid1()) # create_uuid
1458 cmd
= "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'ports')" % (iface
['id'], uuid
)
1459 self
.logger
.debug(cmd
)
1460 self
.cur
.execute(cmd
)
1462 mbps_
=("'"+str(iface
['Mbps_used'])+"'") if 'Mbps_used' in iface
and iface
['Mbps_used'] is not None else "Mbps"
1463 if iface
["dedicated"]=="yes":
1465 elif iface
["dedicated"]=="yes:sriov":
1466 iface_model
="VFnotShared"
1467 elif iface
["dedicated"]=="no":
1470 INSERT
=(iface
['mac_address'], iface
['switch_port'], iface
.get('vlan',None), 'instance:data', iface
['Mbps_used'], iface
['id'],
1471 uuid
, instance_dict
['tenant_id'], iface
.get('name',None), iface
.get('vpci',None), iface
.get('uuid',None), iface_model
)
1472 cmd
= "INSERT INTO ports (mac,switch_port,vlan,type,Mbps,uuid,instance_id,tenant_id,name,vpci,net_id, model) " + \
1473 " VALUES (" + ",".join(map(lambda x
: 'Null' if x
is None else "'"+str(x
)+"'", INSERT
)) + ")"
1474 self
.logger
.debug(cmd
)
1475 self
.cur
.execute(cmd
)
1477 nets
.append(iface
['uuid'])
1479 #discover if this port is not used by anyone
1480 cmd
= "SELECT source_name, mac FROM ( SELECT root_id, count(instance_id) as used FROM resources_port" \
1481 " WHERE root_id=(SELECT root_id from resources_port WHERE id='%s')"\
1482 " GROUP BY root_id ) AS A JOIN resources_port as B ON A.root_id=B.id AND A.used=0" % iface
['port_id']
1483 self
.logger
.debug(cmd
)
1484 self
.cur
.execute(cmd
)
1485 ports_to_free
+= self
.cur
.fetchall()
1487 cmd
= "UPDATE resources_port SET instance_id='%s', port_id='%s',Mbps_used=%s WHERE id='%s'" \
1488 % (uuid
, iface
['id'], mbps_
, iface
['port_id'])
1489 #if Mbps_used not suply, set the same value of 'Mpbs', that is the total
1490 self
.logger
.debug(cmd
)
1491 self
.cur
.execute(cmd
)
1493 if 'memory' in numa
and numa
['memory'] is not None and numa
['memory']>0:
1494 cmd
= "INSERT INTO resources_mem (numa_id, instance_id, consumed) VALUES ('%s','%s','%s')" % (numa
['numa_id'], uuid
, numa
['memory'])
1495 self
.logger
.debug(cmd
)
1496 self
.cur
.execute(cmd
)
1497 if 'devices' not in extended
or extended
['devices'] is None: extended
['devices'] = ()
1498 for device
in extended
['devices']:
1499 if 'vpci' in device
: vpci
= "'" + device
['vpci'] + "'"
1501 if 'image_id' in device
: image_id
= "'" + device
['image_id'] + "'"
1502 else: image_id
= 'Null'
1503 if 'xml' in device
: xml
= "'" + device
['xml'] + "'"
1505 if 'dev' in device
: dev
= "'" + device
['dev'] + "'"
1507 cmd
= "INSERT INTO instance_devices (type, instance_id, image_id, vpci, xml, dev) VALUES ('%s','%s', %s, %s, %s, %s)" % \
1508 (device
['type'], uuid
, image_id
, vpci
, xml
, dev
)
1509 self
.logger
.debug(cmd
)
1510 self
.cur
.execute(cmd
)
1512 #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)
1513 #self.logger.debug(cmd)
1514 #self.cur.execute(cmd)
1518 except (mdb
.Error
, AttributeError) as e
:
1519 r
,c
= self
.format_error(e
, "new_instance", cmd
)
1520 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1522 def get_free_ip_from_range(self
, first_ip
, last_ip
, cidr
, ip_used_list
):
1524 Calculate a free IP from a range given
1525 :param first_ip: First dhcp ip range
1526 :param last_ip: Last dhcp ip range
1527 :param cidr: net cidr
1528 :param ip_used_list: contain all used ips to avoid ip collisions
1532 ip_tools
= IPNetwork(cidr
)
1533 cidr_len
= ip_tools
.prefixlen
1534 ips
= IPNetwork(first_ip
+ '/' + str(cidr_len
))
1535 ip_used_list
.append(str(ips
[0])) # first ip
1536 ip_used_list
.append(str(ips
[1])) # gw ip
1537 ip_used_list
.append(str(ips
[-1])) # broadcast ip
1539 if str(vm_ip
) not in ip_used_list
:
1544 def _get_dhcp_ip_used_list(self
, net_id
):
1546 REtreive from DB all ips already used by the dhcp server for a given net
1550 WHERE
={'type': 'instance:ovs', 'net_id': net_id
}
1551 for retry_
in range(0, 2):
1553 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1554 select_
= "SELECT uuid, ip_address FROM ports "
1556 if WHERE
is None or len(WHERE
) == 0:
1559 where_
= "WHERE " + " AND ".join(
1560 map(lambda x
: str(x
) + (" is Null" if WHERE
[x
] is None else "='" + str(WHERE
[x
]) + "'"),
1562 limit_
= "LIMIT 100"
1563 cmd
= " ".join((select_
, where_
, limit_
))
1564 self
.logger
.debug(cmd
)
1565 self
.cur
.execute(cmd
)
1566 ports
= self
.cur
.fetchall()
1567 ip_address_list
= []
1569 ip_address_list
.append(port
['ip_address'])
1571 return ip_address_list
1574 def delete_instance(self
, instance_id
, tenant_id
, net_dataplane_list
, ports_to_free
, net_ovs_list
, logcause
="requested by http"):
1575 for retry_
in range(0,2):
1579 self
.cur
= self
.con
.cursor()
1581 cmd
= "SELECT uuid FROM instances WHERE uuid='%s' AND tenant_id='%s'" % (instance_id
, tenant_id
)
1582 self
.logger
.debug(cmd
)
1583 self
.cur
.execute(cmd
)
1584 if self
.cur
.rowcount
== 0 : return 0, "instance %s not found in tenant %s" % (instance_id
, tenant_id
)
1586 #delete bridged ifaces, instace_devices, resources_mem; done by database: it is automatic by Database; FOREIGN KEY DELETE CASCADE
1589 cmd
= "SELECT DISTINCT net_id from ports WHERE instance_id = '%s' AND net_id is not Null AND type='instance:data'" % instance_id
1590 self
.logger
.debug(cmd
)
1591 self
.cur
.execute(cmd
)
1592 net_list__
= self
.cur
.fetchall()
1593 for net
in net_list__
:
1594 net_dataplane_list
.append(net
[0])
1596 # get ovs manangement nets
1597 cmd
= "SELECT DISTINCT net_id, vlan, ip_address, mac FROM ports WHERE instance_id='{}' AND net_id is not Null AND "\
1598 "type='instance:ovs'".format(instance_id
)
1599 self
.logger
.debug(cmd
)
1600 self
.cur
.execute(cmd
)
1601 net_ovs_list
+= self
.cur
.fetchall()
1603 #get dataplane interfaces releases by this VM; both PF and VF with no other VF
1604 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 \
1605 + " 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"\
1606 + " JOIN resources_port as C ON A.root_id=C.id"
1607 # cmd = "SELECT DISTINCT root_id FROM resources_port WHERE instance_id = '%s'" % instance_id
1608 self
.logger
.debug(cmd
)
1609 self
.cur
.execute(cmd
)
1610 ports_to_free
+= self
.cur
.fetchall()
1612 #update resources port
1613 cmd
= "UPDATE resources_port SET instance_id=Null, port_id=Null, Mbps_used='0' WHERE instance_id = '%s'" % instance_id
1614 self
.logger
.debug(cmd
)
1615 self
.cur
.execute(cmd
)
1617 # #filter dataplane ports used by this VM that now are free
1618 # for port in ports_list__:
1619 # cmd = "SELECT mac, count(instance_id) FROM resources_port WHERE root_id = '%s'" % port[0]
1620 # self.logger.debug(cmd)
1621 # self.cur.execute(cmd)
1622 # mac_list__ = self.cur.fetchone()
1623 # if mac_list__ and mac_list__[1]==0:
1624 # ports_to_free.append(mac_list__[0])
1627 #update resources core
1628 cmd
= "UPDATE resources_core SET instance_id=Null, v_thread_id=Null, paired='N' WHERE instance_id = '%s'" % instance_id
1629 self
.logger
.debug(cmd
)
1630 self
.cur
.execute(cmd
)
1632 #delete all related uuids
1633 cmd
= "DELETE FROM uuids WHERE root_uuid='%s'" % instance_id
1634 self
.logger
.debug(cmd
)
1635 self
.cur
.execute(cmd
)
1638 #cmd = "INSERT INTO logs (related,level,uuid,description) VALUES ('instances','debug','%s','delete instance %s')" % (instance_id, logcause)
1639 #self.logger.debug(cmd)
1640 #self.cur.execute(cmd)
1643 cmd
= "DELETE FROM instances WHERE uuid='%s' AND tenant_id='%s'" % (instance_id
, tenant_id
)
1644 self
.cur
.execute(cmd
)
1645 return 1, "instance %s from tenant %s DELETED" % (instance_id
, tenant_id
)
1647 except (mdb
.Error
, AttributeError) as e
:
1648 r
,c
= self
.format_error(e
, "delete_instance", cmd
)
1649 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1651 def get_ports(self
, WHERE
):
1652 ''' Obtain ports using the WHERE filtering.
1654 'where_': dict of key:values, translated to key=value AND ... (Optional)
1655 Return: a list with dictionarys at each row
1657 for retry_
in range(0,2):
1662 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1663 select_
= "SELECT uuid,'ACTIVE' as status,admin_state_up,name,net_id,\
1664 tenant_id,type,mac,vlan,switch_port,instance_id,Mbps FROM ports "
1666 if WHERE
is None or len(WHERE
) == 0: where_
= ""
1668 where_
= "WHERE " + " AND ".join(map( lambda x
: str(x
) + (" is Null" if WHERE
[x
] is None else "='"+str(WHERE
[x
])+"'"), WHERE
.keys()) )
1669 limit_
= "LIMIT 100"
1670 cmd
= " ".join( (select_
, where_
, limit_
) )
1671 # print "SELECT multiple de instance_ifaces, iface_uuid, external_ports" #print cmd
1672 self
.logger
.debug(cmd
)
1673 self
.cur
.execute(cmd
)
1674 ports
= self
.cur
.fetchall()
1675 if self
.cur
.rowcount
>0: af
.DeleteNone(ports
)
1676 return self
.cur
.rowcount
, ports
1677 # return self.get_table(FROM=from_, SELECT=select_,WHERE=where_,LIMIT=100)
1678 except (mdb
.Error
, AttributeError) as e
:
1679 r
,c
= self
.format_error(e
, "get_ports", cmd
)
1680 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1682 def check_target_net(self
, net_id
, tenant_id
, port_type
):
1683 '''check if valid attachement of a port into a target net
1685 net_id: target net uuid
1686 tenant_id: client where tenant belongs. Not used in this version
1687 port_type: string with the option 'instance:bridge', 'instance:data', 'external'
1689 (0,net_dict) if ok, where net_dict contain 'uuid','type','vlan', ...
1690 (negative,string-error) if error
1692 for retry_
in range(0,2):
1696 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1697 cmd
= "SELECT * FROM nets WHERE uuid='%s'" % net_id
1698 self
.logger
.debug(cmd
)
1699 self
.cur
.execute(cmd
)
1700 if self
.cur
.rowcount
== 0 : return -1, "network_id %s does not match any net" % net_id
1701 net
= self
.cur
.fetchone()
1704 except (mdb
.Error
, AttributeError) as e
:
1705 r
,c
= self
.format_error(e
, "check_target_net", cmd
)
1706 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1708 if tenant_id
is not None and tenant_id
is not "admin":
1709 if net
['tenant_id']==tenant_id
and net
['shared']=='false':
1710 return -1, "needed admin privileges to attach to the net %s" % net_id
1712 if (net
['type'] in ('p2p','data') and port_type
!= 'instance:data') or \
1713 (net
['type'] in ('bridge_data','bridge_man') and port_type
not in ('instance:bridge', 'instance:ovs')):
1714 return -1, "can not attach a port of type %s into a net of type %s" % (port_type
, net
['type'])
1715 if net
['type'] == 'ptp':
1717 nb_ports
, data
= self
.get_ports( {'net_id':net_id
} )
1724 return -1, "net of type p2p already contain two ports attached. No room for another"
1728 if __name__
== "__main__":