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
, logger_name
= None, debug
=None):
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
63 self
.logger_name
= logger_name
65 self
.logger_name
= 'openvim.db'
66 self
.logger
= logging
.getLogger(self
.logger_name
)
68 self
.logger
.setLevel( getattr(logging
, debug
) )
71 def connect(self
, host
=None, user
=None, passwd
=None, database
=None):
72 '''Connect to the concrete data base.
73 The first time a valid host, user, passwd and database must be provided,
74 Following calls can skip this parameters
77 if host
is not None: self
.host
= host
78 if user
is not None: self
.user
= user
79 if passwd
is not None: self
.passwd
= passwd
80 if database
is not None: self
.database
= database
82 self
.con
= mdb
.connect(self
.host
, self
.user
, self
.passwd
, self
.database
)
83 self
.logger
.debug("connected to DB %s at %s@%s", self
.database
,self
.user
, self
.host
)
85 except mdb
.Error
as e
:
86 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])
89 def get_db_version(self
):
90 ''' Obtain the database schema version.
91 Return: (negative, text) if error or version 0.0 where schema_version table is missing
92 (version_int, version_text) if ok
94 cmd
= "SELECT version_int,version,openvim_ver FROM schema_version"
95 for retry_
in range(0,2):
98 self
.cur
= self
.con
.cursor()
99 self
.logger
.debug(cmd
)
100 self
.cur
.execute(cmd
)
101 rows
= self
.cur
.fetchall()
102 highest_version_int
=0
105 for row
in rows
: #look for the latest version
106 if row
[0]>highest_version_int
:
107 highest_version_int
, highest_version
= row
[0:2]
108 return highest_version_int
, highest_version
109 except (mdb
.Error
, AttributeError) as e
:
110 self
.logger
.error("get_db_version DB Exception %d: %s. Command %s",e
.args
[0], e
.args
[1], cmd
)
111 r
,c
= self
.format_error(e
)
112 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
114 def disconnect(self
):
115 '''disconnect from the data base'''
119 except mdb
.Error
as e
:
120 self
.logger
.error("while disconnecting from DB: Error %d: %s",e
.args
[0], e
.args
[1])
122 except AttributeError as e
: #self.con not defined
123 if e
[0][-5:] == "'con'": return -1, "Database internal error, no connection."
126 def format_error(self
, e
, func
, cmd
, command
=None, extra
=None):
127 '''Creates a text error base on the produced exception
130 func: name of the function that makes the call, for logging purposes
131 cmd: database command that produce the exception
132 command: if the intention is update or delete
133 extra: extra information to add to some commands
135 HTTP error in negative, formatted error text
138 self
.logger
.error("%s DB Exception %s. Command %s",func
, str(e
), cmd
)
139 if type(e
[0]) is str:
140 if e
[0][-5:] == "'con'": return -HTTP_Internal_Server_Error
, "DB Exception, no connection."
142 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
145 return -HTTP_Request_Timeout
,"Database reconnection. Try Again"
146 fk
=e
.args
[1].find("foreign key constraint fails")
148 if command
=="update": return -HTTP_Bad_Request
, "tenant_id %s not found." % extra
149 elif command
=="delete": return -HTTP_Bad_Request
, "Resource is not free. There are %s that prevent its deletion." % extra
150 de
= e
.args
[1].find("Duplicate entry")
151 fk
= e
.args
[1].find("for key")
152 uk
= e
.args
[1].find("Unknown column")
153 wc
= e
.args
[1].find("in 'where clause'")
154 fl
= e
.args
[1].find("in 'field list'")
155 #print de, fk, uk, wc,fl
157 if fk
>=0: #error 1062
158 return -HTTP_Conflict
, "Value %s already in use for %s" % (e
.args
[1][de
+15:fk
], e
.args
[1][fk
+7:])
161 return -HTTP_Bad_Request
, "Field %s cannot be used for filtering" % e
.args
[1][uk
+14:wc
]
163 return -HTTP_Bad_Request
, "Field %s does not exist" % e
.args
[1][uk
+14:wc
]
164 return -HTTP_Internal_Server_Error
, "Database internal Error %d: %s" % (e
.args
[0], e
.args
[1])
166 def __data2db_format(self
, data
):
167 '''convert data to database format. If data is None it return the 'Null' text,
168 otherwise it return the text surrounded by quotes ensuring internal quotes are escaped'''
173 return "'" + out
+ "'"
175 return '"' + out
+ '"'
177 return json
.dumps(out
)
179 def __get_used_net_vlan(self
):
180 #get used from database if needed
182 cmd
= "SELECT vlan FROM nets WHERE vlan>='%s' ORDER BY vlan LIMIT 25" % self
.net_vlan_lastused
184 self
.cur
= self
.con
.cursor()
185 self
.logger
.debug(cmd
)
186 self
.cur
.execute(cmd
)
187 vlan_tuple
= self
.cur
.fetchall()
188 #convert a tuple of tuples in a list of numbers
189 self
.net_vlan_usedlist
= []
191 self
.net_vlan_usedlist
.append(k
[0])
193 except (mdb
.Error
, AttributeError) as e
:
194 return self
.format_error(e
, "get_free_net_vlan", cmd
)
196 def get_free_net_vlan(self
):
197 '''obtain a vlan not used in any net'''
200 self
.logger
.debug("net_vlan_lastused:%d net_vlan_range:%d-%d net_vlan_usedlist:%s",
201 self
.net_vlan_lastused
, self
.net_vlan_range
[0], self
.net_vlan_range
[1], str(self
.net_vlan_usedlist
))
202 self
.net_vlan_lastused
+= 1
203 if self
.net_vlan_lastused
== self
.net_vlan_range
[1]:
204 #start from the begining
205 self
.net_vlan_lastused
= self
.net_vlan_range
[0]
206 self
.net_vlan_usedlist
= None
207 if self
.net_vlan_usedlist
is None \
208 or (len(self
.net_vlan_usedlist
)>0 and self
.net_vlan_lastused
>= self
.net_vlan_usedlist
[-1] and len(self
.net_vlan_usedlist
)==25):
209 r
= self
.__get
_used
_net
_vlan
()
211 self
.logger
.debug("new net_vlan_usedlist %s", str(self
.net_vlan_usedlist
))
212 if self
.net_vlan_lastused
in self
.net_vlan_usedlist
:
215 return self
.net_vlan_lastused
217 def get_table(self
, **sql_dict
):
218 ''' Obtain rows from a table.
219 Atribure sql_dir: dictionary with the following key: value
220 'SELECT': [list of fields to retrieve] (by default all)
221 'FROM': string of table name (Mandatory)
222 'WHERE': dict of key:values, translated to key=value AND ... (Optional)
223 'WHERE_NOT': dict of key:values, translated to key!=value AND ... (Optional)
224 'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
225 'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional)
226 'LIMIT': limit of number of rows (Optional)
227 'DISTINCT': make a select distinct to remove repeated elements
228 Return: a list with dictionarys at each row
232 if sql_dict
.get("DISTINCT"):
233 select_
+= "DISTINCT "
234 select_
+= ("*" if not sql_dict
.get('SELECT') else ",".join(map(str,sql_dict
['SELECT'])) )
235 #print 'select_', select_
236 from_
= "FROM " + str(sql_dict
['FROM'])
237 #print 'from_', from_
241 w
= sql_dict
.get('WHERE')
243 where_and
= " AND ".join(map( lambda x
: str(x
) + (" is Null" if w
[x
] is None else "='"+str(w
[x
])+"'"), w
.keys()) )
244 w
= sql_dict
.get('WHERE_NOT')
246 where_and_not
= " AND ".join(map( lambda x
: str(x
) + (" is not Null" if w
[x
] is None else "!='"+str(w
[x
])+"'"), w
.keys()) )
248 where_and
+= " AND " + where_and_not
250 where_and
= where_and_not
251 w
= sql_dict
.get('WHERE_OR')
253 where_or
= " OR ".join(map( lambda x
: str(x
) + (" is Null" if w
[x
] is None else "='"+str(w
[x
])+"'"), w
.keys()) )
255 if where_and
!=None and where_or
!=None:
256 if sql_dict
.get("WHERE_AND_OR") == "AND":
257 where_
= "WHERE " + where_and
+ " AND (" + where_or
+ ")"
259 where_
= "WHERE (" + where_and
+ ") OR " + where_or
260 elif where_and
!=None and where_or
==None:
261 where_
= "WHERE " + where_and
262 elif where_and
==None and where_or
!=None:
263 where_
= "WHERE " + where_or
266 #print 'where_', where_
267 limit_
= "LIMIT " + str(sql_dict
['LIMIT']) if sql_dict
.get("LIMIT") else ""
268 #print 'limit_', limit_
269 cmd
= " ".join( (select_
, from_
, where_
, limit_
) )
270 for retry_
in range(0,2):
273 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
274 self
.logger
.debug(cmd
)
275 self
.cur
.execute(cmd
)
276 rows
= self
.cur
.fetchall()
277 return self
.cur
.rowcount
, rows
278 except (mdb
.Error
, AttributeError) as e
:
279 r
,c
= self
.format_error(e
, "get_table", cmd
)
280 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
282 def new_tenant(self
, tenant_dict
):
283 ''' Add one row into a table.
285 tenant_dict: dictionary with the key: value to insert
286 It checks presence of uuid and add one automatically otherwise
287 Return: (result, uuid) where result can be 0 if error, or 1 if ok
289 for retry_
in range(0,2):
293 #create uuid if not provided
294 if 'uuid' not in tenant_dict
:
295 uuid
= tenant_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
297 uuid
= str(tenant_dict
['uuid'])
298 #obtain tenant_id for logs
301 self
.cur
= self
.con
.cursor()
303 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','tenants')" % uuid
304 self
.logger
.debug(cmd
)
305 self
.cur
.execute(cmd
)
307 cmd
= "INSERT INTO tenants (" + \
308 ",".join(map(str, tenant_dict
.keys() )) + ") VALUES(" + \
309 ",".join(map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'",tenant_dict
.values() )) + ")"
310 self
.logger
.debug(cmd
)
311 self
.cur
.execute(cmd
)
312 inserted
= self
.cur
.rowcount
314 #del tenant_dict['uuid'] # not interested for the log
315 #cmd = "INSERT INTO logs (related,level,tenant_id,uuid,description) VALUES ('tenants','debug','%s','%s',\"new tenant %s\")" % (uuid, tenant_id, str(tenant_dict))
316 #self.logger.debug(cmd)
317 #self.cur.execute(cmd)
320 if inserted
== 0: return 0, uuid
322 self
.cur
= self
.con
.cursor()
323 #adding public flavors
324 cmd
= "INSERT INTO tenants_flavors(flavor_id,tenant_id) SELECT uuid as flavor_id,'"+ tenant_id
+ "' FROM flavors WHERE public = 'yes'"
325 self
.logger
.debug(cmd
)
326 self
.cur
.execute(cmd
)
327 self
.logger
.debug("attached public flavors: %s", str(self
.cur
.rowcount
))
328 #rows = self.cur.fetchall()
330 # cmd = "INSERT INTO tenants_flavors(flavor_id,tenant_id) VALUES('%s','%s')" % (row[0], tenant_id)
331 # self.cur.execute(cmd )
332 #adding public images
333 cmd
= "INSERT INTO tenants_images(image_id,tenant_id) SELECT uuid as image_id,'"+ tenant_id
+ "' FROM images WHERE public = 'yes'"
334 self
.logger
.debug(cmd
)
335 self
.cur
.execute(cmd
)
336 self
.logger
.debug("attached public images: %s", str(self
.cur
.rowcount
))
338 except (mdb
.Error
, AttributeError) as e
:
340 self
.logger
.warning("new_tenant DB Exception %d: %s. Command %s",e
.args
[0], e
.args
[1], cmd
)
343 r
,c
= self
.format_error(e
, "new_tenant", cmd
)
344 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
346 def new_row(self
, table
, INSERT
, add_uuid
=False, log
=False):
347 ''' Add one row into a table.
349 INSERT: dictionary with the key: value to insert
350 table: table where to insert
351 add_uuid: if True, it will crated an uuid key entry at INSERT if not provided
352 It checks presence of uuid and add one automatically otherwise
353 Return: (result, uuid) where result can be 0 if error, or 1 if ok
355 for retry_
in range(0,2):
359 #create uuid if not provided
360 if 'uuid' not in INSERT
:
361 uuid
= INSERT
['uuid'] = str(myUuid
.uuid1()) # create_uuid
363 uuid
= str(INSERT
['uuid'])
367 self
.cur
= self
.con
.cursor()
370 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','%s')" % (uuid
, table
)
371 self
.logger
.debug(cmd
)
372 self
.cur
.execute(cmd
)
374 cmd
= "INSERT INTO " + table
+" (" + \
375 ",".join(map(str, INSERT
.keys() )) + ") VALUES(" + \
376 ",".join(map(lambda x
: 'Null' if x
is None else "'"+str(x
)+"'", INSERT
.values() )) + ")"
377 self
.logger
.debug(cmd
)
378 self
.cur
.execute(cmd
)
379 nb_rows
= self
.cur
.rowcount
381 #if nb_rows > 0 and log:
382 # if add_uuid: del INSERT['uuid']
383 # #obtain tenant_id for logs
384 # if 'tenant_id' in INSERT:
385 # tenant_id = INSERT['tenant_id']
386 # del INSERT['tenant_id']
387 # elif table == 'tenants':
391 # if uuid is None: uuid_k = uuid_v = ""
392 # else: uuid_k=",uuid"; uuid_v=",'" + str(uuid) + "'"
393 # if tenant_id is None: tenant_k = tenant_v = ""
394 # else: tenant_k=",tenant_id"; tenant_v=",'" + str(tenant_id) + "'"
395 # cmd = "INSERT INTO logs (related,level%s%s,description) VALUES ('%s','debug'%s%s,\"new %s %s\")" \
396 # % (uuid_k, tenant_k, table, uuid_v, tenant_v, table[:-1], str(INSERT))
397 # self.logger.debug(cmd)
398 # self.cur.execute(cmd)
401 except (mdb
.Error
, AttributeError) as e
:
402 r
,c
= self
.format_error(e
, "new_row", cmd
)
403 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
405 def __remove_quotes(self
, data
):
406 '''remove single quotes ' of any string content of data dictionary'''
407 for k
,v
in data
.items():
410 data
[k
] = data
[k
].replace("'","_")
412 def _update_rows_internal(self
, table
, UPDATE
, WHERE
={}):
413 cmd
= "UPDATE " + table
+" SET " + \
414 ",".join(map(lambda x
: str(x
)+'='+ self
.__data
2db
_format
(UPDATE
[x
]), UPDATE
.keys() ));
416 cmd
+= " WHERE " + " and ".join(map(lambda x
: str(x
)+ (' is Null' if WHERE
[x
] is None else"='"+str(WHERE
[x
])+"'" ), WHERE
.keys() ))
417 self
.logger
.debug(cmd
)
418 self
.cur
.execute(cmd
)
419 nb_rows
= self
.cur
.rowcount
422 def update_rows(self
, table
, UPDATE
, WHERE
={}, log
=False):
423 ''' Update one or several rows into a table.
425 UPDATE: dictionary with the key-new_value pairs to change
426 table: table to be modified
427 WHERE: dictionary to filter target rows, key-value
428 log: if true, a log entry is added at logs table
429 Return: (result, None) where result indicates the number of updated files
431 for retry_
in range(0,2):
435 uuid
= WHERE
.get('uuid')
438 self
.cur
= self
.con
.cursor()
439 cmd
= "UPDATE " + table
+" SET " + \
440 ",".join(map(lambda x
: str(x
)+'='+ self
.__data
2db
_format
(UPDATE
[x
]), UPDATE
.keys() ));
442 cmd
+= " WHERE " + " and ".join(map(lambda x
: str(x
)+ (' is Null' if WHERE
[x
] is None else"='"+str(WHERE
[x
])+"'" ), WHERE
.keys() ))
443 self
.logger
.debug(cmd
)
444 self
.cur
.execute(cmd
)
445 nb_rows
= self
.cur
.rowcount
446 #if nb_rows > 0 and log:
448 # if uuid is None: uuid_k = uuid_v = ""
449 # else: uuid_k=",uuid"; uuid_v=",'" + str(uuid) + "'"
450 # cmd = "INSERT INTO logs (related,level%s,description) VALUES ('%s','debug'%s,\"updating %d entry %s\")" \
451 # % (uuid_k, table, uuid_v, nb_rows, (str(UPDATE)).replace('"','-') )
452 # self.logger.debug(cmd)
453 # self.cur.execute(cmd)
455 except (mdb
.Error
, AttributeError) as e
:
456 r
,c
= self
.format_error(e
, "update_rows", cmd
)
457 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
459 def get_host(self
, host_id
):
460 if af
.check_valid_uuid(host_id
):
461 where_filter
="uuid='" + host_id
+ "'"
463 where_filter
="name='" + host_id
+ "'"
464 for retry_
in range(0,2):
468 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
470 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 \
471 FROM hosts WHERE " + where_filter
472 self
.logger
.debug(cmd
)
473 self
.cur
.execute(cmd
)
474 if self
.cur
.rowcount
== 0 :
475 return 0, "host '" + str(host_id
) +"'not found."
476 elif self
.cur
.rowcount
> 1 :
477 return 0, "host '" + str(host_id
) +"' matches more than one result."
478 host
= self
.cur
.fetchone()
479 host_id
= host
['uuid']
481 cmd
= "SELECT id, numa_socket, hugepages, memory, admin_state_up FROM numas WHERE host_id = '" + str(host_id
) + "'"
482 self
.logger
.debug(cmd
)
483 self
.cur
.execute(cmd
)
484 host
['numas'] = self
.cur
.fetchall()
485 for numa
in host
['numas']:
486 #print "SELECT core_id, instance_id, status, thread_id, v_thread_id FROM resources_core WHERE numa_id = '" + str(numa['id']) + "'"
488 cmd
= "SELECT core_id, instance_id, status, thread_id, v_thread_id FROM resources_core WHERE numa_id = '" + str(numa
['id']) + "'"
489 self
.logger
.debug(cmd
)
490 self
.cur
.execute(cmd
)
491 numa
['cores'] = self
.cur
.fetchall()
492 for core
in numa
['cores']:
493 if core
['instance_id'] == None: del core
['instance_id'], core
['v_thread_id']
494 if core
['status'] == 'ok': del core
['status']
496 cmd
= "SELECT sum(consumed) as hugepages_consumed FROM resources_mem WHERE numa_id = '" + str(numa
['id']) + "' GROUP BY numa_id"
497 self
.logger
.debug(cmd
)
498 self
.cur
.execute(cmd
)
499 used
= self
.cur
.fetchone()
500 used_
= int(used
['hugepages_consumed']) if used
!= None else 0
501 numa
['hugepages_consumed'] = used_
503 #cmd = "CALL GetPortsFromNuma(%s)'" % str(numa['id'])
504 #self.cur.callproc('GetPortsFromNuma', (numa['id'],) )
505 #every time a Procedure is launched you need to close and open the cursor
506 #under Error 2014: Commands out of sync; you can't run this command now
508 #self.cur = self.con.cursor(mdb.cursors.DictCursor)
509 cmd
="SELECT Mbps, pci, status, Mbps_used, instance_id, if(id=root_id,'PF','VF') as type_,\
510 switch_port, switch_dpid, mac, source_name\
511 FROM resources_port WHERE numa_id=%d ORDER BY root_id, type_ DESC" % (numa
['id'])
512 self
.logger
.debug(cmd
)
513 self
.cur
.execute(cmd
)
514 ifaces
= self
.cur
.fetchall()
515 #The SQL query will ensure to have SRIOV interfaces from a port first
518 numa
['interfaces'] = []
520 if not iface
["instance_id"]:
521 del iface
["instance_id"]
522 if iface
['status'] == 'ok':
524 Mpbs_consumed
+= int(iface
["Mbps_used"])
525 del iface
["Mbps_used"]
526 if iface
["type_"]=='PF':
527 if not iface
["switch_dpid"]:
528 del iface
["switch_dpid"]
529 if not iface
["switch_port"]:
530 del iface
["switch_port"]
532 iface
["sriovs"] = sriovs
534 iface
["Mpbs_consumed"] = Mpbs_consumed
536 numa
['interfaces'].append(iface
)
540 del iface
["switch_port"]
541 del iface
["switch_dpid"]
546 #delete internal field
549 except (mdb
.Error
, AttributeError) as e
:
550 r
,c
= self
.format_error(e
, "get_host", cmd
)
551 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
556 uuid
= str( myUuid
.uuid1() )
557 if self
.check_uuid(uuid
)[0] == 0:
562 def check_uuid(self
, uuid
):
563 '''check in the database if this uuid is already present'''
565 cmd
= "SELECT * FROM uuids where uuid='" + str(uuid
) + "'"
567 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
568 self
.logger
.debug(cmd
)
569 self
.cur
.execute(cmd
)
570 rows
= self
.cur
.fetchall()
571 return self
.cur
.rowcount
, rows
572 except (mdb
.Error
, AttributeError) as e
:
573 return self
.format_error(e
, "check_uuid", cmd
)
575 def __get_next_ids(self
):
576 '''get next auto increment index of all table in the database'''
577 self
.cur
.execute("SELECT table_name,AUTO_INCREMENT FROM information_schema.tables WHERE AUTO_INCREMENT IS NOT NULL AND table_schema = DATABASE()")
578 rows
= self
.cur
.fetchall()
579 return self
.cur
.rowcount
, dict(rows
)
581 def edit_host(self
, host_id
, host_dict
):
583 for retry_
in range(0,2):
587 self
.cur
= self
.con
.cursor()
590 numa_list
= host_dict
.pop('numas', () )
592 self
._update
_rows
_internal
("hosts", host_dict
, {"uuid": host_id
})
594 where
= {"host_id": host_id
}
595 for numa_dict
in numa_list
:
596 where
["numa_socket"] = str(numa_dict
.pop('numa_socket'))
597 interface_list
= numa_dict
.pop('interfaces', () )
599 self
._update
_rows
_internal
("numas", numa_dict
, where
)
600 for interface
in interface_list
:
601 source_name
= str(interface
.pop("source_name") )
603 #get interface id from resources_port
604 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 " +\
605 "WHERE host_id='%s' and rp.source_name='%s'" %(host_id
, source_name
)
606 self
.logger
.debug(cmd
)
607 self
.cur
.execute(cmd
)
608 row
= self
.cur
.fetchone()
609 if self
.cur
.rowcount
<=0:
610 return -HTTP_Bad_Request
, "Interface source_name='%s' from numa_socket='%s' not found" % (source_name
, str(where
["numa_socket"]))
611 interface_id
= row
[0]
612 self
._update
_rows
_internal
("resources_port", interface
, {"root_id": interface_id
})
613 return self
.get_host(host_id
)
614 except (mdb
.Error
, AttributeError) as e
:
615 r
,c
= self
.format_error(e
, "edit_host", cmd
)
616 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
618 def new_host(self
, host_dict
):
620 for retry_
in range(0,2):
624 self
.cur
= self
.con
.cursor()
626 result
, next_ids
= self
.__get
_next
_ids
()
627 #print "next_ids: " + str(next_ids)
628 if result
<= 0: return result
, "Internal DataBase error getting next id of tables"
630 #create uuid if not provided
631 if 'uuid' not in host_dict
:
632 uuid
= host_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
633 else: #check uuid is valid
634 uuid
= str(host_dict
['uuid'])
635 # result, data = self.check_uuid(uuid)
637 # return -1, "UUID '%s' already in use" % uuid
640 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','hosts')" % uuid
641 self
.logger
.debug(cmd
)
642 result
= self
.cur
.execute(cmd
)
644 #insert in table host
645 numa_list
= host_dict
.pop('numas', [])
646 #get nonhupages and nonisolated cpus
649 for numa
in numa_list
:
650 mem_numa
= numa
.get('memory', 0) - numa
.get('hugepages',0)
652 host_dict
['RAM'] += mem_numa
653 for core
in numa
.get("cores", []):
654 if "status" in core
and core
["status"]=="noteligible":
656 host_dict
['RAM']*=1024 # from GB to MB
658 keys
= ",".join(host_dict
.keys())
659 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", host_dict
.values() ) )
660 cmd
= "INSERT INTO hosts (" + keys
+ ") VALUES (" + values
+ ")"
661 self
.logger
.debug(cmd
)
662 result
= self
.cur
.execute(cmd
)
663 #if result != 1: return -1, "Database Error while inserting at hosts table"
666 nb_numas
= nb_cores
= nb_ifaces
= 0
667 for numa_dict
in numa_list
:
669 interface_list
= numa_dict
.pop('interfaces', [])
670 core_list
= numa_dict
.pop('cores', [])
671 numa_dict
['id'] = next_ids
['numas']; next_ids
['numas'] += 1
672 numa_dict
['host_id'] = uuid
673 keys
= ",".join(numa_dict
.keys())
674 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", numa_dict
.values() ) )
675 cmd
= "INSERT INTO numas (" + keys
+ ") VALUES (" + values
+ ")"
676 self
.logger
.debug(cmd
)
677 result
= self
.cur
.execute(cmd
)
680 for core_dict
in core_list
:
682 core_dict
['numa_id'] = numa_dict
['id']
683 keys
= ",".join(core_dict
.keys())
684 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", core_dict
.values() ) )
685 cmd
= "INSERT INTO resources_core (" + keys
+ ") VALUES (" + values
+ ")"
686 self
.logger
.debug(cmd
)
687 result
= self
.cur
.execute(cmd
)
690 for port_dict
in interface_list
:
692 sriov_list
= port_dict
.pop('sriovs', [])
693 port_dict
['numa_id'] = numa_dict
['id']
694 port_dict
['id'] = port_dict
['root_id'] = next_ids
['resources_port']
695 next_ids
['resources_port'] += 1
696 switch_port
= port_dict
.get('switch_port', None)
697 switch_dpid
= port_dict
.get('switch_dpid', None)
698 keys
= ",".join(port_dict
.keys())
699 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", port_dict
.values() ) )
700 cmd
= "INSERT INTO resources_port (" + keys
+ ") VALUES (" + values
+ ")"
701 self
.logger
.debug(cmd
)
702 result
= self
.cur
.execute(cmd
)
704 #insert sriovs into port table
705 for sriov_dict
in sriov_list
:
706 sriov_dict
['switch_port'] = switch_port
707 sriov_dict
['switch_dpid'] = switch_dpid
708 sriov_dict
['numa_id'] = port_dict
['numa_id']
709 sriov_dict
['Mbps'] = port_dict
['Mbps']
710 sriov_dict
['root_id'] = port_dict
['id']
711 sriov_dict
['id'] = next_ids
['resources_port']
712 if "vlan" in sriov_dict
:
713 del sriov_dict
["vlan"]
714 next_ids
['resources_port'] += 1
715 keys
= ",".join(sriov_dict
.keys())
716 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", sriov_dict
.values() ) )
717 cmd
= "INSERT INTO resources_port (" + keys
+ ") VALUES (" + values
+ ")"
718 self
.logger
.debug(cmd
)
719 result
= self
.cur
.execute(cmd
)
722 #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)
723 #self.logger.debug(cmd)
724 #result = self.cur.execute(cmd)
728 self
.cur
= self
.con
.cursor()
729 self
.logger
.debug("callproc('UpdateSwitchPort', () )")
730 self
.cur
.callproc('UpdateSwitchPort', () )
732 self
.logger
.debug("getting host '%s'",str(host_dict
['uuid']))
733 return self
.get_host(host_dict
['uuid'])
734 except (mdb
.Error
, AttributeError) as e
:
735 r
,c
= self
.format_error(e
, "new_host", cmd
)
736 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
738 def new_flavor(self
, flavor_dict
, tenant_id
):
739 '''Add new flavor into the database. Create uuid if not provided
741 flavor_dict: flavor dictionary with the key: value to insert. Must be valid flavors columns
742 tenant_id: if not 'any', it matches this flavor/tenant inserting at tenants_flavors table
743 Return: (result, data) where result can be
744 negative: error at inserting. data contain text
745 1, inserted, data contain inserted uuid flavor
747 for retry_
in range(0,2):
751 self
.cur
= self
.con
.cursor()
753 #create uuid if not provided
754 if 'uuid' not in flavor_dict
:
755 uuid
= flavor_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
756 else: #check uuid is valid
757 uuid
= str(flavor_dict
['uuid'])
758 # result, data = self.check_uuid(uuid)
760 # return -1, "UUID '%s' already in use" % uuid
763 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','flavors')" % uuid
764 self
.logger
.debug(cmd
)
765 self
.cur
.execute(cmd
)
767 #insert in table flavor
768 keys
= ",".join(flavor_dict
.keys())
769 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", flavor_dict
.values() ) )
770 cmd
= "INSERT INTO flavors (" + keys
+ ") VALUES (" + values
+ ")"
771 self
.logger
.debug(cmd
)
772 self
.cur
.execute(cmd
)
773 #if result != 1: return -1, "Database Error while inserting at flavors table"
775 #insert tenants_flavors
776 if tenant_id
!= 'any':
777 cmd
= "INSERT INTO tenants_flavors (tenant_id,flavor_id) VALUES ('%s','%s')" % (tenant_id
, uuid
)
778 self
.logger
.debug(cmd
)
779 self
.cur
.execute(cmd
)
782 #del flavor_dict['uuid']
783 #if 'extended' in flavor_dict: del flavor_dict['extended'] #remove two many information
784 #cmd = "INSERT INTO logs (related,level,uuid, tenant_id, description) VALUES ('flavors','debug','%s','%s',\"new flavor: %s\")" \
785 # % (uuid, tenant_id, str(flavor_dict))
786 #self.logger.debug(cmd)
787 #self.cur.execute(cmd)
791 except (mdb
.Error
, AttributeError) as e
:
792 r
,c
= self
.format_error(e
, "new_flavor", cmd
, "update", tenant_id
)
793 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
795 def new_image(self
, image_dict
, tenant_id
):
796 '''Add new image into the database. Create uuid if not provided
798 image_dict: image dictionary with the key: value to insert. Must be valid images columns
799 tenant_id: if not 'any', it matches this image/tenant inserting at tenants_images table
800 Return: (result, data) where result can be
801 negative: error at inserting. data contain text
802 1, inserted, data contain inserted uuid image
804 for retry_
in range(0,2):
808 self
.cur
= self
.con
.cursor()
810 #create uuid if not provided
811 if 'uuid' not in image_dict
:
812 uuid
= image_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
813 else: #check uuid is valid
814 uuid
= str(image_dict
['uuid'])
815 # result, data = self.check_uuid(uuid)
817 # return -1, "UUID '%s' already in use" % uuid
820 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','images')" % uuid
821 self
.logger
.debug(cmd
)
822 self
.cur
.execute(cmd
)
824 #insert in table image
825 keys
= ",".join(image_dict
.keys())
826 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", image_dict
.values() ) )
827 cmd
= "INSERT INTO images (" + keys
+ ") VALUES (" + values
+ ")"
828 self
.logger
.debug(cmd
)
829 self
.cur
.execute(cmd
)
830 #if result != 1: return -1, "Database Error while inserting at images table"
832 #insert tenants_images
833 if tenant_id
!= 'any':
834 cmd
= "INSERT INTO tenants_images (tenant_id,image_id) VALUES ('%s','%s')" % (tenant_id
, uuid
)
835 self
.logger
.debug(cmd
)
836 self
.cur
.execute(cmd
)
839 #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'])
840 #self.logger.debug(cmd)
841 #self.cur.execute(cmd)
845 except (mdb
.Error
, AttributeError) as e
:
846 r
,c
= self
.format_error(e
, "new_image", cmd
, "update", tenant_id
)
847 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
849 def delete_image_flavor(self
, item_type
, item_id
, tenant_id
):
850 '''deletes an image or flavor from database
851 item_type must be a 'image' or 'flavor'
853 tenant_id is the asociated tenant, can be 'any' with means all
854 If tenan_id is not any, it deletes from tenants_images/flavors,
855 which means this image/flavor is used by this tenant, and if success,
856 it tries to delete from images/flavors in case this is not public,
857 that only will success if image is private and not used by other tenants
858 If tenant_id is any, it tries to delete from both tables at the same transaction
859 so that image/flavor is completely deleted from all tenants or nothing
861 for retry_
in range(0,2):
864 result
= (-HTTP_Internal_Server_Error
, "internal error")
868 self
.cur
= self
.con
.cursor()
869 cmd
= "DELETE FROM tenants_%ss WHERE %s_id = '%s'" % (item_type
, item_type
, item_id
)
870 if tenant_id
!= 'any':
871 cmd
+= " AND tenant_id = '%s'" % tenant_id
872 self
.logger
.debug(cmd
)
873 self
.cur
.execute(cmd
)
874 deleted
= self
.cur
.rowcount
875 if tenant_id
== 'any': #delete from images/flavors in the SAME transaction
876 cmd
= "DELETE FROM %ss WHERE uuid = '%s'" % (item_type
, item_id
)
877 self
.logger
.debug(cmd
)
878 self
.cur
.execute(cmd
)
879 deleted
= self
.cur
.rowcount
882 cmd
= "DELETE FROM uuids WHERE uuid = '%s'" % item_id
883 self
.logger
.debug(cmd
)
884 self
.cur
.execute(cmd
)
886 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) \
887 # VALUES ('%ss','debug','%s','%s','delete %s completely')" % \
888 # (item_type, item_id, tenant_id, item_type)
889 #self.logger.debug(cmd)
890 #self.cur.execute(cmd)
891 return deleted
, "%s '%s' completely deleted" % (item_type
, item_id
)
892 return 0, "%s '%s' not found" % (item_type
, item_id
)
896 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) \
897 # VALUES ('%ss','debug','%s','%s','delete %s reference for this tenant')" % \
898 # (item_type, item_id, tenant_id, item_type)
899 #self.logger.debug(cmd)
900 #self.cur.execute(cmd)
904 #if tenant!=any delete from images/flavors in OTHER transaction. If fails is because dependencies so that not return error
907 self
.cur
= self
.con
.cursor()
909 #delete image/flavor if not public
910 cmd
= "DELETE FROM %ss WHERE uuid = '%s' AND public = 'no'" % (item_type
, item_id
)
911 self
.logger
.debug(cmd
)
912 self
.cur
.execute(cmd
)
913 deleted_item
= self
.cur
.rowcount
914 if deleted_item
== 1:
916 cmd
= "DELETE FROM uuids WHERE uuid = '%s'" % item_id
917 self
.logger
.debug(cmd
)
918 self
.cur
.execute(cmd
)
920 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) \
921 # VALUES ('%ss','debug','%s','%s','delete %s completely')" % \
922 # (item_type, item_id, tenant_id, item_type)
923 #self.logger.debug(cmd)
924 #self.cur.execute(cmd)
925 except (mdb
.Error
, AttributeError) as e
:
926 #print "delete_%s DB Exception %d: %s" % (item_type, e.args[0], e.args[1])
928 result
= self
.format_error(e
, "delete_"+item_type
, cmd
, "delete", "servers")
931 return 1, "%s '%s' from tenant '%s' %sdeleted" % \
932 (item_type
, item_id
, tenant_id
, "completely " if deleted_item
==1 else "")
934 return 0, "%s '%s' from tenant '%s' not found" % (item_type
, item_id
, tenant_id
)
936 if result
[0]!=-HTTP_Request_Timeout
or retry_
==1: return result
938 def delete_row(self
, table
, uuid
):
939 for retry_
in range(0,2):
944 self
.cur
= self
.con
.cursor()
945 cmd
= "DELETE FROM %s WHERE uuid = '%s'" % (table
, uuid
)
946 self
.logger
.debug(cmd
)
947 self
.cur
.execute(cmd
)
948 deleted
= self
.cur
.rowcount
951 if table
== 'tenants': tenant_str
=uuid
952 else: tenant_str
='Null'
953 self
.cur
= self
.con
.cursor()
954 cmd
= "DELETE FROM uuids WHERE uuid = '%s'" % uuid
955 self
.logger
.debug(cmd
)
956 self
.cur
.execute(cmd
)
958 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) VALUES ('%s','debug','%s','%s','delete %s')" % (table, uuid, tenant_str, table[:-1])
959 #self.logger.debug(cmd)
960 #self.cur.execute(cmd)
961 return deleted
, table
[:-1] + " '%s' %s" %(uuid
, "deleted" if deleted
==1 else "not found")
962 except (mdb
.Error
, AttributeError) as e
:
963 r
,c
= self
.format_error(e
, "delete_row", cmd
, "delete", 'instances' if table
=='hosts' or table
=='tenants' else 'dependencies')
964 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
966 def delete_row_by_key(self
, table
, key
, value
):
967 for retry_
in range(0,2):
972 self
.cur
= self
.con
.cursor()
973 cmd
= "DELETE FROM %s" % (table
)
976 cmd
+= " WHERE %s = '%s'" % (key
, value
)
978 cmd
+= " WHERE %s is null" % (key
)
981 self
.logger
.debug(cmd
)
982 self
.cur
.execute(cmd
)
983 deleted
= self
.cur
.rowcount
985 return -1, 'Not found'
988 except (mdb
.Error
, AttributeError) as e
:
989 r
,c
= self
.format_error(e
, "delete_row_by_key", cmd
, "delete", 'instances' if table
=='hosts' or table
=='tenants' else 'dependencies')
990 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
992 def delete_row_by_dict(self
, **sql_dict
):
993 ''' Deletes rows from a table.
994 Attribute sql_dir: dictionary with the following key: value
995 'FROM': string of table name (Mandatory)
996 'WHERE': dict of key:values, translated to key=value AND ... (Optional)
997 'WHERE_NOT': dict of key:values, translated to key<>value AND ... (Optional)
998 'WHERE_NOTNULL': (list or tuple of items that must not be null in a where ... (Optional)
999 'LIMIT': limit of number of rows (Optional)
1000 Return: the (number of items deleted, descriptive test) if ok; (negative, descriptive text) if error
1003 from_
= "FROM " + str(sql_dict
['FROM'])
1004 #print 'from_', from_
1005 if 'WHERE' in sql_dict
and len(sql_dict
['WHERE']) > 0:
1007 where_
= "WHERE " + " AND ".join(map( lambda x
: str(x
) + (" is Null" if w
[x
] is None else "='"+str(w
[x
])+"'"), w
.keys()) )
1009 if 'WHERE_NOT' in sql_dict
and len(sql_dict
['WHERE_NOT']) > 0:
1010 w
=sql_dict
['WHERE_NOT']
1011 where_2
= " AND ".join(map( lambda x
: str(x
) + (" is not Null" if w
[x
] is None else "<>'"+str(w
[x
])+"'"), w
.keys()) )
1012 if len(where_
)==0: where_
= "WHERE " + where_2
1013 else: where_
= where_
+ " AND " + where_2
1014 if 'WHERE_NOTNULL' in sql_dict
and len(sql_dict
['WHERE_NOTNULL']) > 0:
1015 w
=sql_dict
['WHERE_NOTNULL']
1016 where_2
= " AND ".join(map( lambda x
: str(x
) + " is not Null", w
) )
1017 if len(where_
)==0: where_
= "WHERE " + where_2
1018 else: where_
= where_
+ " AND " + where_2
1019 #print 'where_', where_
1020 limit_
= "LIMIT " + str(sql_dict
['LIMIT']) if 'LIMIT' in sql_dict
else ""
1021 #print 'limit_', limit_
1022 cmd
= " ".join( ("DELETE", from_
, where_
, limit_
) )
1023 self
.logger
.debug(cmd
)
1024 for retry_
in range(0,2):
1028 self
.cur
= self
.con
.cursor()
1029 self
.cur
.execute(cmd
)
1030 deleted
= self
.cur
.rowcount
1031 return deleted
, "%d deleted from %s" % (deleted
, sql_dict
['FROM'][:-1] )
1032 except (mdb
.Error
, AttributeError) as e
:
1033 r
,c
= self
.format_error(e
, "delete_row_by_dict", cmd
, "delete", 'dependencies')
1034 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1037 def get_instance(self
, instance_id
):
1038 for retry_
in range(0,2):
1042 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1044 cmd
= "SELECT uuid, name, description, progress, host_id, flavor_id, image_id, status, last_error, "\
1045 "tenant_id, ram, vcpus, created_at FROM instances WHERE uuid='{}'".format(instance_id
)
1046 self
.logger
.debug(cmd
)
1047 self
.cur
.execute(cmd
)
1048 if self
.cur
.rowcount
== 0 : return 0, "instance '" + str(instance_id
) +"'not found."
1049 instance
= self
.cur
.fetchone()
1051 cmd
= "SELECT uuid as iface_id, net_id, mac as mac_address, ip_address, name, Mbps as bandwidth, "\
1052 "vpci, model FROM ports WHERE (type='instance:bridge' or type='instance:ovs') AND "\
1053 "instance_id= '{}'".format(instance_id
)
1054 self
.logger
.debug(cmd
)
1055 self
.cur
.execute(cmd
)
1056 if self
.cur
.rowcount
> 0 :
1057 instance
['networks'] = self
.cur
.fetchall()
1062 cmd
= "SELECT type, vpci, image_id, xml,dev FROM instance_devices WHERE instance_id = '%s' " % str(instance_id
)
1063 self
.logger
.debug(cmd
)
1064 self
.cur
.execute(cmd
)
1065 if self
.cur
.rowcount
> 0 :
1066 extended
['devices'] = self
.cur
.fetchall()
1069 cmd
= "SELECT id, numa_socket as source FROM numas WHERE host_id = '" + str(instance
['host_id']) + "'"
1070 self
.logger
.debug(cmd
)
1071 self
.cur
.execute(cmd
)
1072 host_numas
= self
.cur
.fetchall()
1073 #print 'host_numas', host_numas
1074 for k
in host_numas
:
1075 numa_id
= str(k
['id'])
1078 cmd
= "SELECT consumed FROM resources_mem WHERE instance_id = '%s' AND numa_id = '%s'" % ( instance_id
, numa_id
)
1079 self
.logger
.debug(cmd
)
1080 self
.cur
.execute(cmd
)
1081 if self
.cur
.rowcount
> 0:
1082 mem_dict
= self
.cur
.fetchone()
1083 numa_dict
['memory'] = mem_dict
['consumed']
1085 cursor2
= self
.con
.cursor()
1086 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
)
1087 self
.logger
.debug(cmd
)
1088 cursor2
.execute(cmd
)
1089 core_list
= []; core_source
= []
1090 paired_list
= []; paired_source
= []
1091 thread_list
= []; thread_source
= []
1092 if cursor2
.rowcount
> 0:
1093 cores
= cursor2
.fetchall()
1095 if core
[4] == 2: #number of used threads from core
1096 if core
[3] == core
[2]: #only one thread asigned to VM, so completely core
1097 core_list
.append(core
[2])
1098 core_source
.append(core
[5])
1099 elif core
[1] == 'Y':
1100 paired_list
.append(core
[2:4])
1101 paired_source
.append(core
[5:7])
1103 thread_list
.extend(core
[2:4])
1104 thread_source
.extend(core
[5:7])
1107 thread_list
.append(core
[2])
1108 thread_source
.append(core
[5])
1109 if len(core_list
) > 0:
1110 numa_dict
['cores'] = len(core_list
)
1111 numa_dict
['cores-id'] = core_list
1112 numa_dict
['cores-source'] = core_source
1113 if len(paired_list
) > 0:
1114 numa_dict
['paired-threads'] = len(paired_list
)
1115 numa_dict
['paired-threads-id'] = paired_list
1116 numa_dict
['paired-threads-source'] = paired_source
1117 if len(thread_list
) > 0:
1118 numa_dict
['threads'] = len(thread_list
)
1119 numa_dict
['threads-id'] = thread_list
1120 numa_dict
['threads-source'] = thread_source
1122 #get dedicated ports and SRIOV
1123 cmd
= "SELECT port_id as iface_id, p.vlan as vlan, p.mac as mac_address, net_id, if(model='PF',\
1124 'yes',if(model='VF','no','yes:sriov')) as dedicated, rp.Mbps as bandwidth, name, vpci, \
1126 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
)
1127 self
.logger
.debug(cmd
)
1128 self
.cur
.execute(cmd
)
1129 if self
.cur
.rowcount
> 0:
1130 numa_dict
['interfaces'] = self
.cur
.fetchall()
1131 #print 'interfaces', numa_dict
1133 if len(numa_dict
) > 0 :
1134 numa_dict
['source'] = k
['source'] #numa socket
1135 numas
.append(numa_dict
)
1137 if len(numas
) > 0 : extended
['numas'] = numas
1138 if len(extended
) > 0 : instance
['extended'] = extended
1139 af
.DeleteNone(instance
)
1141 except (mdb
.Error
, AttributeError) as e
:
1142 r
,c
= self
.format_error(e
, "get_instance", cmd
)
1143 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1145 def get_numas(self
, requirements
, prefered_host_id
=None, only_of_ports
=True):
1146 '''Obtain a valid NUMA/HOST for deployment a VM
1147 requirements: contain requirement regarding:
1148 requirements['ram']: Non huge page memory in MB; 0 to skip
1149 requirements['vcpus']: Non isolated cpus; 0 to skip
1150 requirements['numa']: Requiremets to be fixed in ONE Numa node
1151 requirements['numa']['memory']: Huge page memory in GB at ; 0 for any
1152 requirements['numa']['proc_req_type']: Type of processor, cores or threads
1153 requirements['numa']['proc_req_nb']: Number of isolated cpus
1154 requirements['numa']['port_list']: Physical NIC ports list ; [] for any
1155 requirements['numa']['sriov_list']: Virtual function NIC ports list ; [] for any
1156 prefered_host_id: if not None return this host if it match
1157 only_of_ports: if True only those ports conected to the openflow (of) are valid,
1158 that is, with switch_port information filled; if False, all NIC ports are valid.
1159 Return a valid numa and host
1162 for retry_
in range(0,2):
1166 # #Find numas of prefered host
1167 # prefered_numas = ()
1168 # if prefered_host_id != None:
1169 # self.cur = self.con.cursor()
1170 # self.cur.execute("SELECT id FROM numas WHERE host_id='%s'" + prefered_host_id)
1171 # prefered_numas = self.cur.fetchall()
1174 #Find valid host for the ram and vcpus
1175 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1176 cmd
= "CALL GetHostByMemCpu(%s, %s)" % (str(requirements
['ram']), str(requirements
['vcpus']))
1177 self
.logger
.debug(cmd
)
1178 self
.cur
.callproc('GetHostByMemCpu', (str(requirements
['ram']), str(requirements
['vcpus'])) )
1179 valid_hosts
= self
.cur
.fetchall()
1181 self
.cur
= self
.con
.cursor()
1183 if len(valid_hosts
)<=0:
1184 error_text
= 'No room at data center. Cannot find a host with %s MB memory and %s cpus available' % (str(requirements
['ram']), str(requirements
['vcpus']))
1185 #self.logger.debug(error_text)
1186 return -1, error_text
1188 #elif req_numa != None:
1189 #Find valid numa nodes for memory requirements
1190 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1191 cmd
= "CALL GetNumaByMemory(%s)" % str(requirements
['numa']['memory'])
1192 self
.logger
.debug(cmd
)
1193 self
.cur
.callproc('GetNumaByMemory', (requirements
['numa']['memory'],) )
1194 valid_for_memory
= self
.cur
.fetchall()
1196 self
.cur
= self
.con
.cursor()
1197 if len(valid_for_memory
)<=0:
1198 error_text
= 'No room at data center. Cannot find a host with %s GB Hugepages memory available' % str(requirements
['numa']['memory'])
1199 #self.logger.debug(error_text)
1200 return -1, error_text
1202 #Find valid numa nodes for processor requirements
1203 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1204 if requirements
['numa']['proc_req_type'] == 'threads':
1205 cpu_requirement_text
='cpu-threads'
1206 cmd
= "CALL GetNumaByThread(%s)" % str(requirements
['numa']['proc_req_nb'])
1207 self
.logger
.debug(cmd
)
1208 self
.cur
.callproc('GetNumaByThread', (requirements
['numa']['proc_req_nb'],) )
1210 cpu_requirement_text
='cpu-cores'
1211 cmd
= "CALL GetNumaByCore(%s)" % str(requirements
['numa']['proc_req_nb'])
1212 self
.logger
.debug(cmd
)
1213 self
.cur
.callproc('GetNumaByCore', (requirements
['numa']['proc_req_nb'],) )
1214 valid_for_processor
= self
.cur
.fetchall()
1216 self
.cur
= self
.con
.cursor()
1217 if len(valid_for_processor
)<=0:
1218 error_text
= 'No room at data center. Cannot find a host with %s %s available' % (str(requirements
['numa']['proc_req_nb']),cpu_requirement_text
)
1219 #self.logger.debug(error_text)
1220 return -1, error_text
1222 #Find the numa nodes that comply for memory and processor requirements
1223 #sorting from less to more memory capacity
1225 for m_numa
in valid_for_memory
:
1226 numa_valid_for_processor
= False
1227 for p_numa
in valid_for_processor
:
1228 if m_numa
['numa_id'] == p_numa
['numa_id']:
1229 numa_valid_for_processor
= True
1231 numa_valid_for_host
= False
1232 prefered_numa
= False
1233 for p_host
in valid_hosts
:
1234 if m_numa
['host_id'] == p_host
['uuid']:
1235 numa_valid_for_host
= True
1236 if p_host
['uuid'] == prefered_host_id
:
1237 prefered_numa
= True
1239 if numa_valid_for_host
and numa_valid_for_processor
:
1241 valid_numas
.insert(0, m_numa
['numa_id'])
1243 valid_numas
.append(m_numa
['numa_id'])
1244 if len(valid_numas
)<=0:
1245 error_text
= 'No room at data center. Cannot find a host with %s MB hugepages memory and %s %s available in the same numa' %\
1246 (requirements
['numa']['memory'], str(requirements
['numa']['proc_req_nb']),cpu_requirement_text
)
1247 #self.logger.debug(error_text)
1248 return -1, error_text
1250 # print 'Valid numas list: '+str(valid_numas)
1252 #Find valid numa nodes for interfaces requirements
1253 #For each valid numa we will obtain the number of available ports and check if these are valid
1255 for numa_id
in valid_numas
:
1256 # print 'Checking '+str(numa_id)
1258 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1260 cmd
="CALL GetAvailablePorts(%s)" % str(numa_id
)
1261 self
.logger
.debug(cmd
)
1262 self
.cur
.callproc('GetAvailablePorts', (numa_id
,) )
1264 cmd
="CALL GetAllAvailablePorts(%s)" % str(numa_id
)
1265 self
.logger
.debug(cmd
)
1266 self
.cur
.callproc('GetAllAvailablePorts', (numa_id
,) )
1267 available_ports
= self
.cur
.fetchall()
1269 self
.cur
= self
.con
.cursor()
1271 #Set/reset reservations
1272 for port
in available_ports
:
1273 port
['Mbps_reserved'] = 0
1274 port
['SRIOV_reserved'] = 0
1276 #Try to allocate physical ports
1277 physical_ports_found
= True
1278 for iface
in requirements
['numa']['port_list']:
1279 # print '\t\tchecking iface: '+str(iface)
1281 for port
in available_ports
:
1282 # print '\t\t\tfor port: '+str(port)
1283 #If the port is not empty continue
1284 if port
['Mbps_free'] != port
['Mbps'] or port
['Mbps_reserved'] != 0:
1285 # print '\t\t\t\t Not empty port'
1287 #If the port speed is not enough continue
1288 if port
['Mbps'] < iface
['bandwidth']:
1289 # print '\t\t\t\t Not enough speed'
1292 #Otherwise this is a valid port
1293 port
['Mbps_reserved'] = port
['Mbps']
1294 port
['SRIOV_reserved'] = 0
1295 iface
['port_id'] = port
['port_id']
1296 iface
['vlan'] = None
1297 iface
['mac'] = port
['mac']
1298 iface
['switch_port'] = port
['switch_port']
1299 # print '\t\t\t\t Dedicated port found '+str(port['port_id'])
1303 #if all ports have been checked and no match has been found
1304 #this is not a valid numa
1306 # print '\t\t\t\t\tAll ports have been checked and no match has been found for numa '+str(numa_id)+'\n\n'
1307 physical_ports_found
= False
1310 #if there is no match continue checking the following numa
1311 if not physical_ports_found
:
1314 #Try to allocate SR-IOVs
1315 sriov_ports_found
= True
1316 for iface
in requirements
['numa']['sriov_list']:
1317 # print '\t\tchecking iface: '+str(iface)
1319 for port
in available_ports
:
1320 # print '\t\t\tfor port: '+str(port)
1321 #If there are not available SR-IOVs continue
1322 if port
['availableSRIOV'] - port
['SRIOV_reserved'] <= 0:
1323 # print '\t\t\t\t Not enough SR-IOV'
1325 #If the port free speed is not enough continue
1326 if port
['Mbps_free'] - port
['Mbps_reserved'] < iface
['bandwidth']:
1327 # print '\t\t\t\t Not enough speed'
1330 #Otherwise this is a valid port
1331 port
['Mbps_reserved'] += iface
['bandwidth']
1332 port
['SRIOV_reserved'] += 1
1333 # print '\t\t\t\t SR-IOV found '+str(port['port_id'])
1334 iface
['port_id'] = port
['port_id']
1335 iface
['vlan'] = None
1336 iface
['mac'] = port
['mac']
1337 iface
['switch_port'] = port
['switch_port']
1341 #if all ports have been checked and no match has been found
1342 #this is not a valid numa
1344 # print '\t\t\t\t\tAll ports have been checked and no match has been found for numa '+str(numa_id)+'\n\n'
1345 sriov_ports_found
= False
1348 #if there is no match continue checking the following numa
1349 if not sriov_ports_found
:
1353 if sriov_ports_found
and physical_ports_found
:
1358 error_text
= 'No room at data center. Cannot find a host with the required hugepages, vcpus and interfaces'
1359 #self.logger.debug(error_text)
1360 return -1, error_text
1362 #self.logger.debug('Full match found in numa %s', str(numa_id))
1364 for numa
in valid_for_processor
:
1365 if numa_id
==numa
['numa_id']:
1366 host_id
=numa
['host_id']
1368 return 0, {'numa_id':numa_id
, 'host_id': host_id
, }
1369 except (mdb
.Error
, AttributeError) as e
:
1370 r
,c
= self
.format_error(e
, "get_numas", cmd
)
1371 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1373 def new_instance(self
, instance_dict
, nets
, ports_to_free
):
1374 for retry_
in range(0,2):
1378 self
.cur
= self
.con
.cursor()
1380 #create uuid if not provided
1381 if 'uuid' not in instance_dict
:
1382 uuid
= instance_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
1383 else: #check uuid is valid
1384 uuid
= str(instance_dict
['uuid'])
1388 cmd
= "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'instances')" % (uuid
, uuid
)
1389 self
.logger
.debug(cmd
)
1390 self
.cur
.execute(cmd
)
1392 #insert in table instance
1393 extended
= instance_dict
.pop('extended', None);
1394 bridgedifaces
= instance_dict
.pop('bridged-ifaces', () );
1396 keys
= ",".join(instance_dict
.keys())
1397 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", instance_dict
.values() ) )
1398 cmd
= "INSERT INTO instances (" + keys
+ ") VALUES (" + values
+ ")"
1399 self
.logger
.debug(cmd
)
1400 self
.cur
.execute(cmd
)
1401 #if result != 1: return -1, "Database Error while inserting at instances table"
1404 nb_bridge_ifaces
= nb_cores
= nb_ifaces
= nb_numas
= 0
1405 #insert bridged_ifaces
1407 for iface
in bridgedifaces
:
1408 #generate and insert a iface uuid
1409 if 'enable_dhcp' in iface
and iface
['enable_dhcp']:
1410 dhcp_first_ip
= iface
["dhcp_first_ip"]
1411 del iface
["dhcp_first_ip"]
1412 dhcp_last_ip
= iface
["dhcp_last_ip"]
1413 del iface
["dhcp_last_ip"]
1414 dhcp_cidr
= iface
["cidr"]
1416 del iface
["enable_dhcp"]
1417 used_dhcp_ips
= self
._get
_dhcp
_ip
_used
_list
(iface
["net_id"])
1418 iface
["ip_address"] = self
.get_free_ip_from_range(dhcp_first_ip
, dhcp_last_ip
,
1419 dhcp_cidr
, used_dhcp_ips
)
1421 iface
['uuid'] = str(myUuid
.uuid1()) # create_uuid
1422 cmd
= "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'ports')" % (iface
['uuid'], uuid
)
1423 self
.logger
.debug(cmd
)
1424 self
.cur
.execute(cmd
)
1426 iface
['instance_id'] = uuid
1427 # iface['type'] = 'instance:bridge'
1428 if 'name' not in iface
: iface
['name']="br"+str(nb_bridge_ifaces
)
1429 iface
['Mbps']=iface
.pop('bandwidth', None)
1430 if 'mac_address' not in iface
:
1431 iface
['mac'] = af
.gen_random_mac()
1433 iface
['mac'] = iface
['mac_address']
1434 del iface
['mac_address']
1435 #iface['mac']=iface.pop('mac_address', None) #for leaving mac generation to libvirt
1436 keys
= ",".join(iface
.keys())
1437 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", iface
.values() ) )
1438 cmd
= "INSERT INTO ports (" + keys
+ ") VALUES (" + values
+ ")"
1439 self
.logger
.debug(cmd
)
1440 self
.cur
.execute(cmd
)
1441 nb_bridge_ifaces
+= 1
1443 if extended
is not None:
1444 if 'numas' not in extended
or extended
['numas'] is None: extended
['numas'] = ()
1445 for numa
in extended
['numas']:
1448 if 'cores' not in numa
or numa
['cores'] is None: numa
['cores'] = ()
1449 for core
in numa
['cores']:
1451 cmd
= "UPDATE resources_core SET instance_id='%s'%s%s WHERE id='%s'" \
1453 (",v_thread_id='" + str(core
['vthread']) + "'") if 'vthread' in core
else '', \
1454 (",paired='" + core
['paired'] + "'") if 'paired' in core
else '', \
1456 self
.logger
.debug(cmd
)
1457 self
.cur
.execute(cmd
)
1459 if 'interfaces' not in numa
or numa
['interfaces'] is None: numa
['interfaces'] = ()
1460 for iface
in numa
['interfaces']:
1461 #generate and insert an uuid; iface[id]=iface_uuid; iface[uuid]= net_id
1462 iface
['id'] = str(myUuid
.uuid1()) # create_uuid
1463 cmd
= "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'ports')" % (iface
['id'], uuid
)
1464 self
.logger
.debug(cmd
)
1465 self
.cur
.execute(cmd
)
1467 mbps_
=("'"+str(iface
['Mbps_used'])+"'") if 'Mbps_used' in iface
and iface
['Mbps_used'] is not None else "Mbps"
1468 if iface
["dedicated"]=="yes":
1470 elif iface
["dedicated"]=="yes:sriov":
1471 iface_model
="VFnotShared"
1472 elif iface
["dedicated"]=="no":
1475 INSERT
=(iface
['mac_address'], iface
['switch_port'], iface
.get('vlan',None), 'instance:data', iface
['Mbps_used'], iface
['id'],
1476 uuid
, instance_dict
['tenant_id'], iface
.get('name',None), iface
.get('vpci',None), iface
.get('uuid',None), iface_model
)
1477 cmd
= "INSERT INTO ports (mac,switch_port,vlan,type,Mbps,uuid,instance_id,tenant_id,name,vpci,net_id, model) " + \
1478 " VALUES (" + ",".join(map(lambda x
: 'Null' if x
is None else "'"+str(x
)+"'", INSERT
)) + ")"
1479 self
.logger
.debug(cmd
)
1480 self
.cur
.execute(cmd
)
1482 nets
.append(iface
['uuid'])
1484 #discover if this port is not used by anyone
1485 cmd
= "SELECT source_name, mac FROM ( SELECT root_id, count(instance_id) as used FROM resources_port" \
1486 " WHERE root_id=(SELECT root_id from resources_port WHERE id='%s')"\
1487 " GROUP BY root_id ) AS A JOIN resources_port as B ON A.root_id=B.id AND A.used=0" % iface
['port_id']
1488 self
.logger
.debug(cmd
)
1489 self
.cur
.execute(cmd
)
1490 ports_to_free
+= self
.cur
.fetchall()
1492 cmd
= "UPDATE resources_port SET instance_id='%s', port_id='%s',Mbps_used=%s WHERE id='%s'" \
1493 % (uuid
, iface
['id'], mbps_
, iface
['port_id'])
1494 #if Mbps_used not suply, set the same value of 'Mpbs', that is the total
1495 self
.logger
.debug(cmd
)
1496 self
.cur
.execute(cmd
)
1498 if 'memory' in numa
and numa
['memory'] is not None and numa
['memory']>0:
1499 cmd
= "INSERT INTO resources_mem (numa_id, instance_id, consumed) VALUES ('%s','%s','%s')" % (numa
['numa_id'], uuid
, numa
['memory'])
1500 self
.logger
.debug(cmd
)
1501 self
.cur
.execute(cmd
)
1502 if 'devices' not in extended
or extended
['devices'] is None: extended
['devices'] = ()
1503 for device
in extended
['devices']:
1504 if 'vpci' in device
: vpci
= "'" + device
['vpci'] + "'"
1506 if 'image_id' in device
: image_id
= "'" + device
['image_id'] + "'"
1507 else: image_id
= 'Null'
1508 if 'xml' in device
: xml
= "'" + device
['xml'] + "'"
1510 if 'dev' in device
: dev
= "'" + device
['dev'] + "'"
1512 cmd
= "INSERT INTO instance_devices (type, instance_id, image_id, vpci, xml, dev) VALUES ('%s','%s', %s, %s, %s, %s)" % \
1513 (device
['type'], uuid
, image_id
, vpci
, xml
, dev
)
1514 self
.logger
.debug(cmd
)
1515 self
.cur
.execute(cmd
)
1517 #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)
1518 #self.logger.debug(cmd)
1519 #self.cur.execute(cmd)
1523 except (mdb
.Error
, AttributeError) as e
:
1524 r
,c
= self
.format_error(e
, "new_instance", cmd
)
1525 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1527 def get_free_ip_from_range(self
, first_ip
, last_ip
, cidr
, ip_used_list
):
1529 Calculate a free IP from a range given
1530 :param first_ip: First dhcp ip range
1531 :param last_ip: Last dhcp ip range
1532 :param cidr: net cidr
1533 :param ip_used_list: contain all used ips to avoid ip collisions
1537 ip_tools
= IPNetwork(cidr
)
1538 cidr_len
= ip_tools
.prefixlen
1539 ips
= IPNetwork(first_ip
+ '/' + str(cidr_len
))
1540 ip_used_list
.append(str(ips
[0])) # first ip
1541 ip_used_list
.append(str(ips
[1])) # gw ip
1542 ip_used_list
.append(str(ips
[-1])) # broadcast ip
1544 if str(vm_ip
) not in ip_used_list
:
1549 def _get_dhcp_ip_used_list(self
, net_id
):
1551 REtreive from DB all ips already used by the dhcp server for a given net
1555 WHERE
={'type': 'instance:ovs', 'net_id': net_id
}
1556 for retry_
in range(0, 2):
1558 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1559 select_
= "SELECT uuid, ip_address FROM ports "
1561 if WHERE
is None or len(WHERE
) == 0:
1564 where_
= "WHERE " + " AND ".join(
1565 map(lambda x
: str(x
) + (" is Null" if WHERE
[x
] is None else "='" + str(WHERE
[x
]) + "'"),
1567 limit_
= "LIMIT 100"
1568 cmd
= " ".join((select_
, where_
, limit_
))
1569 self
.logger
.debug(cmd
)
1570 self
.cur
.execute(cmd
)
1571 ports
= self
.cur
.fetchall()
1572 ip_address_list
= []
1574 ip_address_list
.append(port
['ip_address'])
1576 return ip_address_list
1579 def delete_instance(self
, instance_id
, tenant_id
, net_dataplane_list
, ports_to_free
, net_ovs_list
, logcause
="requested by http"):
1580 for retry_
in range(0,2):
1584 self
.cur
= self
.con
.cursor()
1586 cmd
= "SELECT uuid FROM instances WHERE uuid='%s' AND tenant_id='%s'" % (instance_id
, tenant_id
)
1587 self
.logger
.debug(cmd
)
1588 self
.cur
.execute(cmd
)
1589 if self
.cur
.rowcount
== 0 : return 0, "instance %s not found in tenant %s" % (instance_id
, tenant_id
)
1591 #delete bridged ifaces, instace_devices, resources_mem; done by database: it is automatic by Database; FOREIGN KEY DELETE CASCADE
1594 cmd
= "SELECT DISTINCT net_id from ports WHERE instance_id = '%s' AND net_id is not Null AND type='instance:data'" % instance_id
1595 self
.logger
.debug(cmd
)
1596 self
.cur
.execute(cmd
)
1597 net_list__
= self
.cur
.fetchall()
1598 for net
in net_list__
:
1599 net_dataplane_list
.append(net
[0])
1601 # get ovs manangement nets
1602 cmd
= "SELECT DISTINCT net_id, vlan, ip_address, mac FROM ports WHERE instance_id='{}' AND net_id is not Null AND "\
1603 "type='instance:ovs'".format(instance_id
)
1604 self
.logger
.debug(cmd
)
1605 self
.cur
.execute(cmd
)
1606 net_ovs_list
+= self
.cur
.fetchall()
1608 #get dataplane interfaces releases by this VM; both PF and VF with no other VF
1609 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 \
1610 + " 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"\
1611 + " JOIN resources_port as C ON A.root_id=C.id"
1612 # cmd = "SELECT DISTINCT root_id FROM resources_port WHERE instance_id = '%s'" % instance_id
1613 self
.logger
.debug(cmd
)
1614 self
.cur
.execute(cmd
)
1615 ports_to_free
+= self
.cur
.fetchall()
1617 #update resources port
1618 cmd
= "UPDATE resources_port SET instance_id=Null, port_id=Null, Mbps_used='0' WHERE instance_id = '%s'" % instance_id
1619 self
.logger
.debug(cmd
)
1620 self
.cur
.execute(cmd
)
1622 # #filter dataplane ports used by this VM that now are free
1623 # for port in ports_list__:
1624 # cmd = "SELECT mac, count(instance_id) FROM resources_port WHERE root_id = '%s'" % port[0]
1625 # self.logger.debug(cmd)
1626 # self.cur.execute(cmd)
1627 # mac_list__ = self.cur.fetchone()
1628 # if mac_list__ and mac_list__[1]==0:
1629 # ports_to_free.append(mac_list__[0])
1632 #update resources core
1633 cmd
= "UPDATE resources_core SET instance_id=Null, v_thread_id=Null, paired='N' WHERE instance_id = '%s'" % instance_id
1634 self
.logger
.debug(cmd
)
1635 self
.cur
.execute(cmd
)
1637 #delete all related uuids
1638 cmd
= "DELETE FROM uuids WHERE root_uuid='%s'" % instance_id
1639 self
.logger
.debug(cmd
)
1640 self
.cur
.execute(cmd
)
1643 #cmd = "INSERT INTO logs (related,level,uuid,description) VALUES ('instances','debug','%s','delete instance %s')" % (instance_id, logcause)
1644 #self.logger.debug(cmd)
1645 #self.cur.execute(cmd)
1648 cmd
= "DELETE FROM instances WHERE uuid='%s' AND tenant_id='%s'" % (instance_id
, tenant_id
)
1649 self
.cur
.execute(cmd
)
1650 return 1, "instance %s from tenant %s DELETED" % (instance_id
, tenant_id
)
1652 except (mdb
.Error
, AttributeError) as e
:
1653 r
,c
= self
.format_error(e
, "delete_instance", cmd
)
1654 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1656 def get_ports(self
, WHERE
):
1657 ''' Obtain ports using the WHERE filtering.
1659 'where_': dict of key:values, translated to key=value AND ... (Optional)
1660 Return: a list with dictionarys at each row
1662 for retry_
in range(0,2):
1667 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1668 select_
= "SELECT uuid,'ACTIVE' as status,admin_state_up,name,net_id,\
1669 tenant_id,type,mac,vlan,switch_port,instance_id,Mbps FROM ports "
1671 if WHERE
is None or len(WHERE
) == 0: where_
= ""
1673 where_
= "WHERE " + " AND ".join(map( lambda x
: str(x
) + (" is Null" if WHERE
[x
] is None else "='"+str(WHERE
[x
])+"'"), WHERE
.keys()) )
1674 limit_
= "LIMIT 100"
1675 cmd
= " ".join( (select_
, where_
, limit_
) )
1676 # print "SELECT multiple de instance_ifaces, iface_uuid, external_ports" #print cmd
1677 self
.logger
.debug(cmd
)
1678 self
.cur
.execute(cmd
)
1679 ports
= self
.cur
.fetchall()
1680 if self
.cur
.rowcount
>0: af
.DeleteNone(ports
)
1681 return self
.cur
.rowcount
, ports
1682 # return self.get_table(FROM=from_, SELECT=select_,WHERE=where_,LIMIT=100)
1683 except (mdb
.Error
, AttributeError) as e
:
1684 r
,c
= self
.format_error(e
, "get_ports", cmd
)
1685 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1687 def check_target_net(self
, net_id
, tenant_id
, port_type
):
1688 '''check if valid attachement of a port into a target net
1690 net_id: target net uuid
1691 tenant_id: client where tenant belongs. Not used in this version
1692 port_type: string with the option 'instance:bridge', 'instance:data', 'external'
1694 (0,net_dict) if ok, where net_dict contain 'uuid','type','vlan', ...
1695 (negative,string-error) if error
1697 for retry_
in range(0,2):
1701 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1702 cmd
= "SELECT * FROM nets WHERE uuid='%s'" % net_id
1703 self
.logger
.debug(cmd
)
1704 self
.cur
.execute(cmd
)
1705 if self
.cur
.rowcount
== 0 : return -1, "network_id %s does not match any net" % net_id
1706 net
= self
.cur
.fetchone()
1709 except (mdb
.Error
, AttributeError) as e
:
1710 r
,c
= self
.format_error(e
, "check_target_net", cmd
)
1711 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1713 if tenant_id
is not None and tenant_id
is not "admin":
1714 if net
['tenant_id']==tenant_id
and net
['shared']=='false':
1715 return -1, "needed admin privileges to attach to the net %s" % net_id
1717 if (net
['type'] in ('ptp','data') and port_type
not in ('instance:data','external')) or \
1718 (net
['type'] in ('bridge_data','bridge_man') and port_type
not in ('instance:bridge', 'instance:ovs')):
1719 return -1, "Cannot attach a port of type %s into a net of type %s" % (port_type
, net
['type'])
1720 if net
['type'] == 'ptp':
1722 nb_ports
, data
= self
.get_ports( {'net_id':net_id
} )
1729 return -1, "net of type p2p already contain two ports attached. No room for another"
1733 if __name__
== "__main__":