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
41 HTTP_Bad_Request
= 400
42 HTTP_Unauthorized
= 401
44 HTTP_Method_Not_Allowed
= 405
45 HTTP_Request_Timeout
= 408
47 HTTP_Service_Unavailable
= 503
48 HTTP_Internal_Server_Error
= 500
52 def __init__(self
, vlan_range
, debug
="ERROR"):
53 '''vlan_range must be a tuple (vlan_ini, vlan_end) with available vlan values for networks
54 every dataplane network contain a unique value, regardless of it is used or not
57 self
.net_vlan_range
= vlan_range
58 self
.net_vlan_usedlist
= None
59 self
.net_vlan_lastused
= self
.net_vlan_range
[0] -1
61 self
.logger
= logging
.getLogger('vim.db')
62 self
.logger
.setLevel( getattr(logging
, debug
) )
65 def connect(self
, host
=None, user
=None, passwd
=None, database
=None):
66 '''Connect to the concrete data base.
67 The first time a valid host, user, passwd and database must be provided,
68 Following calls can skip this parameters
71 if host
is not None: self
.host
= host
72 if user
is not None: self
.user
= user
73 if passwd
is not None: self
.passwd
= passwd
74 if database
is not None: self
.database
= database
76 self
.con
= mdb
.connect(self
.host
, self
.user
, self
.passwd
, self
.database
)
77 self
.logger
.debug("connected to DB %s at %s@%s", self
.database
,self
.user
, self
.host
)
79 except mdb
.Error
as e
:
80 self
.logger
.error("Cannot connect to DB %s at %s@%s Error %d: %s", self
.database
, self
.user
, self
.host
, e
.args
[0], e
.args
[1])
83 def get_db_version(self
):
84 ''' Obtain the database schema version.
85 Return: (negative, text) if error or version 0.0 where schema_version table is missing
86 (version_int, version_text) if ok
88 cmd
= "SELECT version_int,version,openvim_ver FROM schema_version"
89 for retry_
in range(0,2):
92 self
.cur
= self
.con
.cursor()
93 self
.logger
.debug(cmd
)
95 rows
= self
.cur
.fetchall()
99 for row
in rows
: #look for the latest version
100 if row
[0]>highest_version_int
:
101 highest_version_int
, highest_version
= row
[0:2]
102 return highest_version_int
, highest_version
103 except (mdb
.Error
, AttributeError) as e
:
104 self
.logger
.error("get_db_version DB Exception %d: %s. Command %s",e
.args
[0], e
.args
[1], cmd
)
105 r
,c
= self
.format_error(e
)
106 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
108 def disconnect(self
):
109 '''disconnect from the data base'''
113 except mdb
.Error
as e
:
114 self
.logger
.error("while disconnecting from DB: Error %d: %s",e
.args
[0], e
.args
[1])
116 except AttributeError as e
: #self.con not defined
117 if e
[0][-5:] == "'con'": return -1, "Database internal error, no connection."
120 def format_error(self
, e
, func
, cmd
, command
=None, extra
=None):
121 '''Creates a text error base on the produced exception
124 func: name of the function that makes the call, for logging purposes
125 cmd: database command that produce the exception
126 command: if the intention is update or delete
127 extra: extra information to add to some commands
129 HTTP error in negative, formatted error text
132 self
.logger
.error("%s DB Exception %s. Command %s",func
, str(e
), cmd
)
133 if type(e
[0]) is str:
134 if e
[0][-5:] == "'con'": return -HTTP_Internal_Server_Error
, "DB Exception, no connection."
136 if e
.args
[0]==2006 or e
.args
[0]==2013 : #MySQL server has gone away (((or))) Exception 2013: Lost connection to MySQL server during query
139 return -HTTP_Request_Timeout
,"Database reconnection. Try Again"
140 fk
=e
.args
[1].find("foreign key constraint fails")
142 if command
=="update": return -HTTP_Bad_Request
, "tenant_id %s not found." % extra
143 elif command
=="delete": return -HTTP_Bad_Request
, "Resource is not free. There are %s that prevent its deletion." % extra
144 de
= e
.args
[1].find("Duplicate entry")
145 fk
= e
.args
[1].find("for key")
146 uk
= e
.args
[1].find("Unknown column")
147 wc
= e
.args
[1].find("in 'where clause'")
148 fl
= e
.args
[1].find("in 'field list'")
149 #print de, fk, uk, wc,fl
151 if fk
>=0: #error 1062
152 return -HTTP_Conflict
, "Value %s already in use for %s" % (e
.args
[1][de
+15:fk
], e
.args
[1][fk
+7:])
155 return -HTTP_Bad_Request
, "Field %s can not be used for filtering" % e
.args
[1][uk
+14:wc
]
157 return -HTTP_Bad_Request
, "Field %s does not exist" % e
.args
[1][uk
+14:wc
]
158 return -HTTP_Internal_Server_Error
, "Database internal Error %d: %s" % (e
.args
[0], e
.args
[1])
160 def __data2db_format(self
, data
):
161 '''convert data to database format. If data is None it return the 'Null' text,
162 otherwise it return the text surrounded by quotes ensuring internal quotes are escaped'''
167 return "'" + out
+ "'"
169 return '"' + out
+ '"'
171 return json
.dumps(out
)
173 def __get_used_net_vlan(self
):
174 #get used from database if needed
176 cmd
= "SELECT vlan FROM nets WHERE vlan>='%s' and (type='ptp' or type='data') ORDER BY vlan LIMIT 25" % self
.net_vlan_lastused
178 self
.cur
= self
.con
.cursor()
179 self
.logger
.debug(cmd
)
180 self
.cur
.execute(cmd
)
181 vlan_tuple
= self
.cur
.fetchall()
182 #convert a tuple of tuples in a list of numbers
183 self
.net_vlan_usedlist
= []
185 self
.net_vlan_usedlist
.append(k
[0])
187 except (mdb
.Error
, AttributeError) as e
:
188 return self
.format_error(e
, "get_free_net_vlan", cmd
)
190 def get_free_net_vlan(self
):
191 '''obtain a vlan not used in any net'''
194 self
.logger
.debug("net_vlan_lastused:%d net_vlan_range:%d-%d net_vlan_usedlist:%s",
195 self
.net_vlan_lastused
, self
.net_vlan_range
[0], self
.net_vlan_range
[1], str(self
.net_vlan_usedlist
))
196 self
.net_vlan_lastused
+= 1
197 if self
.net_vlan_lastused
== self
.net_vlan_range
[1]:
198 #start from the begining
199 self
.net_vlan_lastused
= self
.net_vlan_range
[0]
200 self
.net_vlan_usedlist
= None
201 if self
.net_vlan_usedlist
is None \
202 or (len(self
.net_vlan_usedlist
)>0 and self
.net_vlan_lastused
>= self
.net_vlan_usedlist
[-1] and len(self
.net_vlan_usedlist
)==25):
203 r
= self
.__get
_used
_net
_vlan
()
205 self
.logger
.debug("new net_vlan_usedlist %s", str(self
.net_vlan_usedlist
))
206 if self
.net_vlan_lastused
in self
.net_vlan_usedlist
:
209 return self
.net_vlan_lastused
211 def get_table(self
, **sql_dict
):
212 ''' Obtain rows from a table.
213 Atribure sql_dir: dictionary with the following key: value
214 'SELECT': [list of fields to retrieve] (by default all)
215 'FROM': string of table name (Mandatory)
216 'WHERE': dict of key:values, translated to key=value AND ... (Optional)
217 'WHERE_NOT': dict of key:values, translated to key!=value AND ... (Optional)
218 'WHERE_OR': dict of key:values, translated to key=value OR ... (Optional)
219 'WHERE_AND_OR: str 'AND' or 'OR'(by default) mark the priority to 'WHERE AND (WHERE_OR)' or (WHERE) OR WHERE_OR' (Optional)
220 'LIMIT': limit of number of rows (Optional)
221 Return: a list with dictionarys at each row
224 select_
= "SELECT " + ("*" if 'SELECT' not in sql_dict
else ",".join(map(str,sql_dict
['SELECT'])) )
225 #print 'select_', select_
226 from_
= "FROM " + str(sql_dict
['FROM'])
227 #print 'from_', from_
231 w
= sql_dict
.get('WHERE')
233 where_and
= " AND ".join(map( lambda x
: str(x
) + (" is Null" if w
[x
] is None else "='"+str(w
[x
])+"'"), w
.keys()) )
234 w
= sql_dict
.get('WHERE_NOT')
236 where_and_not
= " AND ".join(map( lambda x
: str(x
) + (" is not Null" if w
[x
] is None else "!='"+str(w
[x
])+"'"), w
.keys()) )
238 where_and
+= " AND " + where_and_not
240 where_and
= where_and_not
241 w
= sql_dict
.get('WHERE_OR')
243 where_or
= " OR ".join(map( lambda x
: str(x
) + (" is Null" if w
[x
] is None else "='"+str(w
[x
])+"'"), w
.keys()) )
245 if where_and
!=None and where_or
!=None:
246 if sql_dict
.get("WHERE_AND_OR") == "AND":
247 where_
= "WHERE " + where_and
+ " AND (" + where_or
+ ")"
249 where_
= "WHERE (" + where_and
+ ") OR " + where_or
250 elif where_and
!=None and where_or
==None:
251 where_
= "WHERE " + where_and
252 elif where_and
==None and where_or
!=None:
253 where_
= "WHERE " + where_or
256 #print 'where_', where_
257 limit_
= "LIMIT " + str(sql_dict
['LIMIT']) if 'LIMIT' in sql_dict
else ""
258 #print 'limit_', limit_
259 cmd
= " ".join( (select_
, from_
, where_
, limit_
) )
260 for retry_
in range(0,2):
263 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
264 self
.logger
.debug(cmd
)
265 self
.cur
.execute(cmd
)
266 rows
= self
.cur
.fetchall()
267 return self
.cur
.rowcount
, rows
268 except (mdb
.Error
, AttributeError) as e
:
269 r
,c
= self
.format_error(e
, "get_table", cmd
)
270 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
272 def new_tenant(self
, tenant_dict
):
273 ''' Add one row into a table.
275 tenant_dict: dictionary with the key: value to insert
276 It checks presence of uuid and add one automatically otherwise
277 Return: (result, uuid) where result can be 0 if error, or 1 if ok
279 for retry_
in range(0,2):
283 #create uuid if not provided
284 if 'uuid' not in tenant_dict
:
285 uuid
= tenant_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
287 uuid
= str(tenant_dict
['uuid'])
288 #obtain tenant_id for logs
291 self
.cur
= self
.con
.cursor()
293 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','tenants')" % uuid
294 self
.logger
.debug(cmd
)
295 self
.cur
.execute(cmd
)
297 cmd
= "INSERT INTO tenants (" + \
298 ",".join(map(str, tenant_dict
.keys() )) + ") VALUES(" + \
299 ",".join(map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'",tenant_dict
.values() )) + ")"
300 self
.logger
.debug(cmd
)
301 self
.cur
.execute(cmd
)
302 inserted
= self
.cur
.rowcount
304 #del tenant_dict['uuid'] # not interested for the log
305 #cmd = "INSERT INTO logs (related,level,tenant_id,uuid,description) VALUES ('tenants','debug','%s','%s',\"new tenant %s\")" % (uuid, tenant_id, str(tenant_dict))
306 #self.logger.debug(cmd)
307 #self.cur.execute(cmd)
310 if inserted
== 0: return 0, uuid
312 self
.cur
= self
.con
.cursor()
313 #adding public flavors
314 cmd
= "INSERT INTO tenants_flavors(flavor_id,tenant_id) SELECT uuid as flavor_id,'"+ tenant_id
+ "' FROM flavors WHERE public = 'yes'"
315 self
.logger
.debug(cmd
)
316 self
.cur
.execute(cmd
)
317 self
.logger
.debug("attached public flavors: %s", str(self
.cur
.rowcount
))
318 #rows = self.cur.fetchall()
320 # cmd = "INSERT INTO tenants_flavors(flavor_id,tenant_id) VALUES('%s','%s')" % (row[0], tenant_id)
321 # self.cur.execute(cmd )
322 #adding public images
323 cmd
= "INSERT INTO tenants_images(image_id,tenant_id) SELECT uuid as image_id,'"+ tenant_id
+ "' FROM images WHERE public = 'yes'"
324 self
.logger
.debug(cmd
)
325 self
.cur
.execute(cmd
)
326 self
.logger
.debug("attached public images: %s", str(self
.cur
.rowcount
))
328 except (mdb
.Error
, AttributeError) as e
:
330 self
.logger
.warning("new_tenant DB Exception %d: %s. Command %s",e
.args
[0], e
.args
[1], cmd
)
333 r
,c
= self
.format_error(e
, "new_tenant", cmd
)
334 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
336 def new_row(self
, table
, INSERT
, add_uuid
=False, log
=False):
337 ''' Add one row into a table.
339 INSERT: dictionary with the key: value to insert
340 table: table where to insert
341 add_uuid: if True, it will crated an uuid key entry at INSERT if not provided
342 It checks presence of uuid and add one automatically otherwise
343 Return: (result, uuid) where result can be 0 if error, or 1 if ok
345 for retry_
in range(0,2):
349 #create uuid if not provided
350 if 'uuid' not in INSERT
:
351 uuid
= INSERT
['uuid'] = str(myUuid
.uuid1()) # create_uuid
353 uuid
= str(INSERT
['uuid'])
357 self
.cur
= self
.con
.cursor()
360 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','%s')" % (uuid
, table
)
361 self
.logger
.debug(cmd
)
362 self
.cur
.execute(cmd
)
364 cmd
= "INSERT INTO " + table
+" (" + \
365 ",".join(map(str, INSERT
.keys() )) + ") VALUES(" + \
366 ",".join(map(lambda x
: 'Null' if x
is None else "'"+str(x
)+"'", INSERT
.values() )) + ")"
367 self
.logger
.debug(cmd
)
368 self
.cur
.execute(cmd
)
369 nb_rows
= self
.cur
.rowcount
371 #if nb_rows > 0 and log:
372 # if add_uuid: del INSERT['uuid']
373 # #obtain tenant_id for logs
374 # if 'tenant_id' in INSERT:
375 # tenant_id = INSERT['tenant_id']
376 # del INSERT['tenant_id']
377 # elif table == 'tenants':
381 # if uuid is None: uuid_k = uuid_v = ""
382 # else: uuid_k=",uuid"; uuid_v=",'" + str(uuid) + "'"
383 # if tenant_id is None: tenant_k = tenant_v = ""
384 # else: tenant_k=",tenant_id"; tenant_v=",'" + str(tenant_id) + "'"
385 # cmd = "INSERT INTO logs (related,level%s%s,description) VALUES ('%s','debug'%s%s,\"new %s %s\")" \
386 # % (uuid_k, tenant_k, table, uuid_v, tenant_v, table[:-1], str(INSERT))
387 # self.logger.debug(cmd)
388 # self.cur.execute(cmd)
391 except (mdb
.Error
, AttributeError) as e
:
392 r
,c
= self
.format_error(e
, "new_row", cmd
)
393 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
395 def __remove_quotes(self
, data
):
396 '''remove single quotes ' of any string content of data dictionary'''
397 for k
,v
in data
.items():
400 data
[k
] = data
[k
].replace("'","_")
402 def _update_rows_internal(self
, table
, UPDATE
, WHERE
={}):
403 cmd
= "UPDATE " + table
+" SET " + \
404 ",".join(map(lambda x
: str(x
)+'='+ self
.__data
2db
_format
(UPDATE
[x
]), UPDATE
.keys() ));
406 cmd
+= " WHERE " + " and ".join(map(lambda x
: str(x
)+ (' is Null' if WHERE
[x
] is None else"='"+str(WHERE
[x
])+"'" ), WHERE
.keys() ))
407 self
.logger
.debug(cmd
)
408 self
.cur
.execute(cmd
)
409 nb_rows
= self
.cur
.rowcount
412 def update_rows(self
, table
, UPDATE
, WHERE
={}, log
=False):
413 ''' Update one or several rows into a table.
415 UPDATE: dictionary with the key-new_value pairs to change
416 table: table to be modified
417 WHERE: dictionary to filter target rows, key-value
418 log: if true, a log entry is added at logs table
419 Return: (result, None) where result indicates the number of updated files
421 for retry_
in range(0,2):
425 uuid
= WHERE
.get('uuid')
428 self
.cur
= self
.con
.cursor()
429 cmd
= "UPDATE " + table
+" SET " + \
430 ",".join(map(lambda x
: str(x
)+'='+ self
.__data
2db
_format
(UPDATE
[x
]), UPDATE
.keys() ));
432 cmd
+= " WHERE " + " and ".join(map(lambda x
: str(x
)+ (' is Null' if WHERE
[x
] is None else"='"+str(WHERE
[x
])+"'" ), WHERE
.keys() ))
433 self
.logger
.debug(cmd
)
434 self
.cur
.execute(cmd
)
435 nb_rows
= self
.cur
.rowcount
436 #if nb_rows > 0 and log:
438 # if uuid is None: uuid_k = uuid_v = ""
439 # else: uuid_k=",uuid"; uuid_v=",'" + str(uuid) + "'"
440 # cmd = "INSERT INTO logs (related,level%s,description) VALUES ('%s','debug'%s,\"updating %d entry %s\")" \
441 # % (uuid_k, table, uuid_v, nb_rows, (str(UPDATE)).replace('"','-') )
442 # self.logger.debug(cmd)
443 # self.cur.execute(cmd)
445 except (mdb
.Error
, AttributeError) as e
:
446 r
,c
= self
.format_error(e
, "update_rows", cmd
)
447 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
449 def get_host(self
, host_id
):
450 if af
.check_valid_uuid(host_id
):
451 where_filter
="uuid='" + host_id
+ "'"
453 where_filter
="name='" + host_id
+ "'"
454 for retry_
in range(0,2):
458 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
460 cmd
= "SELECT uuid, user, name, ip_name, description, ranking, admin_state_up, DATE_FORMAT(created_at,'%Y-%m-%dT%H:%i:%s') as created_at \
461 FROM hosts WHERE " + where_filter
462 self
.logger
.debug(cmd
)
463 self
.cur
.execute(cmd
)
464 if self
.cur
.rowcount
== 0 :
465 return 0, "host '" + str(host_id
) +"'not found."
466 elif self
.cur
.rowcount
> 1 :
467 return 0, "host '" + str(host_id
) +"' matches more than one result."
468 host
= self
.cur
.fetchone()
469 host_id
= host
['uuid']
471 cmd
= "SELECT id, numa_socket, hugepages, memory, admin_state_up FROM numas WHERE host_id = '" + str(host_id
) + "'"
472 self
.logger
.debug(cmd
)
473 self
.cur
.execute(cmd
)
474 host
['numas'] = self
.cur
.fetchall()
475 for numa
in host
['numas']:
476 #print "SELECT core_id, instance_id, status, thread_id, v_thread_id FROM resources_core WHERE numa_id = '" + str(numa['id']) + "'"
478 cmd
= "SELECT core_id, instance_id, status, thread_id, v_thread_id FROM resources_core WHERE numa_id = '" + str(numa
['id']) + "'"
479 self
.logger
.debug(cmd
)
480 self
.cur
.execute(cmd
)
481 numa
['cores'] = self
.cur
.fetchall()
482 for core
in numa
['cores']:
483 if core
['instance_id'] == None: del core
['instance_id'], core
['v_thread_id']
484 if core
['status'] == 'ok': del core
['status']
486 cmd
= "SELECT sum(consumed) as hugepages_consumed FROM resources_mem WHERE numa_id = '" + str(numa
['id']) + "' GROUP BY numa_id"
487 self
.logger
.debug(cmd
)
488 self
.cur
.execute(cmd
)
489 used
= self
.cur
.fetchone()
490 used_
= int(used
['hugepages_consumed']) if used
!= None else 0
491 numa
['hugepages_consumed'] = used_
493 #cmd = "CALL GetPortsFromNuma(%s)'" % str(numa['id'])
494 #self.cur.callproc('GetPortsFromNuma', (numa['id'],) )
495 #every time a Procedure is launched you need to close and open the cursor
496 #under Error 2014: Commands out of sync; you can't run this command now
498 #self.cur = self.con.cursor(mdb.cursors.DictCursor)
499 cmd
="SELECT Mbps, pci, status, Mbps_used, instance_id, if(id=root_id,'PF','VF') as type_,\
500 switch_port, switch_dpid, mac, source_name\
501 FROM resources_port WHERE numa_id=%d ORDER BY root_id, type_ DESC" % (numa
['id'])
502 self
.logger
.debug(cmd
)
503 self
.cur
.execute(cmd
)
504 ifaces
= self
.cur
.fetchall()
505 #The SQL query will ensure to have SRIOV interfaces from a port first
508 numa
['interfaces'] = []
510 if not iface
["instance_id"]:
511 del iface
["instance_id"]
512 if iface
['status'] == 'ok':
514 Mpbs_consumed
+= int(iface
["Mbps_used"])
515 del iface
["Mbps_used"]
516 if iface
["type_"]=='PF':
517 if not iface
["switch_dpid"]:
518 del iface
["switch_dpid"]
519 if not iface
["switch_port"]:
520 del iface
["switch_port"]
522 iface
["sriovs"] = sriovs
524 iface
["Mpbs_consumed"] = Mpbs_consumed
526 numa
['interfaces'].append(iface
)
530 del iface
["switch_port"]
531 del iface
["switch_dpid"]
536 #delete internal field
539 except (mdb
.Error
, AttributeError) as e
:
540 r
,c
= self
.format_error(e
, "get_host", cmd
)
541 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
546 uuid
= str( myUuid
.uuid1() )
547 if self
.check_uuid(uuid
)[0] == 0:
552 def check_uuid(self
, uuid
):
553 '''check in the database if this uuid is already present'''
555 cmd
= "SELECT * FROM uuids where uuid='" + str(uuid
) + "'"
557 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
558 self
.logger
.debug(cmd
)
559 self
.cur
.execute(cmd
)
560 rows
= self
.cur
.fetchall()
561 return self
.cur
.rowcount
, rows
562 except (mdb
.Error
, AttributeError) as e
:
563 return self
.format_error(e
, "check_uuid", cmd
)
565 def __get_next_ids(self
):
566 '''get next auto increment index of all table in the database'''
567 self
.cur
.execute("SELECT table_name,AUTO_INCREMENT FROM information_schema.tables WHERE AUTO_INCREMENT IS NOT NULL AND table_schema = DATABASE()")
568 rows
= self
.cur
.fetchall()
569 return self
.cur
.rowcount
, dict(rows
)
571 def edit_host(self
, host_id
, host_dict
):
573 for retry_
in range(0,2):
577 self
.cur
= self
.con
.cursor()
580 numa_list
= host_dict
.pop('numas', () )
582 self
._update
_rows
_internal
("hosts", host_dict
, {"uuid": host_id
})
584 where
= {"host_id": host_id
}
585 for numa_dict
in numa_list
:
586 where
["numa_socket"] = str(numa_dict
.pop('numa_socket'))
587 interface_list
= numa_dict
.pop('interfaces', () )
589 self
._update
_rows
_internal
("numas", numa_dict
, where
)
590 for interface
in interface_list
:
591 source_name
= str(interface
.pop("source_name") )
593 #get interface id from resources_port
594 cmd
= "SELECT rp.id as id FROM resources_port as rp join numas as n on n.id=rp.numa_id join hosts as h on h.uuid=n.host_id " +\
595 "WHERE host_id='%s' and rp.source_name='%s'" %(host_id
, source_name
)
596 self
.logger
.debug(cmd
)
597 self
.cur
.execute(cmd
)
598 row
= self
.cur
.fetchone()
599 if self
.cur
.rowcount
<=0:
600 return -HTTP_Bad_Request
, "Interface source_name='%s' from numa_socket='%s' not found" % (source_name
, str(where
["numa_socket"]))
601 interface_id
= row
[0]
602 self
._update
_rows
_internal
("resources_port", interface
, {"root_id": interface_id
})
603 return self
.get_host(host_id
)
604 except (mdb
.Error
, AttributeError) as e
:
605 r
,c
= self
.format_error(e
, "edit_host", cmd
)
606 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
608 def new_host(self
, host_dict
):
610 for retry_
in range(0,2):
614 self
.cur
= self
.con
.cursor()
616 result
, next_ids
= self
.__get
_next
_ids
()
617 #print "next_ids: " + str(next_ids)
618 if result
<= 0: return result
, "Internal DataBase error getting next id of tables"
620 #create uuid if not provided
621 if 'uuid' not in host_dict
:
622 uuid
= host_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
623 else: #check uuid is valid
624 uuid
= str(host_dict
['uuid'])
625 # result, data = self.check_uuid(uuid)
627 # return -1, "UUID '%s' already in use" % uuid
630 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','hosts')" % uuid
631 self
.logger
.debug(cmd
)
632 result
= self
.cur
.execute(cmd
)
634 #insert in table host
635 numa_list
= host_dict
.pop('numas', [])
636 #get nonhupages and nonisolated cpus
639 for numa
in numa_list
:
640 mem_numa
= numa
.get('memory', 0) - numa
.get('hugepages',0)
642 host_dict
['RAM'] += mem_numa
643 for core
in numa
.get("cores", []):
644 if "status" in core
and core
["status"]=="noteligible":
646 host_dict
['RAM']*=1024 # from GB to MB
648 keys
= ",".join(host_dict
.keys())
649 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", host_dict
.values() ) )
650 cmd
= "INSERT INTO hosts (" + keys
+ ") VALUES (" + values
+ ")"
651 self
.logger
.debug(cmd
)
652 result
= self
.cur
.execute(cmd
)
653 #if result != 1: return -1, "Database Error while inserting at hosts table"
656 nb_numas
= nb_cores
= nb_ifaces
= 0
657 for numa_dict
in numa_list
:
659 interface_list
= numa_dict
.pop('interfaces', [])
660 core_list
= numa_dict
.pop('cores', [])
661 numa_dict
['id'] = next_ids
['numas']; next_ids
['numas'] += 1
662 numa_dict
['host_id'] = uuid
663 keys
= ",".join(numa_dict
.keys())
664 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", numa_dict
.values() ) )
665 cmd
= "INSERT INTO numas (" + keys
+ ") VALUES (" + values
+ ")"
666 self
.logger
.debug(cmd
)
667 result
= self
.cur
.execute(cmd
)
670 for core_dict
in core_list
:
672 core_dict
['numa_id'] = numa_dict
['id']
673 keys
= ",".join(core_dict
.keys())
674 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", core_dict
.values() ) )
675 cmd
= "INSERT INTO resources_core (" + keys
+ ") VALUES (" + values
+ ")"
676 self
.logger
.debug(cmd
)
677 result
= self
.cur
.execute(cmd
)
680 for port_dict
in interface_list
:
682 sriov_list
= port_dict
.pop('sriovs', [])
683 port_dict
['numa_id'] = numa_dict
['id']
684 port_dict
['id'] = port_dict
['root_id'] = next_ids
['resources_port']
685 next_ids
['resources_port'] += 1
686 switch_port
= port_dict
.get('switch_port', None)
687 switch_dpid
= port_dict
.get('switch_dpid', None)
688 keys
= ",".join(port_dict
.keys())
689 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", port_dict
.values() ) )
690 cmd
= "INSERT INTO resources_port (" + keys
+ ") VALUES (" + values
+ ")"
691 self
.logger
.debug(cmd
)
692 result
= self
.cur
.execute(cmd
)
694 #insert sriovs into port table
695 for sriov_dict
in sriov_list
:
696 sriov_dict
['switch_port'] = switch_port
697 sriov_dict
['switch_dpid'] = switch_dpid
698 sriov_dict
['numa_id'] = port_dict
['numa_id']
699 sriov_dict
['Mbps'] = port_dict
['Mbps']
700 sriov_dict
['root_id'] = port_dict
['id']
701 sriov_dict
['id'] = next_ids
['resources_port']
702 if "vlan" in sriov_dict
:
703 del sriov_dict
["vlan"]
704 next_ids
['resources_port'] += 1
705 keys
= ",".join(sriov_dict
.keys())
706 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", sriov_dict
.values() ) )
707 cmd
= "INSERT INTO resources_port (" + keys
+ ") VALUES (" + values
+ ")"
708 self
.logger
.debug(cmd
)
709 result
= self
.cur
.execute(cmd
)
712 #cmd = "INSERT INTO logs (related,level,uuid,description) VALUES ('hosts','debug','%s','new host: %d numas, %d theads, %d ifaces')" % (uuid, nb_numas, nb_cores, nb_ifaces)
713 #self.logger.debug(cmd)
714 #result = self.cur.execute(cmd)
718 self
.cur
= self
.con
.cursor()
719 self
.logger
.debug("callproc('UpdateSwitchPort', () )")
720 self
.cur
.callproc('UpdateSwitchPort', () )
722 self
.logger
.debug("getting host '%s'",str(host_dict
['uuid']))
723 return self
.get_host(host_dict
['uuid'])
724 except (mdb
.Error
, AttributeError) as e
:
725 r
,c
= self
.format_error(e
, "new_host", cmd
)
726 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
728 def new_flavor(self
, flavor_dict
, tenant_id
):
729 '''Add new flavor into the database. Create uuid if not provided
731 flavor_dict: flavor dictionary with the key: value to insert. Must be valid flavors columns
732 tenant_id: if not 'any', it matches this flavor/tenant inserting at tenants_flavors table
733 Return: (result, data) where result can be
734 negative: error at inserting. data contain text
735 1, inserted, data contain inserted uuid flavor
737 for retry_
in range(0,2):
741 self
.cur
= self
.con
.cursor()
743 #create uuid if not provided
744 if 'uuid' not in flavor_dict
:
745 uuid
= flavor_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
746 else: #check uuid is valid
747 uuid
= str(flavor_dict
['uuid'])
748 # result, data = self.check_uuid(uuid)
750 # return -1, "UUID '%s' already in use" % uuid
753 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','flavors')" % uuid
754 self
.logger
.debug(cmd
)
755 self
.cur
.execute(cmd
)
757 #insert in table flavor
758 keys
= ",".join(flavor_dict
.keys())
759 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", flavor_dict
.values() ) )
760 cmd
= "INSERT INTO flavors (" + keys
+ ") VALUES (" + values
+ ")"
761 self
.logger
.debug(cmd
)
762 self
.cur
.execute(cmd
)
763 #if result != 1: return -1, "Database Error while inserting at flavors table"
765 #insert tenants_flavors
766 if tenant_id
!= 'any':
767 cmd
= "INSERT INTO tenants_flavors (tenant_id,flavor_id) VALUES ('%s','%s')" % (tenant_id
, uuid
)
768 self
.logger
.debug(cmd
)
769 self
.cur
.execute(cmd
)
772 #del flavor_dict['uuid']
773 #if 'extended' in flavor_dict: del flavor_dict['extended'] #remove two many information
774 #cmd = "INSERT INTO logs (related,level,uuid, tenant_id, description) VALUES ('flavors','debug','%s','%s',\"new flavor: %s\")" \
775 # % (uuid, tenant_id, str(flavor_dict))
776 #self.logger.debug(cmd)
777 #self.cur.execute(cmd)
781 except (mdb
.Error
, AttributeError) as e
:
782 r
,c
= self
.format_error(e
, "new_flavor", cmd
, "update", tenant_id
)
783 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
785 def new_image(self
, image_dict
, tenant_id
):
786 '''Add new image into the database. Create uuid if not provided
788 image_dict: image dictionary with the key: value to insert. Must be valid images columns
789 tenant_id: if not 'any', it matches this image/tenant inserting at tenants_images table
790 Return: (result, data) where result can be
791 negative: error at inserting. data contain text
792 1, inserted, data contain inserted uuid image
794 for retry_
in range(0,2):
798 self
.cur
= self
.con
.cursor()
800 #create uuid if not provided
801 if 'uuid' not in image_dict
:
802 uuid
= image_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
803 else: #check uuid is valid
804 uuid
= str(image_dict
['uuid'])
805 # result, data = self.check_uuid(uuid)
807 # return -1, "UUID '%s' already in use" % uuid
810 cmd
= "INSERT INTO uuids (uuid, used_at) VALUES ('%s','images')" % uuid
811 self
.logger
.debug(cmd
)
812 self
.cur
.execute(cmd
)
814 #insert in table image
815 keys
= ",".join(image_dict
.keys())
816 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", image_dict
.values() ) )
817 cmd
= "INSERT INTO images (" + keys
+ ") VALUES (" + values
+ ")"
818 self
.logger
.debug(cmd
)
819 self
.cur
.execute(cmd
)
820 #if result != 1: return -1, "Database Error while inserting at images table"
822 #insert tenants_images
823 if tenant_id
!= 'any':
824 cmd
= "INSERT INTO tenants_images (tenant_id,image_id) VALUES ('%s','%s')" % (tenant_id
, uuid
)
825 self
.logger
.debug(cmd
)
826 self
.cur
.execute(cmd
)
829 #cmd = "INSERT INTO logs (related,level,uuid, tenant_id, description) VALUES ('images','debug','%s','%s',\"new image: %s path: %s\")" % (uuid, tenant_id, image_dict['name'], image_dict['path'])
830 #self.logger.debug(cmd)
831 #self.cur.execute(cmd)
835 except (mdb
.Error
, AttributeError) as e
:
836 r
,c
= self
.format_error(e
, "new_image", cmd
, "update", tenant_id
)
837 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
839 def delete_image_flavor(self
, item_type
, item_id
, tenant_id
):
840 '''deletes an image or flavor from database
841 item_type must be a 'image' or 'flavor'
843 tenant_id is the asociated tenant, can be 'any' with means all
844 If tenan_id is not any, it deletes from tenants_images/flavors,
845 which means this image/flavor is used by this tenant, and if success,
846 it tries to delete from images/flavors in case this is not public,
847 that only will success if image is private and not used by other tenants
848 If tenant_id is any, it tries to delete from both tables at the same transaction
849 so that image/flavor is completely deleted from all tenants or nothing
851 for retry_
in range(0,2):
854 result
= (-HTTP_Internal_Server_Error
, "internal error")
858 self
.cur
= self
.con
.cursor()
859 cmd
= "DELETE FROM tenants_%ss WHERE %s_id = '%s'" % (item_type
, item_type
, item_id
)
860 if tenant_id
!= 'any':
861 cmd
+= " AND tenant_id = '%s'" % tenant_id
862 self
.logger
.debug(cmd
)
863 self
.cur
.execute(cmd
)
864 deleted
= self
.cur
.rowcount
865 if tenant_id
== 'any': #delete from images/flavors in the SAME transaction
866 cmd
= "DELETE FROM %ss WHERE uuid = '%s'" % (item_type
, item_id
)
867 self
.logger
.debug(cmd
)
868 self
.cur
.execute(cmd
)
869 deleted
= self
.cur
.rowcount
872 cmd
= "DELETE FROM uuids WHERE uuid = '%s'" % item_id
873 self
.logger
.debug(cmd
)
874 self
.cur
.execute(cmd
)
876 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) \
877 # VALUES ('%ss','debug','%s','%s','delete %s completely')" % \
878 # (item_type, item_id, tenant_id, item_type)
879 #self.logger.debug(cmd)
880 #self.cur.execute(cmd)
881 return deleted
, "%s '%s' completely deleted" % (item_type
, item_id
)
882 return 0, "%s '%s' not found" % (item_type
, item_id
)
886 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) \
887 # VALUES ('%ss','debug','%s','%s','delete %s reference for this tenant')" % \
888 # (item_type, item_id, tenant_id, item_type)
889 #self.logger.debug(cmd)
890 #self.cur.execute(cmd)
894 #if tenant!=any delete from images/flavors in OTHER transaction. If fails is because dependencies so that not return error
897 self
.cur
= self
.con
.cursor()
899 #delete image/flavor if not public
900 cmd
= "DELETE FROM %ss WHERE uuid = '%s' AND public = 'no'" % (item_type
, item_id
)
901 self
.logger
.debug(cmd
)
902 self
.cur
.execute(cmd
)
903 deleted_item
= self
.cur
.rowcount
904 if deleted_item
== 1:
906 cmd
= "DELETE FROM uuids WHERE uuid = '%s'" % item_id
907 self
.logger
.debug(cmd
)
908 self
.cur
.execute(cmd
)
910 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) \
911 # VALUES ('%ss','debug','%s','%s','delete %s completely')" % \
912 # (item_type, item_id, tenant_id, item_type)
913 #self.logger.debug(cmd)
914 #self.cur.execute(cmd)
915 except (mdb
.Error
, AttributeError) as e
:
916 #print "delete_%s DB Exception %d: %s" % (item_type, e.args[0], e.args[1])
918 result
= self
.format_error(e
, "delete_"+item_type
, cmd
, "delete", "servers")
921 return 1, "%s '%s' from tenant '%s' %sdeleted" % \
922 (item_type
, item_id
, tenant_id
, "completely " if deleted_item
==1 else "")
924 return 0, "%s '%s' from tenant '%s' not found" % (item_type
, item_id
, tenant_id
)
926 if result
[0]!=-HTTP_Request_Timeout
or retry_
==1: return result
928 def delete_row(self
, table
, uuid
):
929 for retry_
in range(0,2):
934 self
.cur
= self
.con
.cursor()
935 cmd
= "DELETE FROM %s WHERE uuid = '%s'" % (table
, uuid
)
936 self
.logger
.debug(cmd
)
937 self
.cur
.execute(cmd
)
938 deleted
= self
.cur
.rowcount
941 if table
== 'tenants': tenant_str
=uuid
942 else: tenant_str
='Null'
943 self
.cur
= self
.con
.cursor()
944 cmd
= "DELETE FROM uuids WHERE uuid = '%s'" % uuid
945 self
.logger
.debug(cmd
)
946 self
.cur
.execute(cmd
)
948 #cmd = "INSERT INTO logs (related,level,uuid,tenant_id,description) VALUES ('%s','debug','%s','%s','delete %s')" % (table, uuid, tenant_str, table[:-1])
949 #self.logger.debug(cmd)
950 #self.cur.execute(cmd)
951 return deleted
, table
[:-1] + " '%s' %s" %(uuid
, "deleted" if deleted
==1 else "not found")
952 except (mdb
.Error
, AttributeError) as e
:
953 r
,c
= self
.format_error(e
, "delete_row", cmd
, "delete", 'instances' if table
=='hosts' or table
=='tenants' else 'dependencies')
954 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
956 def delete_row_by_key(self
, table
, key
, value
):
957 for retry_
in range(0,2):
962 self
.cur
= self
.con
.cursor()
963 cmd
= "DELETE FROM %s" % (table
)
966 cmd
+= " WHERE %s = '%s'" % (key
, value
)
968 cmd
+= " WHERE %s is null" % (key
)
971 self
.logger
.debug(cmd
)
972 self
.cur
.execute(cmd
)
973 deleted
= self
.cur
.rowcount
975 return -1, 'Not found'
978 except (mdb
.Error
, AttributeError) as e
:
979 r
,c
= self
.format_error(e
, "delete_row_by_key", cmd
, "delete", 'instances' if table
=='hosts' or table
=='tenants' else 'dependencies')
980 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
982 def delete_row_by_dict(self
, **sql_dict
):
983 ''' Deletes rows from a table.
984 Attribute sql_dir: dictionary with the following key: value
985 'FROM': string of table name (Mandatory)
986 'WHERE': dict of key:values, translated to key=value AND ... (Optional)
987 'WHERE_NOT': dict of key:values, translated to key<>value AND ... (Optional)
988 'WHERE_NOTNULL': (list or tuple of items that must not be null in a where ... (Optional)
989 'LIMIT': limit of number of rows (Optional)
990 Return: the (number of items deleted, descriptive test) if ok; (negative, descriptive text) if error
993 from_
= "FROM " + str(sql_dict
['FROM'])
994 #print 'from_', from_
995 if 'WHERE' in sql_dict
and len(sql_dict
['WHERE']) > 0:
997 where_
= "WHERE " + " AND ".join(map( lambda x
: str(x
) + (" is Null" if w
[x
] is None else "='"+str(w
[x
])+"'"), w
.keys()) )
999 if 'WHERE_NOT' in sql_dict
and len(sql_dict
['WHERE_NOT']) > 0:
1000 w
=sql_dict
['WHERE_NOT']
1001 where_2
= " AND ".join(map( lambda x
: str(x
) + (" is not Null" if w
[x
] is None else "<>'"+str(w
[x
])+"'"), w
.keys()) )
1002 if len(where_
)==0: where_
= "WHERE " + where_2
1003 else: where_
= where_
+ " AND " + where_2
1004 if 'WHERE_NOTNULL' in sql_dict
and len(sql_dict
['WHERE_NOTNULL']) > 0:
1005 w
=sql_dict
['WHERE_NOTNULL']
1006 where_2
= " AND ".join(map( lambda x
: str(x
) + " is not Null", w
) )
1007 if len(where_
)==0: where_
= "WHERE " + where_2
1008 else: where_
= where_
+ " AND " + where_2
1009 #print 'where_', where_
1010 limit_
= "LIMIT " + str(sql_dict
['LIMIT']) if 'LIMIT' in sql_dict
else ""
1011 #print 'limit_', limit_
1012 cmd
= " ".join( ("DELETE", from_
, where_
, limit_
) )
1013 self
.logger
.debug(cmd
)
1014 for retry_
in range(0,2):
1018 self
.cur
= self
.con
.cursor()
1019 self
.cur
.execute(cmd
)
1020 deleted
= self
.cur
.rowcount
1021 return deleted
, "%d deleted from %s" % (deleted
, sql_dict
['FROM'][:-1] )
1022 except (mdb
.Error
, AttributeError) as e
:
1023 r
,c
= self
.format_error(e
, "delete_row_by_dict", cmd
, "delete", 'dependencies')
1024 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1027 def get_instance(self
, instance_id
):
1028 for retry_
in range(0,2):
1032 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1034 cmd
= "SELECT uuid, name, description, progress, host_id, flavor_id, image_id, status, last_error, tenant_id, ram, vcpus, created_at \
1035 FROM instances WHERE uuid = '" + str(instance_id
) +"'"
1036 self
.logger
.debug(cmd
)
1037 self
.cur
.execute(cmd
)
1038 if self
.cur
.rowcount
== 0 : return 0, "instance '" + str(instance_id
) +"'not found."
1039 instance
= self
.cur
.fetchone()
1041 cmd
= "SELECT uuid as iface_id, net_id, mac as mac_address, ip_address, name, Mbps as bandwidth, vpci, model \
1042 FROM ports WHERE type = 'instance:bridge' AND instance_id = '" + instance_id
+ "'"
1043 self
.logger
.debug(cmd
)
1044 self
.cur
.execute(cmd
)
1045 if self
.cur
.rowcount
> 0 :
1046 instance
['networks'] = self
.cur
.fetchall()
1051 cmd
= "SELECT type, vpci, image_id, xml,dev FROM instance_devices WHERE instance_id = '%s' " % str(instance_id
)
1052 self
.logger
.debug(cmd
)
1053 self
.cur
.execute(cmd
)
1054 if self
.cur
.rowcount
> 0 :
1055 extended
['devices'] = self
.cur
.fetchall()
1058 cmd
= "SELECT id, numa_socket as source FROM numas WHERE host_id = '" + str(instance
['host_id']) + "'"
1059 self
.logger
.debug(cmd
)
1060 self
.cur
.execute(cmd
)
1061 host_numas
= self
.cur
.fetchall()
1062 #print 'host_numas', host_numas
1063 for k
in host_numas
:
1064 numa_id
= str(k
['id'])
1067 cmd
= "SELECT consumed FROM resources_mem WHERE instance_id = '%s' AND numa_id = '%s'" % ( instance_id
, numa_id
)
1068 self
.logger
.debug(cmd
)
1069 self
.cur
.execute(cmd
)
1070 if self
.cur
.rowcount
> 0:
1071 mem_dict
= self
.cur
.fetchone()
1072 numa_dict
['memory'] = mem_dict
['consumed']
1074 cursor2
= self
.con
.cursor()
1075 cmd
= "SELECT core_id, paired, MIN(v_thread_id) as v1, MAX(v_thread_id) as v2, COUNT(instance_id) as nb, MIN(thread_id) as t1, MAX(thread_id) as t2 FROM resources_core WHERE instance_id = '%s' AND numa_id = '%s' GROUP BY core_id,paired" % ( str(instance_id
), numa_id
)
1076 self
.logger
.debug(cmd
)
1077 cursor2
.execute(cmd
)
1078 core_list
= []; core_source
= []
1079 paired_list
= []; paired_source
= []
1080 thread_list
= []; thread_source
= []
1081 if cursor2
.rowcount
> 0:
1082 cores
= cursor2
.fetchall()
1084 if core
[4] == 2: #number of used threads from core
1085 if core
[3] == core
[2]: #only one thread asigned to VM, so completely core
1086 core_list
.append(core
[2])
1087 core_source
.append(core
[5])
1088 elif core
[1] == 'Y':
1089 paired_list
.append(core
[2:4])
1090 paired_source
.append(core
[5:7])
1092 thread_list
.extend(core
[2:4])
1093 thread_source
.extend(core
[5:7])
1096 thread_list
.append(core
[2])
1097 thread_source
.append(core
[5])
1098 if len(core_list
) > 0:
1099 numa_dict
['cores'] = len(core_list
)
1100 numa_dict
['cores-id'] = core_list
1101 numa_dict
['cores-source'] = core_source
1102 if len(paired_list
) > 0:
1103 numa_dict
['paired-threads'] = len(paired_list
)
1104 numa_dict
['paired-threads-id'] = paired_list
1105 numa_dict
['paired-threads-source'] = paired_source
1106 if len(thread_list
) > 0:
1107 numa_dict
['threads'] = len(thread_list
)
1108 numa_dict
['threads-id'] = thread_list
1109 numa_dict
['threads-source'] = thread_source
1111 #get dedicated ports and SRIOV
1112 cmd
= "SELECT port_id as iface_id, p.vlan as vlan, p.mac as mac_address, net_id, if(model='PF','yes',if(model='VF','no','yes:sriov')) as dedicated,\
1113 rp.Mbps as bandwidth, name, vpci, pci as source \
1114 FROM resources_port as rp join ports as p on port_id=uuid WHERE p.instance_id = '%s' AND numa_id = '%s' and p.type='instance:data'" % (instance_id
, numa_id
)
1115 self
.logger
.debug(cmd
)
1116 self
.cur
.execute(cmd
)
1117 if self
.cur
.rowcount
> 0:
1118 numa_dict
['interfaces'] = self
.cur
.fetchall()
1119 #print 'interfaces', numa_dict
1121 if len(numa_dict
) > 0 :
1122 numa_dict
['source'] = k
['source'] #numa socket
1123 numas
.append(numa_dict
)
1125 if len(numas
) > 0 : extended
['numas'] = numas
1126 if len(extended
) > 0 : instance
['extended'] = extended
1127 af
.DeleteNone(instance
)
1129 except (mdb
.Error
, AttributeError) as e
:
1130 r
,c
= self
.format_error(e
, "get_instance", cmd
)
1131 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1133 def get_numas(self
, requirements
, prefered_host_id
=None, only_of_ports
=True):
1134 '''Obtain a valid NUMA/HOST for deployment a VM
1135 requirements: contain requirement regarding:
1136 requirements['ram']: Non huge page memory in MB; 0 to skip
1137 requirements['vcpus']: Non isolated cpus; 0 to skip
1138 requirements['numa']: Requiremets to be fixed in ONE Numa node
1139 requirements['numa']['memory']: Huge page memory in GB at ; 0 for any
1140 requirements['numa']['proc_req_type']: Type of processor, cores or threads
1141 requirements['numa']['proc_req_nb']: Number of isolated cpus
1142 requirements['numa']['port_list']: Physical NIC ports list ; [] for any
1143 requirements['numa']['sriov_list']: Virtual function NIC ports list ; [] for any
1144 prefered_host_id: if not None return this host if it match
1145 only_of_ports: if True only those ports conected to the openflow (of) are valid,
1146 that is, with switch_port information filled; if False, all NIC ports are valid.
1147 Return a valid numa and host
1150 for retry_
in range(0,2):
1154 # #Find numas of prefered host
1155 # prefered_numas = ()
1156 # if prefered_host_id != None:
1157 # self.cur = self.con.cursor()
1158 # self.cur.execute("SELECT id FROM numas WHERE host_id='%s'" + prefered_host_id)
1159 # prefered_numas = self.cur.fetchall()
1162 #Find valid host for the ram and vcpus
1163 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1164 cmd
= "CALL GetHostByMemCpu(%s, %s)" % (str(requirements
['ram']), str(requirements
['vcpus']))
1165 self
.logger
.debug(cmd
)
1166 self
.cur
.callproc('GetHostByMemCpu', (str(requirements
['ram']), str(requirements
['vcpus'])) )
1167 valid_hosts
= self
.cur
.fetchall()
1169 self
.cur
= self
.con
.cursor()
1171 if len(valid_hosts
)<=0:
1172 error_text
= 'No room at data center. Can not find a host with %s MB memory and %s cpus available' % (str(requirements
['ram']), str(requirements
['vcpus']))
1173 #self.logger.debug(error_text)
1174 return -1, error_text
1176 #elif req_numa != None:
1177 #Find valid numa nodes for memory requirements
1178 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1179 cmd
= "CALL GetNumaByMemory(%s)" % str(requirements
['numa']['memory'])
1180 self
.logger
.debug(cmd
)
1181 self
.cur
.callproc('GetNumaByMemory', (requirements
['numa']['memory'],) )
1182 valid_for_memory
= self
.cur
.fetchall()
1184 self
.cur
= self
.con
.cursor()
1185 if len(valid_for_memory
)<=0:
1186 error_text
= 'No room at data center. Can not find a host with %s GB Hugepages memory available' % str(requirements
['numa']['memory'])
1187 #self.logger.debug(error_text)
1188 return -1, error_text
1190 #Find valid numa nodes for processor requirements
1191 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1192 if requirements
['numa']['proc_req_type'] == 'threads':
1193 cpu_requirement_text
='cpu-threads'
1194 cmd
= "CALL GetNumaByThread(%s)" % str(requirements
['numa']['proc_req_nb'])
1195 self
.logger
.debug(cmd
)
1196 self
.cur
.callproc('GetNumaByThread', (requirements
['numa']['proc_req_nb'],) )
1198 cpu_requirement_text
='cpu-cores'
1199 cmd
= "CALL GetNumaByCore(%s)" % str(requirements
['numa']['proc_req_nb'])
1200 self
.logger
.debug(cmd
)
1201 self
.cur
.callproc('GetNumaByCore', (requirements
['numa']['proc_req_nb'],) )
1202 valid_for_processor
= self
.cur
.fetchall()
1204 self
.cur
= self
.con
.cursor()
1205 if len(valid_for_processor
)<=0:
1206 error_text
= 'No room at data center. Can not find a host with %s %s available' % (str(requirements
['numa']['proc_req_nb']),cpu_requirement_text
)
1207 #self.logger.debug(error_text)
1208 return -1, error_text
1210 #Find the numa nodes that comply for memory and processor requirements
1211 #sorting from less to more memory capacity
1213 for m_numa
in valid_for_memory
:
1214 numa_valid_for_processor
= False
1215 for p_numa
in valid_for_processor
:
1216 if m_numa
['numa_id'] == p_numa
['numa_id']:
1217 numa_valid_for_processor
= True
1219 numa_valid_for_host
= False
1220 prefered_numa
= False
1221 for p_host
in valid_hosts
:
1222 if m_numa
['host_id'] == p_host
['uuid']:
1223 numa_valid_for_host
= True
1224 if p_host
['uuid'] == prefered_host_id
:
1225 prefered_numa
= True
1227 if numa_valid_for_host
and numa_valid_for_processor
:
1229 valid_numas
.insert(0, m_numa
['numa_id'])
1231 valid_numas
.append(m_numa
['numa_id'])
1232 if len(valid_numas
)<=0:
1233 error_text
= 'No room at data center. Can not find a host with %s MB hugepages memory and %s %s available in the same numa' %\
1234 (requirements
['numa']['memory'], str(requirements
['numa']['proc_req_nb']),cpu_requirement_text
)
1235 #self.logger.debug(error_text)
1236 return -1, error_text
1238 # print 'Valid numas list: '+str(valid_numas)
1240 #Find valid numa nodes for interfaces requirements
1241 #For each valid numa we will obtain the number of available ports and check if these are valid
1243 for numa_id
in valid_numas
:
1244 # print 'Checking '+str(numa_id)
1246 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1248 cmd
="CALL GetAvailablePorts(%s)" % str(numa_id
)
1249 self
.logger
.debug(cmd
)
1250 self
.cur
.callproc('GetAvailablePorts', (numa_id
,) )
1252 cmd
="CALL GetAllAvailablePorts(%s)" % str(numa_id
)
1253 self
.logger
.debug(cmd
)
1254 self
.cur
.callproc('GetAllAvailablePorts', (numa_id
,) )
1255 available_ports
= self
.cur
.fetchall()
1257 self
.cur
= self
.con
.cursor()
1259 #Set/reset reservations
1260 for port
in available_ports
:
1261 port
['Mbps_reserved'] = 0
1262 port
['SRIOV_reserved'] = 0
1264 #Try to allocate physical ports
1265 physical_ports_found
= True
1266 for iface
in requirements
['numa']['port_list']:
1267 # print '\t\tchecking iface: '+str(iface)
1269 for port
in available_ports
:
1270 # print '\t\t\tfor port: '+str(port)
1271 #If the port is not empty continue
1272 if port
['Mbps_free'] != port
['Mbps'] or port
['Mbps_reserved'] != 0:
1273 # print '\t\t\t\t Not empty port'
1275 #If the port speed is not enough continue
1276 if port
['Mbps'] < iface
['bandwidth']:
1277 # print '\t\t\t\t Not enough speed'
1280 #Otherwise this is a valid port
1281 port
['Mbps_reserved'] = port
['Mbps']
1282 port
['SRIOV_reserved'] = 0
1283 iface
['port_id'] = port
['port_id']
1284 iface
['vlan'] = None
1285 iface
['mac'] = port
['mac']
1286 iface
['switch_port'] = port
['switch_port']
1287 # print '\t\t\t\t Dedicated port found '+str(port['port_id'])
1291 #if all ports have been checked and no match has been found
1292 #this is not a valid numa
1294 # print '\t\t\t\t\tAll ports have been checked and no match has been found for numa '+str(numa_id)+'\n\n'
1295 physical_ports_found
= False
1298 #if there is no match continue checking the following numa
1299 if not physical_ports_found
:
1302 #Try to allocate SR-IOVs
1303 sriov_ports_found
= True
1304 for iface
in requirements
['numa']['sriov_list']:
1305 # print '\t\tchecking iface: '+str(iface)
1307 for port
in available_ports
:
1308 # print '\t\t\tfor port: '+str(port)
1309 #If there are not available SR-IOVs continue
1310 if port
['availableSRIOV'] - port
['SRIOV_reserved'] <= 0:
1311 # print '\t\t\t\t Not enough SR-IOV'
1313 #If the port free speed is not enough continue
1314 if port
['Mbps_free'] - port
['Mbps_reserved'] < iface
['bandwidth']:
1315 # print '\t\t\t\t Not enough speed'
1318 #Otherwise this is a valid port
1319 port
['Mbps_reserved'] += iface
['bandwidth']
1320 port
['SRIOV_reserved'] += 1
1321 # print '\t\t\t\t SR-IOV found '+str(port['port_id'])
1322 iface
['port_id'] = port
['port_id']
1323 iface
['vlan'] = None
1324 iface
['mac'] = port
['mac']
1325 iface
['switch_port'] = port
['switch_port']
1329 #if all ports have been checked and no match has been found
1330 #this is not a valid numa
1332 # print '\t\t\t\t\tAll ports have been checked and no match has been found for numa '+str(numa_id)+'\n\n'
1333 sriov_ports_found
= False
1336 #if there is no match continue checking the following numa
1337 if not sriov_ports_found
:
1341 if sriov_ports_found
and physical_ports_found
:
1346 error_text
= 'No room at data center. Can not find a host with the required hugepages, vcpus and interfaces'
1347 #self.logger.debug(error_text)
1348 return -1, error_text
1350 #self.logger.debug('Full match found in numa %s', str(numa_id))
1352 for numa
in valid_for_processor
:
1353 if numa_id
==numa
['numa_id']:
1354 host_id
=numa
['host_id']
1356 return 0, {'numa_id':numa_id
, 'host_id': host_id
, }
1357 except (mdb
.Error
, AttributeError) as e
:
1358 r
,c
= self
.format_error(e
, "get_numas", cmd
)
1359 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1361 def new_instance(self
, instance_dict
, nets
, ports_to_free
):
1362 for retry_
in range(0,2):
1366 self
.cur
= self
.con
.cursor()
1368 #create uuid if not provided
1369 if 'uuid' not in instance_dict
:
1370 uuid
= instance_dict
['uuid'] = str(myUuid
.uuid1()) # create_uuid
1371 else: #check uuid is valid
1372 uuid
= str(instance_dict
['uuid'])
1376 cmd
= "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'instances')" % (uuid
, uuid
)
1377 self
.logger
.debug(cmd
)
1378 self
.cur
.execute(cmd
)
1380 #insert in table instance
1381 extended
= instance_dict
.pop('extended', None);
1382 bridgedifaces
= instance_dict
.pop('bridged-ifaces', () );
1384 keys
= ",".join(instance_dict
.keys())
1385 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", instance_dict
.values() ) )
1386 cmd
= "INSERT INTO instances (" + keys
+ ") VALUES (" + values
+ ")"
1387 self
.logger
.debug(cmd
)
1388 self
.cur
.execute(cmd
)
1389 #if result != 1: return -1, "Database Error while inserting at instances table"
1392 nb_bridge_ifaces
= nb_cores
= nb_ifaces
= nb_numas
= 0
1393 #insert bridged_ifaces
1394 for iface
in bridgedifaces
:
1395 #generate and insert a iface uuid
1396 iface
['uuid'] = str(myUuid
.uuid1()) # create_uuid
1397 cmd
= "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'ports')" % (iface
['uuid'], uuid
)
1398 self
.logger
.debug(cmd
)
1399 self
.cur
.execute(cmd
)
1401 iface
['instance_id'] = uuid
1402 iface
['type'] = 'instance:bridge'
1403 if 'name' not in iface
: iface
['name']="br"+str(nb_bridge_ifaces
)
1404 iface
['Mbps']=iface
.pop('bandwidth', None)
1405 if 'mac_address' not in iface
:
1406 iface
['mac'] = af
.gen_random_mac()
1408 iface
['mac'] = iface
['mac_address']
1409 del iface
['mac_address']
1410 #iface['mac']=iface.pop('mac_address', None) #for leaving mac generation to libvirt
1411 keys
= ",".join(iface
.keys())
1412 values
= ",".join( map(lambda x
: "Null" if x
is None else "'"+str(x
)+"'", iface
.values() ) )
1413 cmd
= "INSERT INTO ports (" + keys
+ ") VALUES (" + values
+ ")"
1414 self
.logger
.debug(cmd
)
1415 self
.cur
.execute(cmd
)
1416 nb_bridge_ifaces
+= 1
1418 if extended
is not None:
1419 if 'numas' not in extended
or extended
['numas'] is None: extended
['numas'] = ()
1420 for numa
in extended
['numas']:
1423 if 'cores' not in numa
or numa
['cores'] is None: numa
['cores'] = ()
1424 for core
in numa
['cores']:
1426 cmd
= "UPDATE resources_core SET instance_id='%s'%s%s WHERE id='%s'" \
1428 (",v_thread_id='" + str(core
['vthread']) + "'") if 'vthread' in core
else '', \
1429 (",paired='" + core
['paired'] + "'") if 'paired' in core
else '', \
1431 self
.logger
.debug(cmd
)
1432 self
.cur
.execute(cmd
)
1434 if 'interfaces' not in numa
or numa
['interfaces'] is None: numa
['interfaces'] = ()
1435 for iface
in numa
['interfaces']:
1436 #generate and insert an uuid; iface[id]=iface_uuid; iface[uuid]= net_id
1437 iface
['id'] = str(myUuid
.uuid1()) # create_uuid
1438 cmd
= "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'ports')" % (iface
['id'], uuid
)
1439 self
.logger
.debug(cmd
)
1440 self
.cur
.execute(cmd
)
1442 mbps_
=("'"+str(iface
['Mbps_used'])+"'") if 'Mbps_used' in iface
and iface
['Mbps_used'] is not None else "Mbps"
1443 if iface
["dedicated"]=="yes":
1445 elif iface
["dedicated"]=="yes:sriov":
1446 iface_model
="VFnotShared"
1447 elif iface
["dedicated"]=="no":
1450 INSERT
=(iface
['mac_address'], iface
['switch_port'], iface
.get('vlan',None), 'instance:data', iface
['Mbps_used'], iface
['id'],
1451 uuid
, instance_dict
['tenant_id'], iface
.get('name',None), iface
.get('vpci',None), iface
.get('uuid',None), iface_model
)
1452 cmd
= "INSERT INTO ports (mac,switch_port,vlan,type,Mbps,uuid,instance_id,tenant_id,name,vpci,net_id, model) " + \
1453 " VALUES (" + ",".join(map(lambda x
: 'Null' if x
is None else "'"+str(x
)+"'", INSERT
)) + ")"
1454 self
.logger
.debug(cmd
)
1455 self
.cur
.execute(cmd
)
1457 nets
.append(iface
['uuid'])
1459 #discover if this port is not used by anyone
1460 cmd
= "SELECT source_name, mac FROM ( SELECT root_id, count(instance_id) as used FROM resources_port" \
1461 " WHERE root_id=(SELECT root_id from resources_port WHERE id='%s')"\
1462 " GROUP BY root_id ) AS A JOIN resources_port as B ON A.root_id=B.id AND A.used=0" % iface
['port_id']
1463 self
.logger
.debug(cmd
)
1464 self
.cur
.execute(cmd
)
1465 ports_to_free
+= self
.cur
.fetchall()
1467 cmd
= "UPDATE resources_port SET instance_id='%s', port_id='%s',Mbps_used=%s WHERE id='%s'" \
1468 % (uuid
, iface
['id'], mbps_
, iface
['port_id'])
1469 #if Mbps_used not suply, set the same value of 'Mpbs', that is the total
1470 self
.logger
.debug(cmd
)
1471 self
.cur
.execute(cmd
)
1473 if 'memory' in numa
and numa
['memory'] is not None and numa
['memory']>0:
1474 cmd
= "INSERT INTO resources_mem (numa_id, instance_id, consumed) VALUES ('%s','%s','%s')" % (numa
['numa_id'], uuid
, numa
['memory'])
1475 self
.logger
.debug(cmd
)
1476 self
.cur
.execute(cmd
)
1477 if 'devices' not in extended
or extended
['devices'] is None: extended
['devices'] = ()
1478 for device
in extended
['devices']:
1479 if 'vpci' in device
: vpci
= "'" + device
['vpci'] + "'"
1481 if 'image_id' in device
: image_id
= "'" + device
['image_id'] + "'"
1482 else: image_id
= 'Null'
1483 if 'xml' in device
: xml
= "'" + device
['xml'] + "'"
1485 if 'dev' in device
: dev
= "'" + device
['dev'] + "'"
1487 cmd
= "INSERT INTO instance_devices (type, instance_id, image_id, vpci, xml, dev) VALUES ('%s','%s', %s, %s, %s, %s)" % \
1488 (device
['type'], uuid
, image_id
, vpci
, xml
, dev
)
1489 self
.logger
.debug(cmd
)
1490 self
.cur
.execute(cmd
)
1492 #cmd = "INSERT INTO logs (related,level,uuid,description) VALUES ('instances','debug','%s','new instance: %d numas, %d theads, %d ifaces %d bridge_ifaces')" % (uuid, nb_numas, nb_cores, nb_ifaces, nb_bridge_ifaces)
1493 #self.logger.debug(cmd)
1494 #self.cur.execute(cmd)
1498 except (mdb
.Error
, AttributeError) as e
:
1499 r
,c
= self
.format_error(e
, "new_instance", cmd
)
1500 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1502 def delete_instance(self
, instance_id
, tenant_id
, net_list
, ports_to_free
, logcause
="requested by http"):
1503 for retry_
in range(0,2):
1507 self
.cur
= self
.con
.cursor()
1509 cmd
= "SELECT uuid FROM instances WHERE uuid='%s' AND tenant_id='%s'" % (instance_id
, tenant_id
)
1510 self
.logger
.debug(cmd
)
1511 self
.cur
.execute(cmd
)
1512 if self
.cur
.rowcount
== 0 : return 0, "instance %s not found in tenant %s" % (instance_id
, tenant_id
)
1514 #delete bridged ifaces, instace_devices, resources_mem; done by database: it is automatic by Database; FOREIGN KEY DELETE CASCADE
1517 cmd
= "SELECT DISTINCT net_id from ports WHERE instance_id = '%s' AND net_id is not Null AND type='instance:data'" % instance_id
1518 self
.logger
.debug(cmd
)
1519 self
.cur
.execute(cmd
)
1520 net_list__
= self
.cur
.fetchall()
1521 for net
in net_list__
:
1522 net_list
.append(net
[0])
1524 #get dataplane interfaces releases by this VM; both PF and VF with no other VF
1525 cmd
="SELECT source_name, mac FROM (SELECT root_id, count(instance_id) as used FROM resources_port WHERE instance_id='%s' GROUP BY root_id ) AS A" % instance_id \
1526 + " JOIN (SELECT root_id, count(instance_id) as used FROM resources_port GROUP BY root_id) AS B ON A.root_id=B.root_id AND A.used=B.used"\
1527 + " JOIN resources_port as C ON A.root_id=C.id"
1528 # cmd = "SELECT DISTINCT root_id FROM resources_port WHERE instance_id = '%s'" % instance_id
1529 self
.logger
.debug(cmd
)
1530 self
.cur
.execute(cmd
)
1531 ports_to_free
+= self
.cur
.fetchall()
1533 #update resources port
1534 cmd
= "UPDATE resources_port SET instance_id=Null, port_id=Null, Mbps_used='0' WHERE instance_id = '%s'" % instance_id
1535 self
.logger
.debug(cmd
)
1536 self
.cur
.execute(cmd
)
1538 # #filter dataplane ports used by this VM that now are free
1539 # for port in ports_list__:
1540 # cmd = "SELECT mac, count(instance_id) FROM resources_port WHERE root_id = '%s'" % port[0]
1541 # self.logger.debug(cmd)
1542 # self.cur.execute(cmd)
1543 # mac_list__ = self.cur.fetchone()
1544 # if mac_list__ and mac_list__[1]==0:
1545 # ports_to_free.append(mac_list__[0])
1548 #update resources core
1549 cmd
= "UPDATE resources_core SET instance_id=Null, v_thread_id=Null, paired='N' WHERE instance_id = '%s'" % instance_id
1550 self
.logger
.debug(cmd
)
1551 self
.cur
.execute(cmd
)
1553 #delete all related uuids
1554 cmd
= "DELETE FROM uuids WHERE root_uuid='%s'" % instance_id
1555 self
.logger
.debug(cmd
)
1556 self
.cur
.execute(cmd
)
1559 #cmd = "INSERT INTO logs (related,level,uuid,description) VALUES ('instances','debug','%s','delete instance %s')" % (instance_id, logcause)
1560 #self.logger.debug(cmd)
1561 #self.cur.execute(cmd)
1564 cmd
= "DELETE FROM instances WHERE uuid='%s' AND tenant_id='%s'" % (instance_id
, tenant_id
)
1565 self
.cur
.execute(cmd
)
1566 return 1, "instance %s from tenant %s DELETED" % (instance_id
, tenant_id
)
1568 except (mdb
.Error
, AttributeError) as e
:
1569 r
,c
= self
.format_error(e
, "delete_instance", cmd
)
1570 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1572 def get_ports(self
, WHERE
):
1573 ''' Obtain ports using the WHERE filtering.
1575 'where_': dict of key:values, translated to key=value AND ... (Optional)
1576 Return: a list with dictionarys at each row
1578 for retry_
in range(0,2):
1583 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1584 select_
= "SELECT uuid,'ACTIVE' as status,admin_state_up,name,net_id,\
1585 tenant_id,type,mac,vlan,switch_port,instance_id,Mbps FROM ports "
1587 if WHERE
is None or len(WHERE
) == 0: where_
= ""
1589 where_
= "WHERE " + " AND ".join(map( lambda x
: str(x
) + (" is Null" if WHERE
[x
] is None else "='"+str(WHERE
[x
])+"'"), WHERE
.keys()) )
1590 limit_
= "LIMIT 100"
1591 cmd
= " ".join( (select_
, where_
, limit_
) )
1592 # print "SELECT multiple de instance_ifaces, iface_uuid, external_ports" #print cmd
1593 self
.logger
.debug(cmd
)
1594 self
.cur
.execute(cmd
)
1595 ports
= self
.cur
.fetchall()
1596 if self
.cur
.rowcount
>0: af
.DeleteNone(ports
)
1597 return self
.cur
.rowcount
, ports
1598 # return self.get_table(FROM=from_, SELECT=select_,WHERE=where_,LIMIT=100)
1599 except (mdb
.Error
, AttributeError) as e
:
1600 r
,c
= self
.format_error(e
, "get_ports", cmd
)
1601 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1603 def check_target_net(self
, net_id
, tenant_id
, port_type
):
1604 '''check if valid attachement of a port into a target net
1606 net_id: target net uuid
1607 tenant_id: client where tenant belongs. Not used in this version
1608 port_type: string with the option 'instance:bridge', 'instance:data', 'external'
1610 (0,net_dict) if ok, where net_dict contain 'uuid','type','vlan', ...
1611 (negative,string-error) if error
1613 for retry_
in range(0,2):
1617 self
.cur
= self
.con
.cursor(mdb
.cursors
.DictCursor
)
1618 cmd
= "SELECT * FROM nets WHERE uuid='%s'" % net_id
1619 self
.logger
.debug(cmd
)
1620 self
.cur
.execute(cmd
)
1621 if self
.cur
.rowcount
== 0 : return -1, "network_id %s does not match any net" % net_id
1622 net
= self
.cur
.fetchone()
1625 except (mdb
.Error
, AttributeError) as e
:
1626 r
,c
= self
.format_error(e
, "check_target_net", cmd
)
1627 if r
!=-HTTP_Request_Timeout
or retry_
==1: return r
,c
1629 if tenant_id
is not None and tenant_id
is not "admin":
1630 if net
['tenant_id']==tenant_id
and net
['shared']=='false':
1631 return -1, "needed admin privileges to attach to the net %s" % net_id
1633 if (net
['type'] in ('p2p','data') and 'port_type' == 'instance:bridge') or \
1634 (net
['type'] in ('bridge_data','bridge_man') and 'port_type' != 'instance:bridge') :
1635 return -1, "can not attach a port of type %s into a net of type %s" % (port_type
, net
['type'])
1636 if net
['type'] == 'ptp':
1638 nb_ports
, data
= self
.get_ports( {'net_id':net_id
} )
1645 return -1, "net of type p2p already contain two ports attached. No room for another"
1649 if __name__
== "__main__":