Re-attach volumes after instance resize
Fixes bug 1051600. Update the compute manager to pass block_device_info to three additional driver entry points and update all virtualization drivers to accept it as an optional argument. Within libvirt, migrate_disk_and_power_off() will now iterate and disconnect any existing connections. finish_migration() simply updates its use of to_xml(), passing block_device_info, which returns a libvirt XML fully populated with volumes. Finally, finish_revert_migration() no longer uses the on-disk XML file, instead generating it via to_xml; as the former lacks volume configuration. Change-Id: I7dccd03ef9cc7d2848f07764d4def3787e41e202
This commit is contained in:
@@ -1445,8 +1445,12 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
old_instance_type = migration_ref['old_instance_type_id']
|
||||
instance_type = instance_types.get_instance_type(old_instance_type)
|
||||
|
||||
block_device_info = self._get_instance_volume_block_device_info(
|
||||
context, instance['uuid'])
|
||||
|
||||
self.driver.finish_revert_migration(instance,
|
||||
self._legacy_nw_info(network_info))
|
||||
self._legacy_nw_info(network_info),
|
||||
block_device_info)
|
||||
|
||||
# Just roll back the record. There's no need to resize down since
|
||||
# the 'old' VM already has the preferred attributes
|
||||
@@ -1558,9 +1562,13 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
self._notify_about_instance_usage(
|
||||
context, instance, "resize.start", network_info=network_info)
|
||||
|
||||
block_device_info = self._get_instance_volume_block_device_info(
|
||||
context, instance['uuid'])
|
||||
|
||||
disk_info = self.driver.migrate_disk_and_power_off(
|
||||
context, instance, migration_ref['dest_host'],
|
||||
instance_type_ref, self._legacy_nw_info(network_info))
|
||||
instance_type_ref, self._legacy_nw_info(network_info),
|
||||
block_device_info)
|
||||
|
||||
self.db.migration_update(context,
|
||||
migration_id,
|
||||
@@ -1609,10 +1617,14 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
context, instance, "finish_resize.start",
|
||||
network_info=network_info)
|
||||
|
||||
block_device_info = self._get_instance_volume_block_device_info(
|
||||
context, instance['uuid'])
|
||||
|
||||
self.driver.finish_migration(context, migration_ref, instance,
|
||||
disk_info,
|
||||
self._legacy_nw_info(network_info),
|
||||
image, resize_instance)
|
||||
image, resize_instance,
|
||||
block_device_info)
|
||||
|
||||
instance = self._instance_update(context,
|
||||
instance['uuid'],
|
||||
|
||||
@@ -3736,7 +3736,8 @@ class LibvirtDriverTestCase(test.TestCase):
|
||||
def fake_extend(path, size):
|
||||
pass
|
||||
|
||||
def fake_to_xml(instance, network_info):
|
||||
def fake_to_xml(instance, network_info, image_meta=None, rescue=None,
|
||||
block_device_info=None):
|
||||
return ""
|
||||
|
||||
def fake_plug_vifs(instance, network_info):
|
||||
@@ -3802,6 +3803,11 @@ class LibvirtDriverTestCase(test.TestCase):
|
||||
def fake_get_info(instance):
|
||||
return {'state': power_state.RUNNING}
|
||||
|
||||
def fake_to_xml(instance, network_info, image_meta=None, rescue=None,
|
||||
block_device_info=None):
|
||||
return ""
|
||||
|
||||
self.stubs.Set(self.libvirtconnection, 'to_xml', fake_to_xml)
|
||||
self.stubs.Set(self.libvirtconnection, 'plug_vifs', fake_plug_vifs)
|
||||
self.stubs.Set(utils, 'execute', fake_execute)
|
||||
fw = base_firewall.NoopFirewallDriver()
|
||||
|
||||
@@ -242,7 +242,8 @@ class ComputeDriver(object):
|
||||
raise NotImplementedError()
|
||||
|
||||
def migrate_disk_and_power_off(self, context, instance, dest,
|
||||
instance_type, network_info):
|
||||
instance_type, network_info,
|
||||
block_device_info=None):
|
||||
"""
|
||||
Transfers the disk of a running instance in multiple phases, turning
|
||||
off the instance before the end.
|
||||
@@ -261,7 +262,8 @@ class ComputeDriver(object):
|
||||
raise NotImplementedError()
|
||||
|
||||
def finish_migration(self, context, migration, instance, disk_info,
|
||||
network_info, image_meta, resize_instance):
|
||||
network_info, image_meta, resize_instance,
|
||||
block_device_info=None):
|
||||
"""Completes a resize, turning on the migrated instance
|
||||
|
||||
:param network_info:
|
||||
@@ -277,7 +279,8 @@ class ComputeDriver(object):
|
||||
# TODO(Vek): Need to pass context in for access to auth_token
|
||||
raise NotImplementedError()
|
||||
|
||||
def finish_revert_migration(self, instance, network_info):
|
||||
def finish_revert_migration(self, instance, network_info,
|
||||
block_device_info=None):
|
||||
"""Finish reverting a resize, powering back on the instance"""
|
||||
# TODO(Vek): Need to pass context in for access to auth_token
|
||||
raise NotImplementedError()
|
||||
|
||||
@@ -124,10 +124,12 @@ class FakeDriver(driver.ComputeDriver):
|
||||
pass
|
||||
|
||||
def migrate_disk_and_power_off(self, context, instance, dest,
|
||||
instance_type, network_info):
|
||||
instance_type, network_info,
|
||||
block_device_info=None):
|
||||
pass
|
||||
|
||||
def finish_revert_migration(self, instance, network_info):
|
||||
def finish_revert_migration(self, instance, network_info,
|
||||
block_device_info=None):
|
||||
pass
|
||||
|
||||
def power_off(self, instance):
|
||||
@@ -252,7 +254,8 @@ class FakeDriver(driver.ComputeDriver):
|
||||
return
|
||||
|
||||
def finish_migration(self, context, migration, instance, disk_info,
|
||||
network_info, image_meta, resize_instance):
|
||||
network_info, image_meta, resize_instance,
|
||||
block_device_info=None):
|
||||
return
|
||||
|
||||
def confirm_migration(self, migration, instance, network_info):
|
||||
|
||||
@@ -207,12 +207,14 @@ class HyperVDriver(driver.ComputeDriver):
|
||||
"""Confirms a resize, destroying the source VM"""
|
||||
LOG.debug(_("confirm_migration called"), instance=instance)
|
||||
|
||||
def finish_revert_migration(self, instance, network_info):
|
||||
def finish_revert_migration(self, instance, network_info,
|
||||
block_device_info=None):
|
||||
"""Finish reverting a resize, powering back on the instance"""
|
||||
LOG.debug(_("finish_revert_migration called"), instance=instance)
|
||||
|
||||
def finish_migration(self, context, migration, instance, disk_info,
|
||||
network_info, image_meta, resize_instance=False):
|
||||
network_info, image_meta, resize_instance=False,
|
||||
block_device_info=None):
|
||||
"""Completes a resize, turning on the migrated instance"""
|
||||
LOG.debug(_("finish_migration called"), instance=instance)
|
||||
|
||||
|
||||
@@ -2765,7 +2765,8 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
|
||||
@exception.wrap_exception()
|
||||
def migrate_disk_and_power_off(self, context, instance, dest,
|
||||
instance_type, network_info):
|
||||
instance_type, network_info,
|
||||
block_device_info=None):
|
||||
LOG.debug(_("Starting migrate_disk_and_power_off"),
|
||||
instance=instance)
|
||||
disk_info_text = self.get_instance_disk_info(instance['name'])
|
||||
@@ -2773,6 +2774,15 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
|
||||
self.power_off(instance)
|
||||
|
||||
block_device_mapping = driver.block_device_info_get_mapping(
|
||||
block_device_info)
|
||||
for vol in block_device_mapping:
|
||||
connection_info = vol['connection_info']
|
||||
mount_device = vol['mount_device'].rpartition("/")[2]
|
||||
self.volume_driver_method('disconnect_volume',
|
||||
connection_info,
|
||||
mount_device)
|
||||
|
||||
# copy disks to destination
|
||||
# rename instance dir to +_resize at first for using
|
||||
# shared storage for instance dir (eg. NFS).
|
||||
@@ -2826,7 +2836,8 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
|
||||
@exception.wrap_exception()
|
||||
def finish_migration(self, context, migration, instance, disk_info,
|
||||
network_info, image_meta, resize_instance):
|
||||
network_info, image_meta, resize_instance,
|
||||
block_device_info=None):
|
||||
LOG.debug(_("Starting finish_migration"), instance=instance)
|
||||
|
||||
# resize disks. only "disk" and "disk.local" are necessary.
|
||||
@@ -2863,18 +2874,21 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
'-O', 'qcow2', info['path'], path_qcow)
|
||||
utils.execute('mv', path_qcow, info['path'])
|
||||
|
||||
xml = self.to_xml(instance, network_info)
|
||||
xml = self.to_xml(instance, network_info,
|
||||
block_device_info=block_device_info)
|
||||
# assume _create_image do nothing if a target file exists.
|
||||
# TODO(oda): injecting files is not necessary
|
||||
self._create_image(context, instance, xml,
|
||||
network_info=network_info,
|
||||
block_device_info=None)
|
||||
self._create_domain_and_network(xml, instance, network_info)
|
||||
self._create_domain_and_network(xml, instance, network_info,
|
||||
block_device_info)
|
||||
timer = utils.LoopingCall(self._wait_for_running, instance)
|
||||
timer.start(interval=0.5).wait()
|
||||
|
||||
@exception.wrap_exception()
|
||||
def finish_revert_migration(self, instance, network_info):
|
||||
def finish_revert_migration(self, instance, network_info,
|
||||
block_device_info=None):
|
||||
LOG.debug(_("Starting finish_revert_migration"),
|
||||
instance=instance)
|
||||
|
||||
@@ -2882,9 +2896,10 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
inst_base_resize = inst_base + "_resize"
|
||||
utils.execute('mv', inst_base_resize, inst_base)
|
||||
|
||||
xml_path = os.path.join(inst_base, 'libvirt.xml')
|
||||
xml = open(xml_path).read()
|
||||
self._create_domain_and_network(xml, instance, network_info)
|
||||
xml = self.to_xml(instance, network_info,
|
||||
block_device_info=block_device_info)
|
||||
self._create_domain_and_network(xml, instance, network_info,
|
||||
block_device_info)
|
||||
|
||||
timer = utils.LoopingCall(self._wait_for_running, instance)
|
||||
timer.start(interval=0.5).wait()
|
||||
|
||||
@@ -183,13 +183,15 @@ class XenAPIDriver(driver.ComputeDriver):
|
||||
# TODO(Vek): Need to pass context in for access to auth_token
|
||||
self._vmops.confirm_migration(migration, instance, network_info)
|
||||
|
||||
def finish_revert_migration(self, instance, network_info):
|
||||
def finish_revert_migration(self, instance, network_info,
|
||||
block_device_info=None):
|
||||
"""Finish reverting a resize, powering back on the instance"""
|
||||
# NOTE(vish): Xen currently does not use network info.
|
||||
self._vmops.finish_revert_migration(instance)
|
||||
|
||||
def finish_migration(self, context, migration, instance, disk_info,
|
||||
network_info, image_meta, resize_instance=False):
|
||||
network_info, image_meta, resize_instance=False,
|
||||
block_device_info=None):
|
||||
"""Completes a resize, turning on the migrated instance"""
|
||||
self._vmops.finish_migration(context, migration, instance, disk_info,
|
||||
network_info, image_meta, resize_instance)
|
||||
@@ -230,7 +232,8 @@ class XenAPIDriver(driver.ComputeDriver):
|
||||
self._vmops.unpause(instance)
|
||||
|
||||
def migrate_disk_and_power_off(self, context, instance, dest,
|
||||
instance_type, network_info):
|
||||
instance_type, network_info,
|
||||
block_device_info=None):
|
||||
"""Transfers the VHD of a running instance to another host, then shuts
|
||||
off the instance copies over the COW disk"""
|
||||
# NOTE(vish): Xen currently does not use network info.
|
||||
|
||||
@@ -189,7 +189,8 @@ class VMOps(object):
|
||||
self._start(instance, vm_ref)
|
||||
|
||||
def finish_migration(self, context, migration, instance, disk_info,
|
||||
network_info, image_meta, resize_instance):
|
||||
network_info, image_meta, resize_instance,
|
||||
block_device_info=None):
|
||||
root_vdi = vm_utils.move_disks(self._session, instance, disk_info)
|
||||
|
||||
if resize_instance:
|
||||
|
||||
Reference in New Issue
Block a user