From: Daniel Henrique Barboza <dhbarboza82(a)gmail.com>
- a new method was introduced in model/host.py that returns all
the unavailable devices that are being used by all the VMs in
the host. This method is used by the get_list() call when
the parameter _available_only is set to 'true'.
- to avoid problems with circular dependencies, the deduce_dev_name
method was moved from model/vmhostdevs to model/host.
Signed-off-by: Daniel Henrique Barboza <dhbarboza82(a)gmail.com>
---
src/kimchi/model/host.py | 105 ++++++++++++++++++++++++++++++++++++++++-
src/kimchi/model/vmhostdevs.py | 75 ++---------------------------
2 files changed, 108 insertions(+), 72 deletions(-)
diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py
index b2fa379..e51ede4 100644
--- a/src/kimchi/model/host.py
+++ b/src/kimchi/model/host.py
@@ -22,6 +22,7 @@ import os
import time
import platform
from collections import defaultdict
+from lxml import objectify
import psutil
from cherrypy.process.plugins import BackgroundTask
@@ -34,7 +35,7 @@ from kimchi.exception import InvalidOperation, InvalidParameter
from kimchi.exception import NotFoundError, OperationFailed
from kimchi.model.config import CapabilitiesModel
from kimchi.model.tasks import TaskModel
-from kimchi.model.vms import DOM_STATE_MAP
+from kimchi.model.vms import DOM_STATE_MAP, VMModel, VMsModel
from kimchi.repositories import Repositories
from kimchi.swupdate import SoftwareUpdate
from kimchi.utils import add_task, kimchi_log
@@ -318,8 +319,29 @@ class DevicesModel(object):
except AttributeError:
self.cap_map['fc_host'] = None
+ def _get_unavailable_devices(self):
+ vm_list = VMsModel.get_vms(self.conn)
+ unavailable_devs = []
+ for vm in vm_list:
+ dom = VMModel.get_vm(vm, self.conn)
+ xmlstr = dom.XMLDesc(0)
+ root = objectify.fromstring(xmlstr)
+ try:
+ hostdev = root.devices.hostdev
+ except AttributeError:
+ continue
+
+ vm_devs = [DeviceModel.deduce_dev_name(e, self.conn)
+ for e in hostdev]
+
+ for dev in vm_devs:
+ unavailable_devs.append(dev)
+
+ return unavailable_devs
+
def get_list(self, _cap=None, _passthrough=None,
- _passthrough_affected_by=None):
+ _passthrough_affected_by=None,
+ _available_only=None):
if _passthrough_affected_by is not None:
# _passthrough_affected_by conflicts with _cap and _passthrough
if (_cap, _passthrough) != (None, None):
@@ -336,8 +358,15 @@ class DevicesModel(object):
conn = self.conn.get()
passthrough_names = [
dev['name'] for dev in hostdev.get_passthrough_dev_infos(conn)]
+
dev_names = list(set(dev_names) & set(passthrough_names))
+ if _available_only is not None and _available_only.lower() \
+ == 'true':
+ unavailable_devs = self._get_unavailable_devices()
+ dev_names = [dev for dev in dev_names
+ if dev not in unavailable_devs]
+
dev_names.sort()
return dev_names
@@ -390,6 +419,78 @@ class DeviceModel(object):
raise NotFoundError('KCHHOST0003E', {'name': nodedev_name})
return hostdev.get_dev_info(dev)
+ @staticmethod
+ def _toint(num_str):
+ if num_str.startswith('0x'):
+ return int(num_str, 16)
+ elif num_str.startswith('0'):
+ return int(num_str, 8)
+ else:
+ return int(num_str)
+
+ @staticmethod
+ def deduce_dev_name(e, conn):
+ if e.attrib['type'] == 'pci':
+ return DeviceModel._deduce_dev_name_pci(e)
+ elif e.attrib['type'] == 'scsi':
+ return DeviceModel._deduce_dev_name_scsi(e)
+ elif e.attrib['type'] == 'usb':
+ return DeviceModel._deduce_dev_name_usb(e, conn)
+ return None
+
+ @staticmethod
+ def _deduce_dev_name_pci(e):
+ attrib = {}
+ for field in ('domain', 'bus', 'slot',
'function'):
+ attrib[field] = DeviceModel._toint(e.source.address.attrib[field])
+ return 'pci_%(domain)04x_%(bus)02x_%(slot)02x_%(function)x' % attrib
+
+ @staticmethod
+ def _deduce_dev_name_scsi(e):
+ attrib = {}
+ for field in ('bus', 'target', 'unit'):
+ attrib[field] = DeviceModel._toint(e.source.address.attrib[field])
+ attrib['host'] = DeviceModel._toint(
+ e.source.adapter.attrib['name'][len('scsi_host'):])
+ return 'scsi_%(host)d_%(bus)d_%(target)d_%(unit)d' % attrib
+
+ @staticmethod
+ def _deduce_dev_name_usb(e, conn):
+ dev_names = DevicesModel(conn=conn).get_list(_cap='usb_device')
+ usb_infos = [DeviceModel(conn=conn).lookup(dev_name)
+ for dev_name in dev_names]
+
+ unknown_dev = None
+
+ try:
+ evendor = DeviceModel._toint(e.source.vendor.attrib['id'])
+ eproduct = DeviceModel._toint(e.source.product.attrib['id'])
+ except AttributeError:
+ evendor = 0
+ eproduct = 0
+ else:
+ unknown_dev = 'usb_vendor_%s_product_%s' % (evendor, eproduct)
+
+ try:
+ ebus = DeviceModel._toint(e.source.address.attrib['bus'])
+ edevice = DeviceModel._toint(e.source.address.attrib['device'])
+ except AttributeError:
+ ebus = -1
+ edevice = -1
+ else:
+ unknown_dev = 'usb_bus_%s_device_%s' % (ebus, edevice)
+
+ for usb_info in usb_infos:
+ ivendor = DeviceModel._toint(usb_info['vendor']['id'])
+ iproduct = DeviceModel._toint(usb_info['product']['id'])
+ if evendor == ivendor and eproduct == iproduct:
+ return usb_info['name']
+ ibus = usb_info['bus']
+ idevice = usb_info['device']
+ if ebus == ibus and edevice == idevice:
+ return usb_info['name']
+ return unknown_dev
+
class PackagesUpdateModel(object):
def __init__(self, **kargs):
diff --git a/src/kimchi/model/vmhostdevs.py b/src/kimchi/model/vmhostdevs.py
index 12226ca..d668223 100644
--- a/src/kimchi/model/vmhostdevs.py
+++ b/src/kimchi/model/vmhostdevs.py
@@ -49,69 +49,7 @@ class VMHostDevsModel(object):
except AttributeError:
return []
- return [self._deduce_dev_name(e) for e in hostdev]
-
- @staticmethod
- def _toint(num_str):
- if num_str.startswith('0x'):
- return int(num_str, 16)
- elif num_str.startswith('0'):
- return int(num_str, 8)
- else:
- return int(num_str)
-
- def _deduce_dev_name(self, e):
- return getattr(self, '_deduce_dev_name_%s' %
e.attrib['type'])(e)
-
- def _deduce_dev_name_pci(self, e):
- attrib = {}
- for field in ('domain', 'bus', 'slot',
'function'):
- attrib[field] = self._toint(e.source.address.attrib[field])
- return 'pci_%(domain)04x_%(bus)02x_%(slot)02x_%(function)x' % attrib
-
- def _deduce_dev_name_scsi(self, e):
- attrib = {}
- for field in ('bus', 'target', 'unit'):
- attrib[field] = self._toint(e.source.address.attrib[field])
- attrib['host'] = self._toint(
- e.source.adapter.attrib['name'][len('scsi_host'):])
- return 'scsi_%(host)d_%(bus)d_%(target)d_%(unit)d' % attrib
-
- def _deduce_dev_name_usb(self, e):
- dev_names = DevicesModel(conn=self.conn).get_list(_cap='usb_device')
- usb_infos = [DeviceModel(conn=self.conn).lookup(dev_name)
- for dev_name in dev_names]
-
- unknown_dev = None
-
- try:
- evendor = self._toint(e.source.vendor.attrib['id'])
- eproduct = self._toint(e.source.product.attrib['id'])
- except AttributeError:
- evendor = 0
- eproduct = 0
- else:
- unknown_dev = 'usb_vendor_%s_product_%s' % (evendor, eproduct)
-
- try:
- ebus = self._toint(e.source.address.attrib['bus'])
- edevice = self._toint(e.source.address.attrib['device'])
- except AttributeError:
- ebus = -1
- edevice = -1
- else:
- unknown_dev = 'usb_bus_%s_device_%s' % (ebus, edevice)
-
- for usb_info in usb_infos:
- ivendor = self._toint(usb_info['vendor']['id'])
- iproduct = self._toint(usb_info['product']['id'])
- if evendor == ivendor and eproduct == iproduct:
- return usb_info['name']
- ibus = usb_info['bus']
- idevice = usb_info['device']
- if ebus == ibus and edevice == idevice:
- return usb_info['name']
- return unknown_dev
+ return [DeviceModel.deduce_dev_name(e, self.conn) for e in hostdev]
def _passthrough_device_validate(self, dev_name):
eligible_dev_names = \
@@ -290,10 +228,8 @@ class VMHostDevModel(object):
raise NotFoundError('KCHVMHDEV0001E',
{'vmid': vmid, 'dev_name': dev_name})
- devsmodel = VMHostDevsModel(conn=self.conn)
-
for e in hostdev:
- deduced_name = devsmodel._deduce_dev_name(e)
+ deduced_name = DeviceModel.deduce_dev_name(e, self.conn)
if deduced_name == dev_name:
return {'name': dev_name, 'type':
e.attrib['type']}
@@ -311,12 +247,11 @@ class VMHostDevModel(object):
raise NotFoundError('KCHVMHDEV0001E',
{'vmid': vmid, 'dev_name': dev_name})
- devsmodel = VMHostDevsModel(conn=self.conn)
- pci_devs = [(devsmodel._deduce_dev_name(e), e) for e in hostdev
- if e.attrib['type'] == 'pci']
+ pci_devs = [(DeviceModel.deduce_dev_name(e, self.conn), e)
+ for e in hostdev if e.attrib['type'] == 'pci']
for e in hostdev:
- if devsmodel._deduce_dev_name(e) == dev_name:
+ if DeviceModel.deduce_dev_name(e, self.conn) == dev_name:
xmlstr = etree.tostring(e)
dom.detachDeviceFlags(
xmlstr, get_vm_config_flag(dom, mode='all'))
--
2.4.3