summaryrefslogtreecommitdiffstats
path: root/nova/virt
diff options
context:
space:
mode:
authorJohn Garbutt <john.garbutt@citrix.com>2012-07-09 15:14:10 +0100
committerJohn Garbutt <john.garbutt@citrix.com>2012-07-17 09:53:01 +0100
commit8b667215e82ffb32ace5df6a12dff7ece42e2b82 (patch)
tree02fc48da39f6836691e7eb4c83768cd0062755e6 /nova/virt
parent500ee77121512fd40f5c2afb885fdc45fbf4b57f (diff)
Partially implements blueprint xenapi-live-migration
This is dependent on refactoring of libvirt live migration. Enables live migration using xenapi: * works when both hosts are part of the same aggregate * assumes shared storage is configured as the default SR Limitations in this version: * only works for images that don't have an external ramdisk/kernel Change-Id: I74fc6aae9a615be7cefb1cf07755764df1af957a
Diffstat (limited to 'nova/virt')
-rw-r--r--nova/virt/xenapi/driver.py83
-rw-r--r--nova/virt/xenapi/fake.py3
-rw-r--r--nova/virt/xenapi/vmops.py57
3 files changed, 138 insertions, 5 deletions
diff --git a/nova/virt/xenapi/driver.py b/nova/virt/xenapi/driver.py
index c7fad6387..2f4059bd3 100644
--- a/nova/virt/xenapi/driver.py
+++ b/nova/virt/xenapi/driver.py
@@ -411,17 +411,90 @@ class XenAPIDriver(driver.ComputeDriver):
db.compute_node_update(ctxt, compute_node_ref[0]['id'], dic)
def ensure_filtering_rules_for_instance(self, instance_ref, network_info):
- """This method is supported only libvirt."""
# NOTE(salvatore-orlando): it enforces security groups on
# host initialization and live migration.
- # Live migration is not supported by XenAPI (as of 2011-11-09)
# In XenAPI we do not assume instances running upon host initialization
return
- def live_migration(self, context, instance_ref, dest,
+ def check_can_live_migrate_destination(self, ctxt, instance_ref,
+ block_migration=False, disk_over_commit=False):
+ """Check if it is possible to execute live migration.
+
+ :param context: security context
+ :param instance_ref: nova.db.sqlalchemy.models.Instance object
+ :param block_migration: if true, prepare for block migration
+ :param disk_over_commit: if true, allow disk over commit
+
+ """
+ self._vmops.check_can_live_migrate_destination(ctxt, instance_ref,
+ block_migration, disk_over_commit)
+
+ def check_can_live_migrate_destination_cleanup(self, ctxt,
+ dest_check_data):
+ """Do required cleanup on dest host after check_can_live_migrate calls
+
+ :param ctxt: security context
+ :param disk_over_commit: if true, allow disk over commit
+ """
+ pass
+
+ def check_can_live_migrate_source(self, ctxt, instance_ref,
+ dest_check_data):
+ """Check if it is possible to execute live migration.
+
+ This checks if the live migration can succeed, based on the
+ results from check_can_live_migrate_destination.
+
+ :param context: security context
+ :param instance_ref: nova.db.sqlalchemy.models.Instance
+ :param dest_check_data: result of check_can_live_migrate_destination
+ """
+ pass
+
+ def live_migration(self, ctxt, instance_ref, dest,
post_method, recover_method, block_migration=False):
- """This method is supported only by libvirt."""
- return
+ """Performs the live migration of the specified instance.
+
+ :params ctxt: security context
+ :params instance_ref:
+ nova.db.sqlalchemy.models.Instance object
+ instance object that is migrated.
+ :params dest: destination host
+ :params post_method:
+ post operation method.
+ expected nova.compute.manager.post_live_migration.
+ :params recover_method:
+ recovery method when any exception occurs.
+ expected nova.compute.manager.recover_live_migration.
+ :params block_migration: if true, migrate VM disk.
+ """
+ self._vmops.live_migrate(ctxt, instance_ref, dest, post_method,
+ recover_method, block_migration)
+
+ def pre_live_migration(self, context, instance_ref, block_device_info,
+ network_info):
+ """Preparation live migration.
+
+ :params block_device_info:
+ It must be the result of _get_instance_volume_bdms()
+ at compute manager.
+ """
+ # TODO(JohnGarbutt) look again when boot-from-volume hits trunk
+ pass
+
+ def post_live_migration_at_destination(self, ctxt, instance_ref,
+ network_info, block_migration):
+ """Post operation of live migration at destination host.
+
+ :params ctxt: security context
+ :params instance_ref:
+ nova.db.sqlalchemy.models.Instance object
+ instance object that is migrated.
+ :params network_info: instance network infomation
+ :params : block_migration: if true, post operation of block_migraiton.
+ """
+ # TODO(JohnGarbutt) look at moving/downloading ramdisk and kernel
+ pass
def unfilter_instance(self, instance_ref, network_info):
"""Removes security groups configured for an instance."""
diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py
index 416bf8b8e..cbfa72413 100644
--- a/nova/virt/xenapi/fake.py
+++ b/nova/virt/xenapi/fake.py
@@ -488,6 +488,9 @@ class SessionBase(object):
db_ref['xenstore_data'] = {}
db_ref['xenstore_data'][key] = value
+ def VM_pool_migrate(self, _1, vm_ref, host_ref, options):
+ pass
+
def VDI_remove_from_other_config(self, _1, vdi_ref, key):
db_ref = _db_content['VDI'][vdi_ref]
if not 'other_config' in db_ref:
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 4805ccaf7..95999584c 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -36,6 +36,7 @@ from nova import db
from nova import exception
from nova import flags
from nova.openstack.common import cfg
+from nova.openstack.common import excutils
from nova.openstack.common import importutils
from nova.openstack.common import jsonutils
from nova.openstack.common import log as logging
@@ -1377,3 +1378,59 @@ class VMOps(object):
"""Removes filters for each VIF of the specified instance."""
self.firewall_driver.unfilter_instance(instance_ref,
network_info=network_info)
+
+ def _get_host_uuid_from_aggregate(self, context, hostname):
+ current_aggregate = db.aggregate_get_by_host(context, FLAGS.host)
+ try:
+ return current_aggregate.metadetails[hostname]
+ except KeyError:
+ reason = _('Destination host:%(hostname)s must be in the same '
+ 'aggregate as the source server')
+ raise exception.MigrationError(reason=reason % locals())
+
+ def _ensure_host_in_aggregate(self, context, hostname):
+ self._get_host_uuid_from_aggregate(context, hostname)
+
+ def _get_host_opaque_ref(self, context, hostname):
+ host_uuid = self._get_host_uuid_from_aggregate(context, hostname)
+ return self._session.call_xenapi("host.get_by_uuid", host_uuid)
+
+ def check_can_live_migrate_destination(self, ctxt, instance_ref,
+ block_migration=False,
+ disk_over_commit=False):
+ """Check if it is possible to execute live migration.
+
+ :param context: security context
+ :param instance_ref: nova.db.sqlalchemy.models.Instance object
+ :param block_migration: if true, prepare for block migration
+ :param disk_over_commit: if true, allow disk over commit
+
+ """
+ if block_migration:
+ #TODO(johngarbutt): XenServer feature coming soon fixes this
+ raise NotImplementedError()
+ else:
+ src = instance_ref['host']
+ self._ensure_host_in_aggregate(ctxt, src)
+ # TODO(johngarbutt) we currently assume
+ # instance is on a SR shared with other destination
+ # block migration work will be able to resolve this
+
+ def live_migrate(self, context, instance, destination_hostname,
+ post_method, recover_method, block_migration):
+ if block_migration:
+ #TODO(johngarbutt): see above
+ raise NotImplementedError()
+ else:
+ try:
+ vm_ref = self._get_vm_opaque_ref(instance)
+ host_ref = self._get_host_opaque_ref(context,
+ destination_hostname)
+ self._session.call_xenapi("VM.pool_migrate", vm_ref,
+ host_ref, {})
+ post_method(context, instance, destination_hostname,
+ block_migration)
+ except Exception:
+ with excutils.save_and_reraise_exception():
+ recover_method(context, instance, destination_hostname,
+ block_migration)