[PATCH V4] [Kimchi 0/2] Issue #817 - PCI attach/detach improvements.

From: Paulo Vital <pvital@linux.vnet.ibm.com> V4: * Removed Libvirt events implementation. V3: * Fixed copyright line of new files. V2: This is the backend part of the solution to Issue #817. In this solution the support for handle Libvirt events is added, as well, the attach and detach functions were modified to return AsyncTasks (then frontend can be informed when a device is really attached/detached). Patch "Add support to Libvirt Events." is the third version of previous submitted patch. Patch "Make detach device return an AsyncTask" needs submitted Wok patch "Update AsyncResource class with delete method." to work. Paulo Vital (2): Make attach device return an AsyncTask Make detach device return an AsyncTask control/vm/hostdevs.py | 6 +-- model/vmhostdevs.py | 103 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 89 insertions(+), 20 deletions(-) -- 2.5.5

From: Paulo Vital <pvital@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@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 5f33d10..2927472 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 @@ -45,7 +46,9 @@ WINDOW_SIZE_BAR = 0x800000000 class VMHostDevsModel(object): def __init__(self, **kargs): self.conn = kargs['conn'] + self.objstore = kargs['objstore'] self.caps = CapabilitiesModel(**kargs) + self.task = TaskModel(**kargs) def get_list(self, vmid): dom = VMModel.get_vm(vmid, self.conn) @@ -70,7 +73,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: @@ -81,13 +88,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: @@ -162,7 +170,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) @@ -227,10 +238,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( @@ -241,7 +254,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 @@ -348,11 +361,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( @@ -365,11 +394,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) class VMHostDevModel(object): -- 2.5.5

From: Paulo Vital <pvital@linux.vnet.ibm.com> Modified VMHostDev class to be an AsyncResource and return an AsyncTask when deleting a specific resource (a.k.a. detach a device from a VM). This patch is part of the solution for Kimchi Issue #817 Signed-off-by: Paulo Vital <pvital@linux.vnet.ibm.com> --- control/vm/hostdevs.py | 4 ++-- model/vmhostdevs.py | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/control/vm/hostdevs.py b/control/vm/hostdevs.py index b0c4d1d..e9fd5dc 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 AsyncCollection, Resource +from wok.control.base import AsyncCollection, AsyncResource from wok.control.utils import UrlSubNode @@ -46,7 +46,7 @@ class VMHostDevs(AsyncCollection): }) -class VMHostDev(Resource): +class VMHostDev(AsyncResource): def __init__(self, model, vmid, ident): super(VMHostDev, self).__init__(model, ident) self.vmid = vmid diff --git a/model/vmhostdevs.py b/model/vmhostdevs.py index 2927472..7051324 100644 --- a/model/vmhostdevs.py +++ b/model/vmhostdevs.py @@ -420,6 +420,8 @@ class VMHostDevsModel(object): class VMHostDevModel(object): def __init__(self, **kargs): self.conn = kargs['conn'] + self.objstore = kargs['objstore'] + self.task = TaskModel(**kargs) def lookup(self, vmid, dev_name): dom = VMModel.get_vm(vmid, self.conn) @@ -457,6 +459,23 @@ class VMHostDevModel(object): raise NotFoundError('KCHVMHDEV0001E', {'vmid': vmid, 'dev_name': dev_name}) + task_params = {'vmid': vmid, + 'dev_name': dev_name, + 'dom': dom, + 'hostdev': hostdev} + task_uri = u'/plugins/kimchi/vms/%s/hostdevs/%s' % \ + (VMModel.get_vm(vmid, self.conn).name(), dev_name) + taskid = add_task(task_uri, self._detach_device, self.objstore, + task_params) + return self.task.lookup(taskid) + + def _detach_device(self, cb, params): + cb('Detaching device.') + vmid = params['vmid'] + dev_name = params['dev_name'] + dom = params['dom'] + hostdev = params['hostdev'] + pci_devs = [(DeviceModel.deduce_dev_name(e, self.conn), e) for e in hostdev if e.attrib['type'] == 'pci'] @@ -470,11 +489,14 @@ class VMHostDevModel(object): for e in hostdev: if DeviceModel.deduce_dev_name(e, self.conn) == dev_name: xmlstr = etree.tostring(e) + cb('Detaching device from VM...') dom.detachDeviceFlags( xmlstr, get_vm_config_flag(dom, mode='all')) if e.attrib['type'] == 'pci': + cb('Deleting affected PCI devices...') self._delete_affected_pci_devices(dom, dev_name, pci_devs) if is_3D_device: + cb('Updating MMIO from VM...') devsmodel = VMHostDevsModel(conn=self.conn) devsmodel.update_mmio_guest(vmid, False) break @@ -482,6 +504,8 @@ class VMHostDevModel(object): raise NotFoundError('KCHVMHDEV0001E', {'vmid': vmid, 'dev_name': dev_name}) + cb('OK', True) + def _delete_affected_pci_devices(self, dom, dev_name, pci_devs): dev_model = DeviceModel(conn=self.conn) try: -- 2.5.5
participants (2)
-
Aline Manera
-
pvital@linux.vnet.ibm.com