diff options
| author | John Garbutt <john.garbutt@citrix.com> | 2012-07-09 15:14:10 +0100 |
|---|---|---|
| committer | John Garbutt <john.garbutt@citrix.com> | 2012-07-17 09:53:01 +0100 |
| commit | 8b667215e82ffb32ace5df6a12dff7ece42e2b82 (patch) | |
| tree | 02fc48da39f6836691e7eb4c83768cd0062755e6 /nova/virt | |
| parent | 500ee77121512fd40f5c2afb885fdc45fbf4b57f (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.py | 83 | ||||
| -rw-r--r-- | nova/virt/xenapi/fake.py | 3 | ||||
| -rw-r--r-- | nova/virt/xenapi/vmops.py | 57 |
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) |
