[Kimchi-devel] [PATCH] [Kimchi 3/4] Make attach device return an AsyncTask

pvital at linux.vnet.ibm.com pvital at linux.vnet.ibm.com
Thu Apr 14 21:36:56 UTC 2016


From: Paulo Vital <pvital at linux.vnet.ibm.com>

Modified VMHostDevs class to be an AsyncCollection and return an AsyncTask when
creating a new resource (a.k.a. attach a device into a VM).

This patch is part of the solution for Kimchi Issue #817

Signed-off-by: Paulo Vital <pvital at linux.vnet.ibm.com>
---
 control/vm/hostdevs.py |  4 +--
 model/vmhostdevs.py    | 79 +++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 64 insertions(+), 19 deletions(-)

diff --git a/control/vm/hostdevs.py b/control/vm/hostdevs.py
index 8a82db0..b0c4d1d 100644
--- a/control/vm/hostdevs.py
+++ b/control/vm/hostdevs.py
@@ -17,7 +17,7 @@
 # License along with this library; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 
-from wok.control.base import Collection, Resource
+from wok.control.base import AsyncCollection, Resource
 from wok.control.utils import UrlSubNode
 
 
@@ -33,7 +33,7 @@ VMHOSTDEV_REQUESTS = {
 
 
 @UrlSubNode("hostdevs")
-class VMHostDevs(Collection):
+class VMHostDevs(AsyncCollection):
     def __init__(self, model, vmid):
         super(VMHostDevs, self).__init__(model)
         self.resource = VMHostDev
diff --git a/model/vmhostdevs.py b/model/vmhostdevs.py
index 9d1d702..0cdf032 100644
--- a/model/vmhostdevs.py
+++ b/model/vmhostdevs.py
@@ -27,8 +27,9 @@ from operator import itemgetter
 
 from wok.exception import InvalidOperation, InvalidParameter, NotFoundError
 from wok.exception import OperationFailed
+from wok.model.tasks import TaskModel
 from wok.rollbackcontext import RollbackContext
-from wok.utils import run_command, wok_log
+from wok.utils import add_task, run_command, wok_log
 
 from wok.plugins.kimchi.model.config import CapabilitiesModel
 from wok.plugins.kimchi.model.host import DeviceModel, DevicesModel
@@ -46,7 +47,9 @@ class VMHostDevsModel(object):
     def __init__(self, **kargs):
         self.conn = kargs['conn']
         self.events = kargs['eventsloop']
+        self.objstore = kargs['objstore']
         self.caps = CapabilitiesModel(**kargs)
+        self.task = TaskModel(**kargs)
         self._register_device_event()
 
     def get_list(self, vmid):
@@ -72,7 +75,11 @@ class VMHostDevsModel(object):
         dev_info = DeviceModel(conn=self.conn).lookup(dev_name)
 
         if dev_info['device_type'] == 'pci':
-            return self._attach_pci_device(vmid, dev_info)
+            taskid = add_task(u'/plugins/kimchi/vms/%s/hostdevs/' %
+                              VMModel.get_vm(vmid, self.conn).name(),
+                              self._attach_pci_device, self.objstore,
+                              {'vmid': vmid, 'dev_info': dev_info})
+            return self.task.lookup(taskid)
 
         with RollbackContext() as rollback:
             try:
@@ -83,13 +90,14 @@ class VMHostDevsModel(object):
             else:
                 rollback.prependDefer(dev.reAttach)
 
-            attach_device = getattr(
-                self, '_attach_%s_device' % dev_info['device_type'])
-
-            info = attach_device(vmid, dev_info)
             rollback.commitAll()
 
-        return info
+        taskid = add_task(u'/plugins/kimchi/vms/%s/hostdevs/' %
+                          VMModel.get_vm(vmid, self.conn).name(),
+                          '_attach_%s_device' % dev_info['device_type'],
+                          self.objstore, {'vmid': vmid, 'dev_info': dev_info})
+
+        return self.task.lookup(taskid)
 
     def _get_pci_device_xml(self, dev_info, slot, is_multifunction):
         if 'detach_driver' not in dev_info:
@@ -164,7 +172,10 @@ class VMHostDevsModel(object):
 
         return free+1
 
-    def _attach_pci_device(self, vmid, dev_info):
+    def _attach_pci_device(self, cb, params):
+        cb('Attaching PCI device')
+        vmid = params['vmid']
+        dev_info = params['dev_info']
         self._validate_pci_passthrough_env()
 
         dom = VMModel.get_vm(vmid, self.conn)
@@ -229,10 +240,12 @@ class VMHostDevsModel(object):
         with RollbackContext() as rollback:
             for pci_info in pci_infos:
                 pci_info['detach_driver'] = driver
+                cb('Reading source device XML')
                 xmlstr = self._get_pci_device_xml(pci_info,
                                                   slot,
                                                   is_multifunction)
                 try:
+                    cb('Attaching device to VM')
                     dom.attachDeviceFlags(xmlstr, device_flags)
                 except libvirt.libvirtError:
                     wok_log.error(
@@ -243,7 +256,7 @@ class VMHostDevsModel(object):
                                       xmlstr, device_flags)
             rollback.commitAll()
 
-        return dev_info['name']
+        cb('OK', True)
 
     def _count_3D_devices_attached(self, dom):
         counter = 0
@@ -350,11 +363,27 @@ class VMHostDevsModel(object):
                              mode='subsystem', type='scsi', sgio='unfiltered')
         return etree.tostring(host_dev)
 
