summaryrefslogtreecommitdiffstats
path: root/nova/virt
diff options
context:
space:
mode:
authorRenuka Apte <renuka.apte@citrix.com>2012-09-04 23:02:16 -0700
committerClay Gerrard <clay.gerrard@gmail.com>2012-10-03 20:32:22 -0500
commit359527501604ea720b594a2ed1b32cd29fe6adbc (patch)
tree2e938a604d06016107f0782d7971a18beb33e936 /nova/virt
parent1d4506c16aec9674be6a3685ba585a8bbd9c1559 (diff)
xenapi: Refactor snapshots during resize
Currently, we use VM.snapshot for resize, which fails if we have a volume attached to the VM, which does not support snapshots. This change uses VDI.snapshot instead, for all VDIs that are not attached by nova. Also needed for xenapi: detaching and reattaching volumes during migrations and reverting of migrations. Fixes Bug #1028092 Change-Id: I3e2973747135a9c33de194e38537620c397bb87e
Diffstat (limited to 'nova/virt')
-rw-r--r--nova/virt/xenapi/driver.py27
-rw-r--r--nova/virt/xenapi/vm_utils.py48
-rw-r--r--nova/virt/xenapi/vmops.py20
-rw-r--r--nova/virt/xenapi/volumeops.py4
4 files changed, 76 insertions, 23 deletions
diff --git a/nova/virt/xenapi/driver.py b/nova/virt/xenapi/driver.py
index 7d6ec37bb..04b75598c 100644
--- a/nova/virt/xenapi/driver.py
+++ b/nova/virt/xenapi/driver.py
@@ -188,6 +188,13 @@ class XenAPIDriver(driver.ComputeDriver):
"""Finish reverting a resize, powering back on the instance"""
# NOTE(vish): Xen currently does not use network info.
self._vmops.finish_revert_migration(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._volumeops.attach_volume(connection_info,
+ instance['name'], mount_device)
def finish_migration(self, context, migration, instance, disk_info,
network_info, image_meta, resize_instance=False,
@@ -195,6 +202,13 @@ class XenAPIDriver(driver.ComputeDriver):
"""Completes a resize, turning on the migrated instance"""
self._vmops.finish_migration(context, migration, instance, disk_info,
network_info, image_meta, resize_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._volumeops.attach_volume(connection_info,
+ instance['name'], mount_device)
def snapshot(self, context, instance, image_id):
""" Create snapshot from a running VM instance """
@@ -237,8 +251,17 @@ class XenAPIDriver(driver.ComputeDriver):
"""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.
- return self._vmops.migrate_disk_and_power_off(context, instance,
- dest, instance_type)
+ rv = self._vmops.migrate_disk_and_power_off(context, instance,
+ dest, instance_type)
+ block_device_mapping = driver.block_device_info_get_mapping(
+ block_device_info)
+ name_label = self._vmops._get_orig_vm_name_label(instance)
+ for vol in block_device_mapping:
+ connection_info = vol['connection_info']
+ mount_device = vol['mount_device'].rpartition("/")[2]
+ self._volumeops.detach_volume(connection_info,
+ name_label, mount_device)
+ return rv
def suspend(self, instance):
"""suspend the specified instance"""
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index 7a37bcdac..764a0c59f 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -524,39 +524,51 @@ def snapshot_attached_here(session, instance, vm_ref, label):
vm_vdi_ref, vm_vdi_rec = get_vdi_for_vm_safely(session, vm_ref)
original_parent_uuid = _get_vhd_parent_uuid(session, vm_vdi_ref)
- template_vm_ref, template_vdi_uuid = _create_snapshot(
- session, instance, vm_ref, label)
-
try:
+ vdi_snapshot_recs = _vdi_snapshot_vm_base(session, instance, vm_ref)
sr_ref = vm_vdi_rec["SR"]
parent_uuid, base_uuid = _wait_for_vhd_coalesce(
session, instance, sr_ref, vm_vdi_ref, original_parent_uuid)
- vdi_uuids = [vdi_rec['uuid'] for vdi_rec in
- _walk_vdi_chain(session, template_vdi_uuid)]
+ vdi_uuids = []
+ for snapshot in vdi_snapshot_recs:
+ vdi_uuids += [vdi_rec['uuid'] for vdi_rec in
+ _walk_vdi_chain(session, snapshot['uuid'])]
yield vdi_uuids
finally:
- _destroy_snapshot(session, instance, template_vm_ref)
-
+ _destroy_snapshots(session, instance, vdi_snapshot_recs)
-def _create_snapshot(session, instance, vm_ref, label):
- template_vm_ref = session.call_xenapi('VM.snapshot', vm_ref, label)
- template_vdi_rec = get_vdi_for_vm_safely(session, template_vm_ref)[1]
- template_vdi_uuid = template_vdi_rec["uuid"]
- LOG.debug(_("Created snapshot %(template_vdi_uuid)s with label"
- " '%(label)s'"), locals(), instance=instance)
+def _vdi_snapshot_vm_base(session, instance, vm_ref):
+ """Make a snapshot of every non-cinder VDI and return a list
+ of the new vdi records.
+ """
+ new_vdis = []
+ try:
+ vbd_refs = session.call_xenapi("VM.get_VBDs", vm_ref)
+ for vbd_ref in vbd_refs:
+ oc = session.call_xenapi("VBD.get_other_config", vbd_ref)
+ if 'osvol' not in oc:
+ # This volume is not a nova/cinder volume
+ vdi_ref = session.call_xenapi("VBD.get_VDI", vbd_ref)
+ snapshot_ref = session.call_xenapi("VDI.snapshot", vdi_ref,
+ {})
+ new_vdis.append(session.call_xenapi("VDI.get_record",
+ snapshot_ref))
- return template_vm_ref, template_vdi_uuid
+ except session.XenAPI.Failure:
+ LOG.exception(_("Failed to snapshot VDI"), instance=instance)
+ raise
+ finally:
+ return new_vdis
-def _destroy_snapshot(session, instance, vm_ref):
- vdi_refs = lookup_vm_vdis(session, vm_ref)
+def _destroy_snapshots(session, instance, vdi_snapshot_recs):
+ vdi_refs = [session.call_xenapi("VDI.get_by_uuid", vdi_rec['uuid'])
+ for vdi_rec in vdi_snapshot_recs]
safe_destroy_vdis(session, vdi_refs)
- destroy_vm(session, instance, vm_ref)
-
def get_sr_path(session):
"""Return the path to our storage repository
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index ae8efc5f3..feee83b5d 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -192,10 +192,26 @@ class VMOps(object):
if resize_instance:
self._resize_instance(instance, root_vdi)
+ # Check if kernel and ramdisk are external
+ kernel_file = None
+ ramdisk_file = None
+
+ name_label = instance['name']
+ if instance['kernel_id']:
+ vdis = vm_utils.create_kernel_image(context, self._session,
+ instance, name_label, instance['kernel_id'],
+ vm_utils.ImageType.KERNEL)
+ kernel_file = vdis['kernel'].get('file')
+ if instance['ramdisk_id']:
+ vdis = vm_utils.create_kernel_image(context, self._session,
+ instance, name_label, instance['ramdisk_id'],
+ vm_utils.ImageType.RAMDISK)
+ ramdisk_file = vdis['ramdisk'].get('file')
+
vm_ref = self._create_vm(context, instance, instance['name'],
{'root': root_vdi},
- network_info, image_meta)
-
+ network_info, image_meta, kernel_file,
+ ramdisk_file)
# 5. Start VM
self._start(instance, vm_ref=vm_ref)
self._update_instance_progress(context, instance,
diff --git a/nova/virt/xenapi/volumeops.py b/nova/virt/xenapi/volumeops.py
index ec495ebc1..09d735902 100644
--- a/nova/virt/xenapi/volumeops.py
+++ b/nova/virt/xenapi/volumeops.py
@@ -215,8 +215,10 @@ class VolumeOps(object):
raise Exception(_('Unable to locate volume %s') % mountpoint)
try:
+ vm_rec = self._session.call_xenapi("VM.get_record", vm_ref)
sr_ref = volume_utils.find_sr_from_vbd(self._session, vbd_ref)
- vm_utils.unplug_vbd(self._session, vbd_ref)
+ if vm_rec['power_state'] != 'Halted':
+ vm_utils.unplug_vbd(self._session, vbd_ref)
except volume_utils.StorageError, exc:
LOG.exception(exc)
raise Exception(_('Unable to detach volume %s') % mountpoint)