Skip to content

Commit

Permalink
libvirt: persist volume attachments into config
Browse files Browse the repository at this point in the history
When you attach a volume to a running instance, only the running
xml is updated in libvirt. This is due to the usage of the
VIRT_DOMAIN_AFFECT_CURRENT flag passed to attach device. What we
really want is to affect both the config and the running xml. There
is no combination of flags that works in all states, so we explicitly
set the right combination of flags depending on the running state
of the vm.

Includes a test to test_virt_drivers to ensure the flags are passed
correctly.

Fixes bug 1071069

Change-Id: I1992748b08daf99cf03dfeb0937ad42457fff1a3
  • Loading branch information
vishvananda committed Oct 24, 2012
1 parent 86b9147 commit 814e7f8
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 3 deletions.
7 changes: 6 additions & 1 deletion nova/tests/fakelibvirt.py
Expand Up @@ -73,6 +73,8 @@ def _reset():
VIR_DOMAIN_UNDEFINE_MANAGED_SAVE = 1

VIR_DOMAIN_AFFECT_CURRENT = 0
VIR_DOMAIN_AFFECT_LIVE = 1
VIR_DOMAIN_AFFECT_CONFIG = 2

VIR_CPU_COMPARE_ERROR = -1
VIR_CPU_COMPARE_INCOMPATIBLE = 0
Expand Down Expand Up @@ -337,7 +339,10 @@ def attachDevice(self, xml):
self._def['devices']['disks'] += [disk_info]
return True

def attachDeviceFlags(self, xml, _flags):
def attachDeviceFlags(self, xml, flags):
if (flags & VIR_DOMAIN_AFFECT_LIVE and
self._state != VIR_DOMAIN_RUNNING):
raise libvirtError("AFFECT_LIVE only allowed for running domains!")
self.attachDevice(xml)

def detachDevice(self, xml):
Expand Down
12 changes: 12 additions & 0 deletions nova/tests/test_virt_drivers.py
Expand Up @@ -360,6 +360,18 @@ def test_attach_detach_volume(self):
instance_ref['name'],
'/mnt/nova/something')

@catch_notimplementederror
def test_attach_detach_different_power_states(self):
instance_ref, network_info = self._get_running_instance()
self.connection.power_off(instance_ref)
self.connection.attach_volume({'driver_volume_type': 'fake'},
instance_ref['name'],
'/mnt/nova/something')
self.connection.power_on(instance_ref)
self.connection.detach_volume({'driver_volume_type': 'fake'},
instance_ref['name'],
'/mnt/nova/something')

@catch_notimplementederror
def test_get_info(self):
instance_ref, network_info = self._get_running_instance()
Expand Down
16 changes: 14 additions & 2 deletions nova/virt/libvirt/driver.py
Expand Up @@ -646,7 +646,13 @@ def attach_volume(self, connection_info, instance_name, mountpoint):
self._conn.defineXML(domxml)
else:
try:
flags = (libvirt.VIR_DOMAIN_AFFECT_CURRENT)
# 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 = LIBVIRT_POWER_STATE[virt_dom.info()[0]]
if state == power_state.RUNNING:
flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE
virt_dom.attachDeviceFlags(conf.to_xml(), flags)
except Exception, ex:
if isinstance(ex, libvirt.libvirtError):
Expand Down Expand Up @@ -704,7 +710,13 @@ def detach_volume(self, connection_info, instance_name, mountpoint):
domxml = virt_dom.XMLDesc(libvirt.VIR_DOMAIN_XML_SECURE)
self._conn.defineXML(domxml)
else:
flags = (libvirt.VIR_DOMAIN_AFFECT_CURRENT)
# 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 = LIBVIRT_POWER_STATE[virt_dom.info()[0]]
if state == power_state.RUNNING:
flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE
virt_dom.detachDeviceFlags(xml, flags)
except libvirt.libvirtError as ex:
# NOTE(vish): This is called to cleanup volumes after live
Expand Down

0 comments on commit 814e7f8

Please sign in to comment.