def get_control_rule_info(self, audit_info, name): try: msg_b = WokMessage("GINAUD0001M", None, "/plugins/ginger") text_b = msg_b.get_text(prepend_code=False, translate=True) msg_e = WokMessage("GINAUD0002M", None, "/plugins/ginger") text_e = msg_e.get_text(prepend_code=False, translate=True) msg_f = WokMessage("GINAUD0003M", None, "/plugins/ginger") text_f = msg_f.get_text(prepend_code=False, translate=True) msg_r = WokMessage("GINAUD0004M", None, "/plugins/ginger") text_r = msg_r.get_text(prepend_code=False, translate=True) msg_D = WokMessage("GINAUD0005M", None, "/plugins/ginger") text_D = msg_D.get_text(prepend_code=False, translate=True) control_rules_dict = {'-b': text_b, '-e': text_e, '-f': text_f, '-r': text_r, '-D': text_D} control_info = dict() control_info['rule_info'] = {} if name.split(" ")[0] != "-D": control_info['rule_info']['conf_value'] = name.split(" ")[1] control_info['rule_info']['conf_option'] = \ name.split(" ")[0] + ": " + \ control_rules_dict[name.split(" ")[0]] audit_info.update(control_info) except Exception, e: raise OperationFailed("GINAUD0007E", {"error": e.message})
def get_control_rule_info(self, audit_info, name): try: msg_b = WokMessage("GINAUD0001M", None, "/plugins/ginger") text_b = msg_b.get_text(prepend_code=False, translate=True) msg_e = WokMessage("GINAUD0002M", None, "/plugins/ginger") text_e = msg_e.get_text(prepend_code=False, translate=True) msg_f = WokMessage("GINAUD0003M", None, "/plugins/ginger") text_f = msg_f.get_text(prepend_code=False, translate=True) msg_r = WokMessage("GINAUD0004M", None, "/plugins/ginger") text_r = msg_r.get_text(prepend_code=False, translate=True) msg_D = WokMessage("GINAUD0005M", None, "/plugins/ginger") text_D = msg_D.get_text(prepend_code=False, translate=True) control_rules_dict = {'-b': text_b, '-e': text_e, '-f': text_f, '-r': text_r, '-D': text_D} control_info = dict() control_info['rule_info'] = {} if name.split(" ")[0] != "-D": control_info['rule_info']['conf_value'] = name.split(" ")[1] control_info['rule_info']['conf_option'] = \ name.split(" ")[0] + ": " + \ control_rules_dict[name.split(" ")[0]] audit_info.update(control_info) except Exception as e: raise OperationFailed("GINAUD0007E", {"error": e.message})
def getTranslatedMessage(self, message, error, app_root): code = message.get('code', '') params = message.get('params', {}) msg = WokMessage(code, params, app_root) text = msg.get_text(prepend_code=False, translate=True) if error: code = error.get('code', '') params = error.get('params', {}) msg = WokMessage(code, params, app_root) text += ' (%s)' % msg.get_text(prepend_code=True, translate=True) return text
def _detach_device(self, cb, params): cb('Detaching device') self._cb = cb vmid = params['vmid'] dev_name = params['dev_name'] dom = params['dom'] hostdev = params['hostdev'] lock = params['lock'] with lock: pci_devs = [(DeviceModel.deduce_dev_name(e, self.conn), e) for e in hostdev if e.attrib['type'] == 'pci'] dev_info = self.dev_model.lookup(dev_name) is_3D_device = self.dev_model.is_device_3D_controller(dev_info) if is_3D_device and DOM_STATE_MAP[dom.info()[0]] != "shutoff": raise InvalidOperation('KCHVMHDEV0006E', {'name': dev_info['name']}) # check for multifunction and detach all functions together try: multi = self._unplug_multifunction_pci(dom, hostdev, dev_name) except libvirt.libvirtError: multi = False # successfully detached all functions: finish operation if multi: if is_3D_device: devsmodel = VMHostDevsModel(conn=self.conn) devsmodel.update_mmio_guest(vmid, False) if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True) return # detach each function individually for e in hostdev: if DeviceModel.deduce_dev_name(e, self.conn) == dev_name: xmlstr = etree.tostring(e) dom.detachDeviceFlags( xmlstr, get_vm_config_flag(dom, mode='all')) if e.attrib['type'] == 'pci': self._delete_affected_pci_devices(dom, dev_name, pci_devs) if is_3D_device: devsmodel = VMHostDevsModel(conn=self.conn) devsmodel.update_mmio_guest(vmid, False) break else: msg = WokMessage('KCHVMHDEV0001E', {'vmid': vmid, 'dev_name': dev_name}) cb(msg.get_text(), False) raise NotFoundError('KCHVMHDEV0001E', {'vmid': vmid, 'dev_name': dev_name}) if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True)
def event_enospc_cb(self, conn, dom, path, dev, action, reason, args): if reason == "enospc": info = { "vm": dom.name(), "srcPath": path, "devAlias": dev, } add_notification("KCHEVENT0004W", info, '/plugins/kimchi') msg = WokMessage("KCHEVENT0004W", info, '/plugins/kimchi') wok_log.warning(msg.get_text())
def _attach_multifunction_devices(self, dom, pci_infos, driver, vmid): slot = 0 is_multifunction = len(pci_infos) > 1 device_flags = get_vm_config_flag(dom, mode='all') with RollbackContext() as rollback: # multifuction: try to attach all functions together within one # xml file. It requires libvirt support. if is_multifunction: # search for the first available slot in guest xml slot = self._available_slot(dom) xmlstr = self._get_pci_devices_xml(pci_infos, slot, driver) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: # If operation fails, we try the other way, where each # function is attached individually pass else: rollback.prependDefer( dom.detachDeviceFlags, xmlstr, device_flags ) rollback.commitAll() if DOM_STATE_MAP[dom.info()[0]] == 'shutoff': self._cb('OK', True) return # attach each function individually (multi or single function) for pci_info in pci_infos: pci_info['detach_driver'] = driver xmlstr = self._get_pci_device_xml( pci_info, slot, is_multifunction) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: msg = WokMessage( 'KCHVMHDEV0007E', { 'device': pci_info['name'], 'vm': vmid} ) self._cb(msg.get_text(), False) wok_log.error( 'Failed to attach host device %s to VM %s: \n%s', pci_info['name'], vmid, xmlstr, ) raise rollback.prependDefer( dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll()
def _detach_device(self, cb, params): cb('Detaching device') self._cb = cb vmid = params['vmid'] dev_name = params['dev_name'] dom = params['dom'] hostdev = params['hostdev'] lock = params['lock'] with lock: pci_devs = [(DeviceModel.deduce_dev_name(e, self.conn), e) for e in hostdev if e.attrib['type'] == 'pci'] dev_info = self.dev_model.lookup(dev_name) is_3D_device = self.dev_model.is_device_3D_controller(dev_info) if is_3D_device and DOM_STATE_MAP[dom.info()[0]] != "shutoff": raise InvalidOperation('KCHVMHDEV0006E', {'name': dev_info['name']}) if self._hotunplug_multifunction_pci(dom, hostdev, dev_name): if is_3D_device: devsmodel = VMHostDevsModel(conn=self.conn) devsmodel.update_mmio_guest(vmid, False) if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True) return for e in hostdev: if DeviceModel.deduce_dev_name(e, self.conn) == dev_name: xmlstr = etree.tostring(e) dom.detachDeviceFlags(xmlstr, get_vm_config_flag(dom, mode='all')) if e.attrib['type'] == 'pci': self._delete_affected_pci_devices( dom, dev_name, pci_devs) if is_3D_device: devsmodel = VMHostDevsModel(conn=self.conn) devsmodel.update_mmio_guest(vmid, False) break else: msg = WokMessage('KCHVMHDEV0001E', { 'vmid': vmid, 'dev_name': dev_name }) cb(msg.get_text(), False) raise NotFoundError('KCHVMHDEV0001E', { 'vmid': vmid, 'dev_name': dev_name }) if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True)
def _attach_all_devices(self, pci_infos): with RollbackContext() as rollback: for pci_info in pci_infos: try: dev = self.conn.get().nodeDeviceLookupByName( pci_info['name']) dev.dettach() except Exception: msg = WokMessage('KCHVMHDEV0005E', {'name': pci_info['name']}) self._cb(msg.get_text(), False) raise OperationFailed('KCHVMHDEV0005E', {'name': pci_info['name']}) else: rollback.prependDefer(dev.reAttach) rollback.commitAll()
def _attach_all_devices(self, pci_infos): with RollbackContext() as rollback: for pci_info in pci_infos: try: dev = self.conn.get().nodeDeviceLookupByName( pci_info['name']) dev.dettach() except Exception: msg = WokMessage('KCHVMHDEV0005E', { 'name': pci_info['name']}) self._cb(msg.get_text(), False) raise OperationFailed( 'KCHVMHDEV0005E', {'name': pci_info['name']} ) else: rollback.prependDefer(dev.reAttach) rollback.commitAll()
def _attach_scsi_device(self, cb, params): cb('Attaching SCSI device...') self._cb = cb vmid = params['vmid'] dev_info = params['dev_info'] lock = params['lock'] try: self._passthrough_device_validate(dev_info['name']) except InvalidParameter as e: cb(str(e), False) raise with lock: dom = VMModel.get_vm(vmid, self.conn) with RollbackContext() as rollback: 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: msg = WokMessage( 'KCHVMHDEV0007E', { 'device': dev_info['name'], 'vm': vmid} ) cb(msg.get_text(), False) 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() if DOM_STATE_MAP[dom.info()[0]] == 'shutoff': cb('OK', True)
def _attach_pci_device(self, cb, params): cb('Attaching PCI device') self._cb = cb vmid = params['vmid'] dev_info = params['dev_info'] lock = params['lock'] try: self._passthrough_device_validate(dev_info['name']) except InvalidParameter as e: cb(e.message, False) raise with lock: try: self._validate_pci_passthrough_env() except InvalidOperation as e: cb(e.message, False) raise dom = VMModel.get_vm(vmid, self.conn) driver = 'vfio' if self.caps.kernel_vfio else 'kvm' # 'vfio' systems requires a usb controller in order to support pci # hotplug on Power. if driver == 'vfio' and platform.machine().startswith('ppc') and \ DOM_STATE_MAP[dom.info()[0]] != "shutoff" and \ not self.have_usb_controller(vmid): msg = WokMessage('KCHVMHDEV0008E', {'vmid': vmid}) cb(msg.get_text(), False) raise InvalidOperation("KCHVMHDEV0008E", {'vmid': vmid}) # Attach all PCI devices in the same IOMMU group affected_names = self.devs_model.get_list( _passthrough_affected_by=dev_info['name']) passthrough_names = self.devs_model.get_list( _cap='pci', _passthrough='true') group_names = list(set(affected_names) & set(passthrough_names)) pci_infos = [self.dev_model.lookup(dev_name) for dev_name in group_names] pci_infos.append(dev_info) is_multifunction = len(pci_infos) > 1 pci_infos = sorted(pci_infos, key=itemgetter('name')) # does not allow hot-plug of 3D graphic cards is_3D_device = self.dev_model.is_device_3D_controller(dev_info) if is_3D_device and DOM_STATE_MAP[dom.info()[0]] != "shutoff": msg = WokMessage('KCHVMHDEV0006E', {'name': dev_info['name']}) cb(msg.get_text(), False) raise InvalidOperation('KCHVMHDEV0006E', {'name': dev_info['name']}) # all devices in the group that is going to be attached to the vm # must be detached from the host first with RollbackContext() as rollback: for pci_info in pci_infos: try: dev = self.conn.get().nodeDeviceLookupByName( pci_info['name']) dev.dettach() except Exception: msg = WokMessage('KCHVMHDEV0005E', {'name': pci_info['name']}) cb(msg.get_text(), False) raise OperationFailed('KCHVMHDEV0005E', {'name': pci_info['name']}) else: rollback.prependDefer(dev.reAttach) rollback.commitAll() device_flags = get_vm_config_flag(dom, mode='all') # when attaching a 3D graphic device it might be necessary to # increase the window size memory in order to be able to attach # more than one device to the same guest if is_3D_device: self.update_mmio_guest(vmid, True) slot = 0 if is_multifunction: # search for the first available slot in guest xml slot = self._available_slot(dom) with RollbackContext() as rollback: # multifuction: try to attach all functions together within one # xml file. It requires libvirt support. if is_multifunction: xmlstr = self._get_pci_devices_xml(pci_infos, slot, driver) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: # If operation fails, we try the other way, where each # function is attached individually pass else: rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True) return # attach each function individually (multi or single function) for pci_info in pci_infos: pci_info['detach_driver'] = driver xmlstr = self._get_pci_device_xml(pci_info, slot, is_multifunction) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: msg = WokMessage('KCHVMHDEV0007E', {'device': pci_info['name'], 'vm': vmid}) cb(msg.get_text(), False) wok_log.error( 'Failed to attach host device %s to VM %s: \n%s', pci_info['name'], vmid, xmlstr) raise rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True)
def event_enospc_cb(self, conn, dom, path, dev, action, reason, args): if reason == 'enospc': info = {'vm': dom.name(), 'srcPath': path, 'devAlias': dev} add_notification('KCHEVENT0004W', info, '/plugins/kimchi') msg = WokMessage('KCHEVENT0004W', info, '/plugins/kimchi') wok_log.warning(msg.get_text())
def _attach_pci_device(self, cb, params): cb('Attaching PCI device') self._cb = cb vmid = params['vmid'] dev_info = params['dev_info'] lock = params['lock'] try: self._passthrough_device_validate(dev_info['name']) except InvalidParameter as e: cb(e.message, False) raise with lock: try: self._validate_pci_passthrough_env() except InvalidOperation as e: cb(e.message, False) raise dom = VMModel.get_vm(vmid, self.conn) # Due to libvirt limitation, we don't support live assigne device # to vfio driver. driver = ('vfio' if DOM_STATE_MAP[dom.info()[0]] == "shutoff" and self.caps.kernel_vfio else 'kvm') # on powerkvm systems it must be vfio driver. distro, _, _ = platform.linux_distribution() if distro == 'IBM_PowerKVM': driver = 'vfio' # Attach all PCI devices in the same IOMMU group affected_names = self.devs_model.get_list( _passthrough_affected_by=dev_info['name']) passthrough_names = self.devs_model.get_list( _cap='pci', _passthrough='true') group_names = list(set(affected_names) & set(passthrough_names)) pci_infos = [self.dev_model.lookup(dev_name) for dev_name in group_names] pci_infos.append(dev_info) is_multifunction = len(pci_infos) > 1 pci_infos = sorted(pci_infos, key=itemgetter('name')) # does not allow hot-plug of 3D graphic cards is_3D_device = self.dev_model.is_device_3D_controller(dev_info) if is_3D_device and DOM_STATE_MAP[dom.info()[0]] != "shutoff": msg = WokMessage('KCHVMHDEV0006E', {'name': dev_info['name']}) cb(msg.get_text(), False) raise InvalidOperation('KCHVMHDEV0006E', {'name': dev_info['name']}) # all devices in the group that is going to be attached to the vm # must be detached from the host first with RollbackContext() as rollback: for pci_info in pci_infos: try: dev = self.conn.get().nodeDeviceLookupByName( pci_info['name']) dev.dettach() except Exception: msg = WokMessage('KCHVMHDEV0005E', {'name': pci_info['name']}) cb(msg.get_text(), False) raise OperationFailed('KCHVMHDEV0005E', {'name': pci_info['name']}) else: rollback.prependDefer(dev.reAttach) rollback.commitAll() device_flags = get_vm_config_flag(dom, mode='all') # when attaching a 3D graphic device it might be necessary to # increase the window size memory in order to be able to attach # more than one device to the same guest if is_3D_device: self.update_mmio_guest(vmid, True) slot = 0 if is_multifunction: # search for the first available slot in guest xml slot = self._available_slot(dom) with RollbackContext() as rollback: # multifunction hotplug is a special case where all functions # must be attached together within one xml file, the same does # not happen to multifunction coldplug - where each function # is attached individually if DOM_STATE_MAP[dom.info()[0]] != 'shutoff' and \ is_multifunction: xmlstr = self._get_pci_devices_xml(pci_infos, slot, driver) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: msg = WokMessage('KCHVMHDEV0007E', {'device': pci_info['name'], 'vm': vmid}) cb(msg.get_text(), False) wok_log.error( 'Failed to attach mutifunction device VM %s: \n%s', vmid, xmlstr) raise rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True) return for pci_info in pci_infos: pci_info['detach_driver'] = driver xmlstr = self._get_pci_device_xml(pci_info, slot, is_multifunction) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: msg = WokMessage('KCHVMHDEV0007E', {'device': pci_info['name'], 'vm': vmid}) cb(msg.get_text(), False) wok_log.error( 'Failed to attach host device %s to VM %s: \n%s', pci_info['name'], vmid, xmlstr) raise rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True)
'PUT': self.update}[method](*args, **kargs) status = cherrypy.response.status except WokException, e: status = e.getHttpStatusCode() raise cherrypy.HTTPError(status, e.message) except cherrypy.HTTPError, e: status = e.status raise finally: # log request if method not in LOG_DISABLED_METHODS: code = self.getRequestMessage(method) msg = WokMessage(code, self.log_args) RequestRecord( msg.get_text(prepend_code=False), app=get_plugin_from_request(), req=method, status=status, user=cherrypy.session.get(USER_NAME, 'N/A'), ip=cherrypy.request.remote.ip ).log() return result def is_authorized(self): user_name = cherrypy.session.get(USER_NAME, '') user_groups = cherrypy.session.get(USER_GROUPS, []) user_role = cherrypy.session.get(USER_ROLES, {}).get(self.role_key) users = self.data.get("users", None)
def _attach_pci_device(self, cb, params): cb('Attaching PCI device') self._cb = cb vmid = params['vmid'] dev_info = params['dev_info'] lock = params['lock'] try: self._passthrough_device_validate(dev_info['name']) except InvalidParameter as e: cb(str(e), False) raise with lock: try: self._validate_pci_passthrough_env() except InvalidOperation as e: cb(str(e), False) raise dom = VMModel.get_vm(vmid, self.conn) driver = 'vfio' if self.caps.kernel_vfio else 'kvm' # 'vfio' systems requires a usb controller in order to support pci # hotplug on Power. if ( driver == 'vfio' and platform.machine().startswith('ppc') and DOM_STATE_MAP[dom.info()[0]] != 'shutoff' and not self.have_usb_controller(vmid) ): msg = WokMessage('KCHVMHDEV0008E', {'vmid': vmid}) cb(msg.get_text(), False) raise InvalidOperation('KCHVMHDEV0008E', {'vmid': vmid}) # Attach all PCI devices in the same IOMMU group affected_names = self.devs_model.get_list( _passthrough_affected_by=dev_info['name'] ) passthrough_names = self.devs_model.get_list( _cap='pci', _passthrough='true' ) group_names = list(set(affected_names) & set(passthrough_names)) pci_infos = [self.dev_model.lookup( dev_name) for dev_name in group_names] pci_infos.append(dev_info) pci_infos = sorted(pci_infos, key=itemgetter('name')) # does not allow hot-plug of 3D graphic cards is_3D_device = self.dev_model.is_device_3D_controller(dev_info) if is_3D_device and DOM_STATE_MAP[dom.info()[0]] != 'shutoff': msg = WokMessage('KCHVMHDEV0006E', {'name': dev_info['name']}) cb(msg.get_text(), False) raise InvalidOperation( 'KCHVMHDEV0006E', {'name': dev_info['name']}) # all devices in the group that is going to be attached to the vm # must be detached from the host first self._attach_all_devices(pci_infos) # when attaching a 3D graphic device it might be necessary to # increase the window size memory in order to be able to attach # more than one device to the same guest if is_3D_device: self.update_mmio_guest(vmid, True) self._attach_multifunction_devices(dom, pci_infos, driver, vmid) if DOM_STATE_MAP[dom.info()[0]] == 'shutoff': cb('OK', True)
def _attach_pci_device(self, cb, params): cb('Attaching PCI device') self._cb = cb vmid = params['vmid'] dev_info = params['dev_info'] lock = params['lock'] try: self._passthrough_device_validate(dev_info['name']) except InvalidParameter as e: cb(e.message, False) raise with lock: try: self._validate_pci_passthrough_env() except InvalidOperation as e: cb(e.message, False) raise dom = VMModel.get_vm(vmid, self.conn) driver = 'vfio' if self.caps.kernel_vfio else 'kvm' # 'vfio' systems requires a usb controller in order to support pci # hotplug on Power. if driver == 'vfio' and platform.machine().startswith('ppc') and \ DOM_STATE_MAP[dom.info()[0]] != "shutoff" and \ not self.have_usb_controller(vmid): msg = WokMessage('KCHVMHDEV0008E', {'vmid': vmid}) cb(msg.get_text(), False) raise InvalidOperation("KCHVMHDEV0008E", {'vmid': vmid}) # Attach all PCI devices in the same IOMMU group affected_names = self.devs_model.get_list( _passthrough_affected_by=dev_info['name']) passthrough_names = self.devs_model.get_list(_cap='pci', _passthrough='true') group_names = list(set(affected_names) & set(passthrough_names)) pci_infos = [ self.dev_model.lookup(dev_name) for dev_name in group_names ] pci_infos.append(dev_info) is_multifunction = len(pci_infos) > 1 pci_infos = sorted(pci_infos, key=itemgetter('name')) # does not allow hot-plug of 3D graphic cards is_3D_device = self.dev_model.is_device_3D_controller(dev_info) if is_3D_device and DOM_STATE_MAP[dom.info()[0]] != "shutoff": msg = WokMessage('KCHVMHDEV0006E', {'name': dev_info['name']}) cb(msg.get_text(), False) raise InvalidOperation('KCHVMHDEV0006E', {'name': dev_info['name']}) # all devices in the group that is going to be attached to the vm # must be detached from the host first with RollbackContext() as rollback: for pci_info in pci_infos: try: dev = self.conn.get().nodeDeviceLookupByName( pci_info['name']) dev.dettach() except Exception: msg = WokMessage('KCHVMHDEV0005E', {'name': pci_info['name']}) cb(msg.get_text(), False) raise OperationFailed('KCHVMHDEV0005E', {'name': pci_info['name']}) else: rollback.prependDefer(dev.reAttach) rollback.commitAll() device_flags = get_vm_config_flag(dom, mode='all') # when attaching a 3D graphic device it might be necessary to # increase the window size memory in order to be able to attach # more than one device to the same guest if is_3D_device: self.update_mmio_guest(vmid, True) slot = 0 if is_multifunction: # search for the first available slot in guest xml slot = self._available_slot(dom) with RollbackContext() as rollback: # multifuction: try to attach all functions together within one # xml file. It requires libvirt support. if is_multifunction: xmlstr = self._get_pci_devices_xml(pci_infos, slot, driver) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: # If operation fails, we try the other way, where each # function is attached individually pass else: rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True) return # attach each function individually (multi or single function) for pci_info in pci_infos: pci_info['detach_driver'] = driver xmlstr = self._get_pci_device_xml(pci_info, slot, is_multifunction) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: msg = WokMessage('KCHVMHDEV0007E', { 'device': pci_info['name'], 'vm': vmid }) cb(msg.get_text(), False) wok_log.error( 'Failed to attach host device %s to VM %s: \n%s', pci_info['name'], vmid, xmlstr) raise rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True)
def _attach_pci_device(self, cb, params): cb('Attaching PCI device') self._cb = cb vmid = params['vmid'] dev_info = params['dev_info'] lock = params['lock'] try: self._passthrough_device_validate(dev_info['name']) except InvalidParameter as e: cb(e.message, False) raise with lock: try: self._validate_pci_passthrough_env() except InvalidOperation as e: cb(e.message, False) raise dom = VMModel.get_vm(vmid, self.conn) # Due to libvirt limitation, we don't support live assigne device # to vfio driver. driver = ('vfio' if DOM_STATE_MAP[dom.info()[0]] == "shutoff" and self.caps.kernel_vfio else 'kvm') # on powerkvm systems it must be vfio driver. distro, _, _ = platform.linux_distribution() if distro == 'IBM_PowerKVM': driver = 'vfio' # Attach all PCI devices in the same IOMMU group affected_names = self.devs_model.get_list( _passthrough_affected_by=dev_info['name']) passthrough_names = self.devs_model.get_list(_cap='pci', _passthrough='true') group_names = list(set(affected_names) & set(passthrough_names)) pci_infos = [ self.dev_model.lookup(dev_name) for dev_name in group_names ] pci_infos.append(dev_info) is_multifunction = len(pci_infos) > 1 pci_infos = sorted(pci_infos, key=itemgetter('name')) # does not allow hot-plug of 3D graphic cards is_3D_device = self.dev_model.is_device_3D_controller(dev_info) if is_3D_device and DOM_STATE_MAP[dom.info()[0]] != "shutoff": msg = WokMessage('KCHVMHDEV0006E', {'name': dev_info['name']}) cb(msg.get_text(), False) raise InvalidOperation('KCHVMHDEV0006E', {'name': dev_info['name']}) # all devices in the group that is going to be attached to the vm # must be detached from the host first with RollbackContext() as rollback: for pci_info in pci_infos: try: dev = self.conn.get().nodeDeviceLookupByName( pci_info['name']) dev.dettach() except Exception: msg = WokMessage('KCHVMHDEV0005E', {'name': pci_info['name']}) cb(msg.get_text(), False) raise OperationFailed('KCHVMHDEV0005E', {'name': pci_info['name']}) else: rollback.prependDefer(dev.reAttach) rollback.commitAll() device_flags = get_vm_config_flag(dom, mode='all') # when attaching a 3D graphic device it might be necessary to # increase the window size memory in order to be able to attach # more than one device to the same guest if is_3D_device: self.update_mmio_guest(vmid, True) slot = 0 if is_multifunction: # search for the first available slot in guest xml slot = self._available_slot(dom) with RollbackContext() as rollback: # multifunction hotplug is a special case where all functions # must be attached together within one xml file, the same does # not happen to multifunction coldplug - where each function # is attached individually if DOM_STATE_MAP[dom.info()[0]] != 'shutoff' and \ is_multifunction: xmlstr = self._get_pci_devices_xml(pci_infos, slot, driver) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: msg = WokMessage('KCHVMHDEV0007E', { 'device': pci_info['name'], 'vm': vmid }) cb(msg.get_text(), False) wok_log.error( 'Failed to attach mutifunction device VM %s: \n%s', vmid, xmlstr) raise rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True) return for pci_info in pci_infos: pci_info['detach_driver'] = driver xmlstr = self._get_pci_device_xml(pci_info, slot, is_multifunction) try: dom.attachDeviceFlags(xmlstr, device_flags) except libvirt.libvirtError: msg = WokMessage('KCHVMHDEV0007E', { 'device': pci_info['name'], 'vm': vmid }) cb(msg.get_text(), False) wok_log.error( 'Failed to attach host device %s to VM %s: \n%s', pci_info['name'], vmid, xmlstr) raise rollback.prependDefer(dom.detachDeviceFlags, xmlstr, device_flags) rollback.commitAll() if DOM_STATE_MAP[dom.info()[0]] == "shutoff": cb('OK', True)