summaryrefslogtreecommitdiffstats
path: root/nova/virt
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-02-15 00:27:39 +0000
committerGerrit Code Review <review@openstack.org>2012-02-15 00:27:39 +0000
commitcc12819adef88983ef78e9bfb18745df9c39b561 (patch)
tree754f450506eb0ec29831d6b4246767b05ff8a8f2 /nova/virt
parent9e4131741b3c767f97408442048a639a66a3d780 (diff)
parentcb1c1d406b98e492931ff19e29735aa592a99f15 (diff)
Merge "Added resize support for Libvirt/KVM."
Diffstat (limited to 'nova/virt')
-rw-r--r--nova/virt/driver.py4
-rw-r--r--nova/virt/fake.py5
-rw-r--r--nova/virt/libvirt/connection.py142
-rw-r--r--nova/virt/libvirt/utils.py3
-rw-r--r--nova/virt/xenapi_conn.py6
5 files changed, 154 insertions, 6 deletions
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index ad2e82a31..821455b45 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -258,7 +258,7 @@ class ComputeDriver(object):
raise NotImplementedError()
def migrate_disk_and_power_off(self, context, instance, dest,
- instance_type):
+ instance_type, network_info):
"""
Transfers the disk of a running instance in multiple phases, turning
off the instance before the end.
@@ -293,7 +293,7 @@ class ComputeDriver(object):
# TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
- def finish_revert_migration(self, instance):
+ def finish_revert_migration(self, instance, network_info):
"""Finish reverting a resize, powering back on the instance"""
# TODO(Vek): Need to pass context in for access to auth_token
raise NotImplementedError()
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index 204ffb56c..53a1ea4c9 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -144,7 +144,10 @@ class FakeConnection(driver.ComputeDriver):
pass
def migrate_disk_and_power_off(self, context, instance, dest,
- instance_type):
+ instance_type, network_info):
+ pass
+
+ def finish_revert_migration(self, instance, network_info):
pass
def poll_unconfirmed_resizes(self, resize_confirm_window):
diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py
index efd972b4b..77b53e9fb 100644
--- a/nova/virt/libvirt/connection.py
+++ b/nova/virt/libvirt/connection.py
@@ -63,6 +63,7 @@ from nova import flags
import nova.image
from nova import log as logging
from nova.openstack.common import cfg
+from nova import network
from nova import utils
from nova.virt import driver
from nova.virt import images
@@ -437,6 +438,12 @@ class LibvirtConnection(driver.ComputeDriver):
'initiator': self._initiator,
}
+ def _cleanup_resize(self, instance):
+ target = os.path.join(FLAGS.instances_path,
+ instance['name'] + "_resize")
+ if os.path.exists(target):
+ shutil.rmtree(target)
+
def volume_driver_method(self, method_name, connection_info,
*args, **kwargs):
driver_type = connection_info.get('driver_volume_type')
@@ -2081,6 +2088,141 @@ class LibvirtConnection(driver.ComputeDriver):
"""Manage the local cache of images."""
self.image_cache_manager.verify_base_images(context)
+ @exception.wrap_exception()
+ def migrate_disk_and_power_off(self, context, instance, dest,
+ instance_type, network_info):
+ LOG.debug(_("Instance %s: Starting migrate_disk_and_power_off"),
+ instance['name'])
+ disk_info_text = self.get_instance_disk_info(instance['name'])
+ disk_info = utils.loads(disk_info_text)
+
+ self._destroy(instance, network_info, cleanup=False)
+
+ # copy disks to destination
+ # if disk type is qcow2, convert to raw then send to dest.
+ # rename instance dir to +_resize at first for using
+ # shared storage for instance dir (eg. NFS).
+ same_host = (dest == self.get_host_ip_addr())
+ inst_base = "%s/%s" % (FLAGS.instances_path, instance['name'])
+ inst_base_resize = inst_base + "_resize"
+ try:
+ utils.execute('mv', inst_base, inst_base_resize)
+ if same_host:
+ utils.execute('mkdir', '-p', inst_base)
+ else:
+ utils.execute('ssh', dest, 'mkdir', '-p', inst_base)
+ for info in disk_info:
+ # assume inst_base == dirname(info['path'])
+ to_path = "%s:%s" % (dest, info['path'])
+ fname = os.path.basename(info['path'])
+ from_path = os.path.join(inst_base_resize, fname)
+ if info['type'] == 'qcow2':
+ tmp_path = from_path + "_rbase"
+ utils.execute('qemu-img', 'convert', '-f', 'qcow2',
+ '-O', 'raw', from_path, tmp_path)
+ if same_host:
+ utils.execute('mv', tmp_path, info['path'])
+ else:
+ utils.execute('scp', tmp_path, to_path)
+ utils.execute('rm', '-f', tmp_path)
+ else: # raw
+ if same_host:
+ utils.execute('cp', from_path, info['path'])
+ else:
+ utils.execute('scp', from_path, to_path)
+ except Exception, e:
+ try:
+ if os.path.exists(inst_base_resize):
+ utils.execute('rm', '-rf', inst_base)
+ utils.execute('mv', inst_base_resize, inst_base)
+ utils.execute('ssh', dest, 'rm', '-rf', inst_base)
+ except:
+ pass
+ raise e
+
+ return disk_info_text
+
+ def _wait_for_running(self, instance_name):
+ try:
+ state = self.get_info(instance_name)['state']
+ except exception.NotFound:
+ msg = _("During wait running, %s disappeared.") % instance_name
+ LOG.error(msg)
+ raise utils.LoopingCallDone
+
+ if state == power_state.RUNNING:
+ msg = _("Instance %s running successfully.") % instance_name
+ LOG.info(msg)
+ raise utils.LoopingCallDone
+
+ @exception.wrap_exception()
+ def finish_migration(self, context, migration, instance, disk_info,
+ network_info, image_meta, resize_instance):
+ LOG.debug(_("Instance %s: Starting finish_migration"),
+ instance['name'])
+
+ # resize disks. only "disk" and "disk.local" are necessary.
+ disk_info = utils.loads(disk_info)
+ for info in disk_info:
+ fname = os.path.basename(info['path'])
+ if fname == 'disk':
+ disk.extend(info['path'],
+ instance['root_gb'] * 1024 * 1024 * 1024)
+ elif fname == 'disk.local':
+ disk.extend(info['path'],
+ instance['ephemeral_gb'] * 1024 * 1024 * 1024)
+ if FLAGS.use_cow_images:
+ # back to qcow2 (no backing_file though) so that snapshot
+ # will be available
+ path_qcow = info['path'] + '_qcow'
+ utils.execute('qemu-img', 'convert', '-f', 'raw',
+ '-O', 'qcow2', info['path'], path_qcow)
+ utils.execute('mv', path_qcow, info['path'])
+
+ xml = self.to_xml(instance, network_info)
+
+ self.plug_vifs(instance, network_info)
+ self.firewall_driver.setup_basic_filtering(instance, network_info)
+ self.firewall_driver.prepare_instance_filter(instance, network_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)
+
+ domain = self._create_new_domain(xml)
+
+ self.firewall_driver.apply_instance_filter(instance, network_info)
+
+ timer = utils.LoopingCall(self._wait_for_running, instance['name'])
+ return timer.start(interval=0.5, now=True)
+
+ @exception.wrap_exception()
+ def finish_revert_migration(self, instance, network_info):
+ LOG.debug(_("Instance %s: Starting finish_revert_migration"),
+ instance['name'])
+
+ inst_base = "%s/%s" % (FLAGS.instances_path, instance['name'])
+ 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.plug_vifs(instance, network_info)
+ self.firewall_driver.setup_basic_filtering(instance, network_info)
+ self.firewall_driver.prepare_instance_filter(instance, network_info)
+ # images already exist
+ domain = self._create_new_domain(xml)
+ self.firewall_driver.apply_instance_filter(instance, network_info)
+
+ timer = utils.LoopingCall(self._wait_for_running, instance['name'])
+ return timer.start(interval=0.5, now=True)
+
+ def confirm_migration(self, migration, instance, network_info):
+ """Confirms a resize, destroying the source VM"""
+ self._cleanup_resize(instance)
+
class HostState(object):
"""Manages information about the compute node through libvirt"""
diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py
index 0b94a173f..080b58736 100644
--- a/nova/virt/libvirt/utils.py
+++ b/nova/virt/libvirt/utils.py
@@ -102,7 +102,8 @@ def get_disk_backing_file(path):
out, err = execute(FLAGS.qemu_img, 'info', path)
backing_file = [i.split('actual path:')[1].strip()[:-1]
for i in out.split('\n') if 0 <= i.find('backing file')]
- backing_file = os.path.basename(backing_file[0])
+ if backing_file:
+ backing_file = os.path.basename(backing_file[0])
return backing_file
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index 7c419824a..1e2d11bb0 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -211,8 +211,9 @@ class XenAPIConnection(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):
+ def finish_revert_migration(self, instance, network_info):
"""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,
@@ -252,9 +253,10 @@ class XenAPIConnection(driver.ComputeDriver):
self._vmops.unpause(instance)
def migrate_disk_and_power_off(self, context, instance, dest,
- instance_type):
+ instance_type, network_info):
"""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)