diff options
Diffstat (limited to 'nova/virt')
| -rw-r--r-- | nova/virt/driver.py | 5 | ||||
| -rw-r--r-- | nova/virt/fake.py | 6 | ||||
| -rw-r--r-- | nova/virt/libvirt/driver.py | 4 | ||||
| -rw-r--r-- | nova/virt/xenapi/driver.py | 25 | ||||
| -rw-r--r-- | nova/virt/xenapi/fake.py | 26 | ||||
| -rw-r--r-- | nova/virt/xenapi/vmops.py | 96 |
6 files changed, 136 insertions, 26 deletions
diff --git a/nova/virt/driver.py b/nova/virt/driver.py index dafb83568..53b37ada6 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -337,7 +337,8 @@ class ComputeDriver(object): raise NotImplementedError() def live_migration(self, ctxt, instance_ref, dest, - post_method, recover_method, block_migration=False): + post_method, recover_method, block_migration=False, + migrate_data=None): """Live migration of an instance to another host. :params ctxt: security context @@ -352,6 +353,8 @@ class ComputeDriver(object): recovery method when any exception occurs. expected nova.compute.manager.recover_live_migration. :params block_migration: if true, migrate VM disk. + :params migrate_data: implementation specific params. + """ raise NotImplementedError() diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 823a6e310..2d4672876 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -257,12 +257,11 @@ class FakeDriver(driver.ComputeDriver): raise NotImplementedError('This method is supported only by libvirt.') def get_instance_disk_info(self, instance_name): - """This method is supported only by libvirt.""" return def live_migration(self, context, instance_ref, dest, - post_method, recover_method, block_migration=False): - """This method is supported only by libvirt.""" + post_method, recover_method, block_migration=False, + migrate_data=None): return def finish_migration(self, context, migration, instance, disk_info, @@ -274,7 +273,6 @@ class FakeDriver(driver.ComputeDriver): def pre_live_migration(self, context, instance_ref, block_device_info, network_info): - """This method is supported only by libvirt.""" return def unfilter_instance(self, instance_ref, network_info): diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index e521fca59..2ca5c2edf 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -2399,7 +2399,8 @@ class LibvirtDriver(driver.ComputeDriver): self.firewall_driver.filter_defer_apply_off() def live_migration(self, ctxt, instance_ref, dest, - post_method, recover_method, block_migration=False): + post_method, recover_method, block_migration=False, + migrate_data=None): """Spawning live_migration operation for distributing high-load. :params ctxt: security context @@ -2415,6 +2416,7 @@ class LibvirtDriver(driver.ComputeDriver): recovery method when any exception occurs. expected nova.compute.manager.recover_live_migration. :params block_migration: if true, do block migration. + :params migrate_data: implementation specific params """ diff --git a/nova/virt/xenapi/driver.py b/nova/virt/xenapi/driver.py index 6af06a283..2f472fc7b 100644 --- a/nova/virt/xenapi/driver.py +++ b/nova/virt/xenapi/driver.py @@ -430,8 +430,10 @@ class XenAPIDriver(driver.ComputeDriver): :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) + return 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): @@ -452,11 +454,25 @@ class XenAPIDriver(driver.ComputeDriver): :param context: security context :param instance_ref: nova.db.sqlalchemy.models.Instance :param dest_check_data: result of check_can_live_migrate_destination + includes the block_migration flag """ + self._vmops.check_can_live_migrate_source(ctxt, instance_ref, + dest_check_data) + + def get_instance_disk_info(self, instance_name): + """Used by libvirt for live migration. We rely on xenapi + checks to do this for us.""" + pass + + def pre_block_migration(self, ctxt, instance_ref, disk_info_json): + """Used by libvirt for live migration. We rely on xenapi + checks to do this for us. May be used in the future to + populate the vdi/vif maps""" pass def live_migration(self, ctxt, instance_ref, dest, - post_method, recover_method, block_migration=False): + post_method, recover_method, block_migration=False, + migrate_data=None): """Performs the live migration of the specified instance. :params ctxt: security context @@ -471,9 +487,10 @@ class XenAPIDriver(driver.ComputeDriver): recovery method when any exception occurs. expected nova.compute.manager.recover_live_migration. :params block_migration: if true, migrate VM disk. + :params migrate_data: implementation specific params """ self._vmops.live_migrate(ctxt, instance_ref, dest, post_method, - recover_method, block_migration) + recover_method, block_migration, migrate_data) def pre_live_migration(self, context, instance_ref, block_device_info, network_info): diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py index cbfa72413..0fcd30ebe 100644 --- a/nova/virt/xenapi/fake.py +++ b/nova/virt/xenapi/fake.py @@ -292,7 +292,8 @@ def _create_local_pif(host_ref): 'physical': True, 'VLAN': -1, 'device': 'fake0', - 'host_uuid': host_ref}) + 'host_uuid': host_ref, + 'network': ''}) return pif_ref @@ -491,6 +492,10 @@ class SessionBase(object): def VM_pool_migrate(self, _1, vm_ref, host_ref, options): pass + def VM_migrate_send(self, vmref, migrate_data, islive, vdi_map, + vif_map, 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: @@ -599,6 +604,25 @@ class SessionBase(object): def pool_set_name_label(self, session, pool_ref, name): pass + def host_migrate_receive(self, session, destref, nwref, options): + # The dictionary below represents the true keys, as + # returned by a destination host, but fake values. + return {'xenops': 'http://localhost/services/xenops?' + 'session_id=OpaqueRef:81d00b97-b205-b34d-924e-6f9597854cc0', + 'host': 'OpaqueRef:5e4a3dd1-b71c-74ba-bbc6-58ee9ff6a889', + 'master': 'http://localhost/', + 'session_id': 'OpaqueRef:81d00b97-b205-b34d-924e-6f9597854cc0', + 'SM': 'http://localhost/services/SM?' + 'session_id=OpaqueRef:81d00b97-b205-b34d-924e-6f9597854cc0'} + + def VM_assert_can_migrate(self, session, vmref, migrate_data, live, + vdi_map, vif_map, options): + pass + + def VM_migrate_send(self, session, mref, migrate_data, live, vdi_map, + vif_map, options): + pass + def network_get_all_records_where(self, _1, filter): return self.xenapi.network.get_all_records() diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index dbff55d1f..c74c19773 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -542,6 +542,7 @@ class VMOps(object): 'weight', str(vcpu_weight)) def _get_vm_opaque_ref(self, instance): + """Get xapi OpaqueRef from a db record.""" vm_ref = vm_utils.lookup(self._session, instance['name']) if vm_ref is None: raise exception.NotFound(_('Could not find VM with name %s') % @@ -1482,6 +1483,30 @@ class VMOps(object): host_uuid = self._get_host_uuid_from_aggregate(context, hostname) return self._session.call_xenapi("host.get_by_uuid", host_uuid) + def _migrate_receive(self, ctxt): + destref = self._session.get_xenapi_host() + # Get the network to for migrate. + # This is the one associated with the pif marked management. From cli: + # uuid=`xe pif-list --minimal management=true` + # xe pif-param-get param-name=network-uuid uuid=$uuid + expr = 'field "management" = "true"' + pifs = self._session.call_xenapi('PIF.get_all_records_where', + expr) + if len(pifs) != 1: + raise exception.MigrationError('No suitable network for migrate') + + nwref = pifs[pifs.keys()[0]]['network'] + try: + options = {} + migrate_data = self._session.call_xenapi("host.migrate_receive", + destref, + nwref, + options) + except self._session.XenAPI.Failure as exc: + LOG.exception(exc) + raise exception.MigrationError(_('Migrate Receive failed')) + return migrate_data + def check_can_live_migrate_destination(self, ctxt, instance_ref, block_migration=False, disk_over_commit=False): @@ -1494,30 +1519,71 @@ class VMOps(object): """ if block_migration: - #TODO(johngarbutt): XenServer feature coming soon fixes this - raise NotImplementedError() + migrate_data = self._migrate_receive(ctxt) + dest_check_data = {} + dest_check_data["block_migration"] = block_migration + dest_check_data["migrate_data"] = migrate_data + return dest_check_data 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 + return None - def live_migrate(self, context, instance, destination_hostname, - post_method, recover_method, block_migration): - if block_migration: - #TODO(johngarbutt): see above - raise NotImplementedError() - else: + def check_can_live_migrate_source(self, ctxt, instance_ref, + dest_check_data): + """ Check if it is possible to execute live migration + on the source side. + :param context: security context + :param instance_ref: nova.db.sqlalchemy.models.Instance object + :param dest_check_data: data returned by the check on the + destination, includes block_migration flag + + """ + if dest_check_data and 'migrate_data' in dest_check_data: + vmref = self._get_vm_opaque_ref(instance_ref) + migrate_data = dest_check_data['migrate_data'] try: - vm_ref = self._get_vm_opaque_ref(instance) + vdi_map = {} + vif_map = {} + options = {} + self._session.call_xenapi("VM.assert_can_migrate", vmref, + migrate_data, True, vdi_map, vif_map, + options) + except self._session.XenAPI.Failure as exc: + LOG.exception(exc) + raise exception.MigrationError(_('VM.assert_can_migrate' + 'failed')) + + def live_migrate(self, context, instance, destination_hostname, + post_method, recover_method, block_migration, + migrate_data=None): + try: + vm_ref = self._get_vm_opaque_ref(instance) + if block_migration: + if not migrate_data: + raise exception.InvalidParameterValue('Block Migration ' + 'requires migrate data from destination') + try: + vdi_map = {} + vif_map = {} + options = {} + self._session.call_xenapi("VM.migrate_send", vm_ref, + migrate_data, True, + vdi_map, vif_map, options) + except self._session.XenAPI.Failure as exc: + LOG.exception(exc) + raise exception.MigrationError(_('Migrate Send failed')) + else: 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) + post_method(context, instance, destination_hostname, + block_migration) + except Exception: + with excutils.save_and_reraise_exception(): + recover_method(context, instance, destination_hostname, + block_migration) |