-    def _attach_scsi_device(self, vmid, dev_info):
-        xmlstr = self._get_scsi_device_xml(dev_info)
+    def _attach_scsi_device(self, cb, params):
+        cb('Attaching SCSI device...')
+        vmid = params['vmid']
+        dev_info = params['dev_info']
         dom = VMModel.get_vm(vmid, self.conn)
-        dom.attachDeviceFlags(xmlstr, get_vm_config_flag(dom, mode='all'))
-        return dev_info['name']
+
+        with RollbackContext() as rollback:
+            cb('Reading source device XML')
+            xmlstr = self._get_scsi_device_xml(dev_info)
+            device_flags = get_vm_config_flag(dom, mode='all')
+            try:
+                cb('Attaching device to VM')
+                dom.attachDeviceFlags(xmlstr, device_flags)
+            except libvirt.libvirtError:
+                wok_log.error('Failed to attach host device %s to VM %s: \n%s',
+                              dev_info['name'], vmid, xmlstr)
+                raise
+            rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags)
+            rollback.commitAll()
+
+        cb('OK', True)
 
     def _get_usb_device_xml(self, dev_info):
         source = E.source(
@@ -367,11 +396,27 @@ class VMHostDevsModel(object):
                              ype='usb', managed='yes')
         return etree.tostring(host_dev)
 
-    def _attach_usb_device(self, vmid, dev_info):
-        xmlstr = self._get_usb_device_xml(dev_info)
+    def _attach_usb_device(self, cb, params):
+        cb('Attaching USB device...')
+        vmid = params['vmid']
+        dev_info = params['dev_info']
         dom = VMModel.get_vm(vmid, self.conn)
-        dom.attachDeviceFlags(xmlstr, get_vm_config_flag(dom, mode='all'))
-        return dev_info['name']
+
+        with RollbackContext() as rollback:
+            cb('Reading source device XML')
+            xmlstr = self._get_usb_device_xml(dev_info)
+            device_flags = get_vm_config_flag(dom, mode='all')
+            try:
+                cb('Attaching device to VM')
+                dom.attachDeviceFlags(xmlstr, device_flags)
+            except libvirt.libvirtError:
+                wok_log.error('Failed to attach host device %s to VM %s: \n%s',
+                              dev_info['name'], vmid, xmlstr)
+                raise
+            rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags)
+            rollback.commitAll()
+
+        cb('OK', True)
 
     def _vm_event_device_added_cb(self, conn, dom, dev, opaque):
         """
-- 
2.5.5




More information about the Kimchi-devel mailing list