[Kimchi-devel] [PATCH 1/3] Get available host passthrough devices: model changes

dhbarboza82 at gmail.com dhbarboza82 at gmail.com
Tue Jul 14 15:00:03 UTC 2015


From: Daniel Henrique Barboza <dhbarboza82 at 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 at 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




More information about the Kimchi-devel mailing list