Merge "libvirt: introduce method detach_device to Guest object"
This commit is contained in:
commit
6085d1e877
|
@ -607,7 +607,7 @@ class Domain(object):
|
|||
disk_info['_attached'] = True
|
||||
return disk_info in self._def['devices']['disks']
|
||||
|
||||
def detachDeviceFlags(self, xml, _flags):
|
||||
def detachDeviceFlags(self, xml, flags):
|
||||
self.detachDevice(xml)
|
||||
|
||||
def XMLDesc(self, flags):
|
||||
|
|
|
@ -808,14 +808,15 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
|||
lambda x, y: FakeDev()
|
||||
|
||||
class FakeDomain(object):
|
||||
def detachDeviceFlags(self, xml, flag):
|
||||
def detachDeviceFlags(self, xml, flags):
|
||||
pci_devices[0]['hypervisor_name'] = 'marked'
|
||||
pass
|
||||
|
||||
def XMLDesc(self, flag):
|
||||
return fake_domXML1
|
||||
|
||||
drvr._detach_pci_devices(FakeDomain(), pci_devices)
|
||||
guest = libvirt_guest.Guest(FakeDomain())
|
||||
drvr._detach_pci_devices(guest, pci_devices)
|
||||
self.assertEqual(pci_devices[0]['hypervisor_name'], 'marked')
|
||||
|
||||
def test_detach_pci_devices_timeout(self):
|
||||
|
@ -852,13 +853,15 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
|||
lambda x, y: FakeDev()
|
||||
|
||||
class FakeDomain(object):
|
||||
def detachDeviceFlags(self, xml, flag):
|
||||
def detachDeviceFlags(self, xml, flags):
|
||||
pass
|
||||
|
||||
def XMLDesc(self, flag):
|
||||
return fake_domXML1
|
||||
|
||||
guest = libvirt_guest.Guest(FakeDomain())
|
||||
self.assertRaises(exception.PciDeviceDetachFailed,
|
||||
drvr._detach_pci_devices, FakeDomain(), pci_devices)
|
||||
drvr._detach_pci_devices, guest, pci_devices)
|
||||
|
||||
def test_get_connector(self):
|
||||
initiator = 'fake.initiator.iqn'
|
||||
|
@ -4704,7 +4707,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
|||
<source file="/path/to/fake-volume"/>
|
||||
<target bus="virtio" dev="vdc"/>
|
||||
</disk>
|
||||
""", flags)
|
||||
""", flags=flags)
|
||||
mock_disconnect_volume.assert_called_with(
|
||||
connection_info, 'vdc')
|
||||
|
||||
|
@ -8288,8 +8291,9 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
|||
|
||||
domain = FakeVirtDomain()
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
|
||||
guest = libvirt_guest.Guest(domain)
|
||||
|
||||
drvr._detach_sriov_ports(self.context, instance, domain)
|
||||
drvr._detach_sriov_ports(self.context, instance, guest)
|
||||
mock_get_image_metadata.assert_called_once_with(
|
||||
instance.system_metadata)
|
||||
self.assertTrue(mock_detachDeviceFlags.called)
|
||||
|
|
|
@ -228,3 +228,47 @@ class GuestTestCase(test.NoDBTestCase):
|
|||
domain.attachDeviceFlags.assert_called_once_with(
|
||||
"</xml>", flags=(fakelibvirt.VIR_DOMAIN_AFFECT_CONFIG |
|
||||
fakelibvirt.VIR_DOMAIN_AFFECT_LIVE))
|
||||
|
||||
def test_detach_device(self):
|
||||
domain = mock.Mock(spec=fakelibvirt.virDomain)
|
||||
conf = mock.Mock(spec=vconfig.LibvirtConfigGuestDevice)
|
||||
conf.to_xml.return_value = "</xml>"
|
||||
|
||||
guest = libvirt_guest.Guest(domain)
|
||||
guest.detach_device(conf)
|
||||
|
||||
domain.detachDeviceFlags.assert_called_once_with("</xml>", flags=0)
|
||||
|
||||
def test_detach_device_persistent(self):
|
||||
domain = mock.Mock(spec=fakelibvirt.virDomain)
|
||||
conf = mock.Mock(spec=vconfig.LibvirtConfigGuestDevice)
|
||||
conf.to_xml.return_value = "</xml>"
|
||||
|
||||
guest = libvirt_guest.Guest(domain)
|
||||
guest.detach_device(conf, persistent=True)
|
||||
|
||||
domain.detachDeviceFlags.assert_called_once_with(
|
||||
"</xml>", flags=fakelibvirt.VIR_DOMAIN_AFFECT_CONFIG)
|
||||
|
||||
def test_detach_device_live(self):
|
||||
domain = mock.Mock(spec=fakelibvirt.virDomain)
|
||||
conf = mock.Mock(spec=vconfig.LibvirtConfigGuestDevice)
|
||||
conf.to_xml.return_value = "</xml>"
|
||||
|
||||
guest = libvirt_guest.Guest(domain)
|
||||
guest.detach_device(conf, live=True)
|
||||
|
||||
domain.detachDeviceFlags.assert_called_once_with(
|
||||
"</xml>", flags=fakelibvirt.VIR_DOMAIN_AFFECT_LIVE)
|
||||
|
||||
def test_detach_device_persistent_live(self):
|
||||
domain = mock.Mock(spec=fakelibvirt.virDomain)
|
||||
conf = mock.Mock(spec=vconfig.LibvirtConfigGuestDevice)
|
||||
conf.to_xml.return_value = "</xml>"
|
||||
|
||||
guest = libvirt_guest.Guest(domain)
|
||||
guest.detach_device(conf, persistent=True, live=True)
|
||||
|
||||
domain.detachDeviceFlags.assert_called_once_with(
|
||||
"</xml>", flags=(fakelibvirt.VIR_DOMAIN_AFFECT_CONFIG |
|
||||
fakelibvirt.VIR_DOMAIN_AFFECT_LIVE))
|
||||
|
|
|
@ -1199,31 +1199,21 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
disk_dev = mountpoint.rpartition("/")[2]
|
||||
try:
|
||||
guest = self._host.get_guest(instance)
|
||||
|
||||
# TODO(sahid): We are converting all calls from a
|
||||
# virDomain object to use nova.virt.libvirt.Guest.
|
||||
# We should be able to remove virt_dom at the end.
|
||||
virt_dom = guest._domain
|
||||
conf = guest.get_disk(disk_dev)
|
||||
if not conf:
|
||||
raise exception.DiskNotFound(location=disk_dev)
|
||||
else:
|
||||
# NOTE(vish): We can always affect config because our
|
||||
# domains are persistent, but we should only
|
||||
# affect live if the domain is running.
|
||||
flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG
|
||||
state = self._get_power_state(virt_dom)
|
||||
if state in (power_state.RUNNING, power_state.PAUSED):
|
||||
flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE
|
||||
virt_dom.detachDeviceFlags(conf.to_xml(), flags)
|
||||
|
||||
if encryption:
|
||||
# The volume must be detached from the VM before
|
||||
# disconnecting it from its encryptor. Otherwise, the
|
||||
# encryptor may report that the volume is still in use.
|
||||
encryptor = self._get_volume_encryptor(connection_info,
|
||||
encryption)
|
||||
encryptor.detach_volume(**encryption)
|
||||
state = self._get_power_state(guest._domain)
|
||||
live = state in (power_state.RUNNING, power_state.PAUSED)
|
||||
guest.detach_device(conf, persistent=True, live=live)
|
||||
|
||||
if encryption:
|
||||
# The volume must be detached from the VM before
|
||||
# disconnecting it from its encryptor. Otherwise, the
|
||||
# encryptor may report that the volume is still in use.
|
||||
encryptor = self._get_volume_encryptor(connection_info,
|
||||
encryption)
|
||||
encryptor.detach_volume(**encryption)
|
||||
except exception.InstanceNotFound:
|
||||
# NOTE(zhaoqin): If the instance does not exist, _lookup_by_name()
|
||||
# will throw InstanceNotFound exception. Need to
|
||||
|
@ -1263,20 +1253,13 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
|
||||
def detach_interface(self, instance, vif):
|
||||
guest = self._host.get_guest(instance)
|
||||
|
||||
# TODO(sahid): We are converting all calls from a
|
||||
# virDomain object to use nova.virt.libvirt.Guest.
|
||||
# We should be able to remove virt_dom at the end.
|
||||
virt_dom = guest._domain
|
||||
cfg = self.vif_driver.get_config(instance, vif, None, instance.flavor,
|
||||
CONF.libvirt.virt_type)
|
||||
try:
|
||||
self.vif_driver.unplug(instance, vif)
|
||||
flags = libvirt.VIR_DOMAIN_AFFECT_CONFIG
|
||||
state = self._get_power_state(virt_dom)
|
||||
if state == power_state.RUNNING or state == power_state.PAUSED:
|
||||
flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE
|
||||
virt_dom.detachDeviceFlags(cfg.to_xml(), flags)
|
||||
state = self._get_power_state(guest._domain)
|
||||
live = state in (power_state.RUNNING, power_state.PAUSED)
|
||||
guest.detach_device(cfg, persistent=True, live=live)
|
||||
except libvirt.libvirtError as ex:
|
||||
error_code = ex.get_error_code()
|
||||
if error_code == libvirt.VIR_ERR_NO_DOMAIN:
|
||||
|
@ -1393,9 +1376,9 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
# NOTE(dkang): managedSave does not work for LXC
|
||||
if CONF.libvirt.virt_type != 'lxc' and not live_snapshot:
|
||||
if state == power_state.RUNNING or state == power_state.PAUSED:
|
||||
self._detach_pci_devices(virt_dom,
|
||||
self._detach_pci_devices(guest,
|
||||
pci_manager.get_instance_pci_devs(instance))
|
||||
self._detach_sriov_ports(context, instance, virt_dom)
|
||||
self._detach_sriov_ports(context, instance, guest)
|
||||
virt_dom.managedSave(0)
|
||||
|
||||
snapshot_backend = self.image_backend.snapshot(instance,
|
||||
|
@ -2309,9 +2292,9 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
# We should be able to remove dom at the end.
|
||||
dom = guest._domain
|
||||
|
||||
self._detach_pci_devices(dom,
|
||||
self._detach_pci_devices(guest,
|
||||
pci_manager.get_instance_pci_devs(instance))
|
||||
self._detach_sriov_ports(context, instance, dom)
|
||||
self._detach_sriov_ports(context, instance, guest)
|
||||
dom.managedSave(0)
|
||||
|
||||
def resume(self, context, instance, network_info, block_device_info=None):
|
||||
|
@ -2980,7 +2963,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
dev['instance_uuid'],
|
||||
reason=six.text_type(exc))
|
||||
|
||||
def _detach_pci_devices(self, dom, pci_devs):
|
||||
def _detach_pci_devices(self, guest, pci_devs):
|
||||
|
||||
# for libvirt version < 1.1.1, this is race condition
|
||||
# so forbid detach if not had this version
|
||||
|
@ -2993,11 +2976,10 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
dev=pci_devs)
|
||||
try:
|
||||
for dev in pci_devs:
|
||||
dom.detachDeviceFlags(self._get_guest_pci_device(dev).to_xml(),
|
||||
libvirt.VIR_DOMAIN_AFFECT_LIVE)
|
||||
guest.detach_device(self._get_guest_pci_device(dev), live=True)
|
||||
# after detachDeviceFlags returned, we should check the dom to
|
||||
# ensure the detaching is finished
|
||||
xml = dom.XMLDesc(0)
|
||||
xml = guest._domain.XMLDesc(0)
|
||||
xml_doc = etree.fromstring(xml)
|
||||
guest_config = vconfig.LibvirtConfigGuest()
|
||||
guest_config.parse_dom(xml_doc)
|
||||
|
@ -3057,7 +3039,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
{'port': vif, 'dom': guest.id})
|
||||
guest.attach_device(cfg)
|
||||
|
||||
def _detach_sriov_ports(self, context, instance, dom):
|
||||
def _detach_sriov_ports(self, context, instance, guest):
|
||||
network_info = instance.info_cache.network_info
|
||||
if network_info is None:
|
||||
return
|
||||
|
@ -3082,8 +3064,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
image_meta,
|
||||
instance.flavor,
|
||||
CONF.libvirt.virt_type)
|
||||
dom.detachDeviceFlags(cfg.to_xml(),
|
||||
libvirt.VIR_DOMAIN_AFFECT_LIVE)
|
||||
guest.detach_device(cfg, live=True)
|
||||
|
||||
def _set_host_enabled(self, enabled,
|
||||
disable_reason=DISABLE_REASON_UNDEFINED):
|
||||
|
|
|
@ -207,6 +207,19 @@ class Guest(object):
|
|||
conf.parse_dom(node)
|
||||
return conf
|
||||
|
||||
def detach_device(self, conf, persistent=False, live=False):
|
||||
"""Detaches device to the guest.
|
||||
|
||||
:param conf: A LibvirtConfigObject of the device to detach
|
||||
:param persistent: A bool to indicate whether the change is
|
||||
persistent or not
|
||||
:param live: A bool to indicate whether it affect the guest
|
||||
in running state
|
||||
"""
|
||||
flags = persistent and libvirt.VIR_DOMAIN_AFFECT_CONFIG or 0
|
||||
flags |= live and libvirt.VIR_DOMAIN_AFFECT_LIVE or 0
|
||||
self._domain.detachDeviceFlags(conf.to_xml(), flags=flags)
|
||||
|
||||
|
||||
class GuestVCPUInfo(object):
|
||||
def __init__(self, id, cpu, state, time):
|
||||
|
|
Loading…
Reference in New Issue