diff options
-rw-r--r-- | .mailmap | 1 | ||||
-rw-r--r-- | Authors | 2 | ||||
-rwxr-xr-x | bin/nova-manage | 2 | ||||
-rw-r--r-- | nova/api/openstack/compute/contrib/disk_config.py | 2 | ||||
-rw-r--r-- | nova/api/openstack/compute/contrib/extended_status.py | 3 | ||||
-rw-r--r-- | nova/compute/api.py | 3 | ||||
-rw-r--r-- | nova/compute/manager.py | 7 | ||||
-rw-r--r-- | nova/exception.py | 16 | ||||
-rw-r--r-- | nova/scheduler/api.py | 2 | ||||
-rw-r--r-- | nova/tests/test_libvirt.py | 274 | ||||
-rw-r--r-- | nova/tests/test_virt_drivers.py | 9 | ||||
-rw-r--r-- | nova/tests/test_xenapi.py | 9 | ||||
-rw-r--r-- | nova/virt/driver.py | 4 | ||||
-rw-r--r-- | nova/virt/fake.py | 5 | ||||
-rw-r--r-- | nova/virt/libvirt/connection.py | 142 | ||||
-rw-r--r-- | nova/virt/libvirt/utils.py | 3 | ||||
-rw-r--r-- | nova/virt/vmwareapi/network_utils.py | 6 | ||||
-rw-r--r-- | nova/virt/xenapi_conn.py | 6 |
18 files changed, 463 insertions, 33 deletions
@@ -18,6 +18,7 @@ <corywright@gmail.com> <cory.wright@rackspace.com> <dan@nicira.com> <danwent@dan-xs3-cs> <dan@nicira.com> <danwent@gmail.com> +<derekh@redhat.com> <higginsd@gmail.com> <devin.carlen@gmail.com> <devcamcar@illian.local> <dprince@redhat.com> <dan.prince@rackspace.com> <edouard1.thuleau@orange.com> <thuleau@gmail.com> @@ -42,7 +42,7 @@ David Pravec <David.Pravec@danix.org> David Subiros <david.perez5@hp.com> Dean Troyer <dtroyer@gmail.com> Deepak Garg <deepak.garg@citrix.com> -Derek Higgins <higginsd@gmail.com> +Derek Higgins <derekh@redhat.com> Devdeep Singh <devdeep.singh@citrix.com> Devendra Modium <dmodium@isi.edu> Devin Carlen <devin.carlen@gmail.com> diff --git a/bin/nova-manage b/bin/nova-manage index a271cf2ff..49ec41656 100755 --- a/bin/nova-manage +++ b/bin/nova-manage @@ -616,7 +616,7 @@ class ProjectCommands(object): print e print _("The above error may show that the certificate db has " "not been created.\nPlease create a database by running " - "a nova-api server on this host.") + "a nova-cert server on this host.") AccountCommands = ProjectCommands diff --git a/nova/api/openstack/compute/contrib/disk_config.py b/nova/api/openstack/compute/contrib/disk_config.py index 46c09ffa8..5b249478a 100644 --- a/nova/api/openstack/compute/contrib/disk_config.py +++ b/nova/api/openstack/compute/contrib/disk_config.py @@ -106,6 +106,8 @@ class ServerDiskConfigController(wsgi.Controller): # Filter out any servers that already have the key set # (most likely from a remote zone) servers = [s for s in servers if API_DISK_CONFIG not in s] + if not servers: + return # Get DB information for servers uuids = [server['id'] for server in servers] diff --git a/nova/api/openstack/compute/contrib/extended_status.py b/nova/api/openstack/compute/contrib/extended_status.py index 55e4a3aee..9447bf300 100644 --- a/nova/api/openstack/compute/contrib/extended_status.py +++ b/nova/api/openstack/compute/contrib/extended_status.py @@ -36,6 +36,9 @@ class ExtendedStatusController(wsgi.Controller): self.compute_api = compute.API() def _get_instances(self, context, instance_uuids): + if not instance_uuids: + return {} + filters = {'uuid': instance_uuids} instances = self.compute_api.get_all(context, filters) return dict((instance['uuid'], instance) for instance in instances) diff --git a/nova/compute/api.py b/nova/compute/api.py index 30fe911ff..514f0c133 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -1729,6 +1729,9 @@ class API(base.Base): def get_instance_faults(self, context, instances): """Get all faults for a list of instance uuids.""" + if not instances: + return {} + for instance in instances: check_policy(context, 'get_instance_faults', instance) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 159aa8c76..3639541ff 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -1152,6 +1152,7 @@ class ComputeManager(manager.SchedulerDependentManager): migration_ref = self.db.migration_get(context, migration_id) instance_ref = self.db.instance_get_by_uuid(context, migration_ref.instance_uuid) + network_info = self._get_instance_nw_info(context, instance_ref) self._notify_about_instance_usage(instance_ref, "resize.revert.start") @@ -1171,7 +1172,8 @@ class ComputeManager(manager.SchedulerDependentManager): vm_state=vm_states.ACTIVE, task_state=None) - self.driver.finish_revert_migration(instance_ref) + self.driver.finish_revert_migration(instance_ref, + self._legacy_nw_info(network_info)) self.db.migration_update(context, migration_id, {'status': 'reverted'}) @@ -1239,6 +1241,7 @@ class ComputeManager(manager.SchedulerDependentManager): instance_type_ref = self.db.instance_type_get(context, migration_ref.new_instance_type_id) + network_info = self._get_instance_nw_info(context, instance_ref) self.db.migration_update(context, migration_id, {'status': 'migrating'}) @@ -1246,7 +1249,7 @@ class ComputeManager(manager.SchedulerDependentManager): try: disk_info = self.driver.migrate_disk_and_power_off( context, instance_ref, migration_ref['dest_host'], - instance_type_ref) + instance_type_ref, self._legacy_nw_info(network_info)) except Exception, error: with utils.save_and_reraise_exception(): msg = _('%s. Setting instance vm_state to ERROR') diff --git a/nova/exception.py b/nova/exception.py index dfa20dd25..9bb39b2f4 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -76,8 +76,7 @@ class ProcessExecutionError(IOError): class Error(Exception): - def __init__(self, message=None): - super(Error, self).__init__(message) + pass class EC2APIError(Error): @@ -207,9 +206,6 @@ class MelangeConnectionFailed(NovaException): class NotAuthorized(NovaException): message = _("Not authorized.") - def __init__(self, *args, **kwargs): - super(NotAuthorized, self).__init__(*args, **kwargs) - class AdminRequired(NotAuthorized): message = _("User does not have admin privileges") @@ -406,9 +402,6 @@ class InvalidEc2Id(Invalid): class NotFound(NovaException): message = _("Resource could not be found.") - def __init__(self, *args, **kwargs): - super(NotFound, self).__init__(*args, **kwargs) - class FlagNotSet(NotFound): message = _("Required flag %(flag)s not set.") @@ -911,11 +904,8 @@ class ImageTooLarge(NovaException): message = _("Image is larger than instance type allows") -class ZoneRequestError(Error): - def __init__(self, message=None): - if message is None: - message = _("1 or more Zones could not complete the request") - super(ZoneRequestError, self).__init__(message=message) +class ZoneRequestError(NovaException): + message = _("1 or more Zones could not complete the request") class InstanceTypeMemoryTooSmall(NovaException): diff --git a/nova/scheduler/api.py b/nova/scheduler/api.py index 9706a5d8e..68d4c29e7 100644 --- a/nova/scheduler/api.py +++ b/nova/scheduler/api.py @@ -259,7 +259,7 @@ class RedirectResult(exception.Error): def __init__(self, results): self.results = results super(RedirectResult, self).__init__( - message=_("Uncaught Zone redirection exception")) + _("Uncaught Zone redirection exception")) class reroute_compute(object): diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py index 66a8db2b5..2eede7ed5 100644 --- a/nova/tests/test_libvirt.py +++ b/nova/tests/test_libvirt.py @@ -20,6 +20,7 @@ import mox import os import re import shutil +import sys import tempfile from xml.etree.ElementTree import fromstring as xml_to_tree @@ -33,10 +34,12 @@ from nova import log as logging from nova import test from nova import utils from nova.api.ec2 import cloud +from nova.compute import instance_types from nova.compute import power_state from nova.compute import vm_states from nova.virt import images from nova.virt import driver +from nova.virt import firewall as base_firewall from nova.virt.libvirt import connection from nova.virt.libvirt import firewall from nova.virt.libvirt import volume @@ -1175,7 +1178,8 @@ class LibvirtConnTestCase(test.TestCase): conn = connection.LibvirtConnection(False) self.stubs.Set(conn, '_lookup_by_name', fake_lookup_by_name) - instance = {"name": "instancename", "id": "instanceid"} + instance = {"name": "instancename", "id": "instanceid", + "uuid": "875a8070-d0b9-4949-8b31-104d125c9a64"} conn.destroy(instance, []) @@ -1983,3 +1987,271 @@ disk size: 4.4M''', '')) self.mox.ReplayAll() libvirt_utils.fetch_image(context, target, image_id, user_id, project_id) + + +class LibvirtConnectionTestCase(test.TestCase): + """Test for nova.virt.libvirt.connection.LibvirtConnection.""" + def setUp(self): + super(LibvirtConnectionTestCase, self).setUp() + + self.libvirtconnection = connection.LibvirtConnection(read_only=True) + self.platform = sys.platform + self.exe_flag = False + + self.temp_path = os.path.join(flags.FLAGS.instances_path, + 'instance-00000001/', '') + try: + os.makedirs(self.temp_path) + except Exception: + print 'testcase init error' + pass + + def tearDown(self): + super(LibvirtConnectionTestCase, self).tearDown() + sys.platform = self.platform + + try: + shutil.rmtree(flags.FLAGS.instances_path) + except Exception: + pass + + class NullFirewallDriver(base_firewall.FirewallDriver): + def __init__(self, get_connection, **kwargs): + pass + + def prepare_instance_filter(self, instance, network_info): + pass + + def unfilter_instance(self, instance, network_info): + pass + + def apply_instance_filter(self, instance, network_info): + pass + + def refresh_security_group_rules(self, security_group_id): + pass + + def refresh_security_group_members(self, security_group_id): + pass + + def refresh_provider_fw_rules(self): + pass + + def setup_basic_filtering(self, instance, network_info): + pass + + def instance_filter_exists(self, instance, network_info): + return True + + def _create_instance(self, params=None): + """Create a test instance""" + if not params: + params = {} + + inst = {} + inst['image_ref'] = '1' + inst['reservation_id'] = 'r-fakeres' + inst['launch_time'] = '10' + inst['user_id'] = 'fake' + inst['project_id'] = 'fake' + type_id = instance_types.get_instance_type_by_name('m1.tiny')['id'] + inst['instance_type_id'] = type_id + inst['ami_launch_index'] = 0 + inst['host'] = 'host1' + inst['root_gb'] = 10 + inst['ephemeral_gb'] = 20 + inst['config_drive'] = 1 + inst['kernel_id'] = 2 + inst['ramdisk_id'] = 3 + inst['config_drive_id'] = 1 + inst['key_data'] = 'ABCDEFG' + + inst.update(params) + return db.instance_create(context.get_admin_context(), inst) + + def test_migrate_disk_and_power_off_exception(self): + """Test for nova.virt.libvirt.connection.LivirtConnection + .migrate_disk_and_power_off. """ + + self.counter = 0 + + def fake_get_instance_disk_info(instance): + return [] + + def fake_destroy(instance, network_info, cleanup=True): + pass + + def fake_get_host_ip_addr(): + return '10.0.0.1' + + def fake_execute(*args, **kwargs): + self.counter += 1 + if self.counter == 1: + raise Exception() + pass + + def fake_os_path_exists(path): + return True + + self.stubs.Set(self.libvirtconnection, 'get_instance_disk_info', + fake_get_instance_disk_info) + self.stubs.Set(self.libvirtconnection, '_destroy', fake_destroy) + self.stubs.Set(self.libvirtconnection, 'get_host_ip_addr', + fake_get_host_ip_addr) + self.stubs.Set(utils, 'execute', fake_execute) + self.stubs.Set(os.path, 'exists', fake_os_path_exists) + + ins_ref = self._create_instance() + self.assertRaises(Exception, + self.libvirtconnection.migrate_disk_and_power_off, + None, ins_ref, [], '10.0.0.2', None, None) + + def test_migrate_disk_and_power_off(self): + """Test for nova.virt.libvirt.connection.LivirtConnection + .migrate_disk_and_power_off. """ + + disk_info = [{'type': 'qcow2', 'path': '/test/disk', + 'virt_disk_size': '10737418240', + 'backing_file': '/base/disk', + 'disk_size':'83886080'}, + {'type': 'raw', 'path': '/test/disk.local', + 'virt_disk_size': '10737418240', + 'backing_file': '/base/disk.local', + 'disk_size':'83886080'}] + disk_info_text = utils.dumps(disk_info) + + def fake_get_instance_disk_info(instance): + return disk_info_text + + def fake_destroy(instance, network_info, cleanup=True): + pass + + def fake_get_host_ip_addr(): + return '10.0.0.1' + + def fake_execute(*args, **kwargs): + pass + + self.stubs.Set(self.libvirtconnection, 'get_instance_disk_info', + fake_get_instance_disk_info) + self.stubs.Set(self.libvirtconnection, '_destroy', fake_destroy) + self.stubs.Set(self.libvirtconnection, 'get_host_ip_addr', + fake_get_host_ip_addr) + self.stubs.Set(utils, 'execute', fake_execute) + + ins_ref = self._create_instance() + """ dest is different host case """ + out = self.libvirtconnection.migrate_disk_and_power_off( + None, ins_ref, '10.0.0.2', None, None) + self.assertEquals(out, disk_info_text) + + """ dest is same host case """ + out = self.libvirtconnection.migrate_disk_and_power_off( + None, ins_ref, '10.0.0.1', None, None) + self.assertEquals(out, disk_info_text) + + def test_wait_for_running(self): + """Test for nova.virt.libvirt.connection.LivirtConnection + ._wait_for_running. """ + + def fake_get_info(instance_name): + if instance_name == "not_found": + raise exception.NotFound + elif instance_name == "running": + return {'state': power_state.RUNNING} + else: + return {'state': power_state.SHUTOFF} + + self.stubs.Set(self.libvirtconnection, 'get_info', + fake_get_info) + + """ instance not found case """ + self.assertRaises(utils.LoopingCallDone, + self.libvirtconnection._wait_for_running, + "not_found") + + """ instance is running case """ + self.assertRaises(utils.LoopingCallDone, + self.libvirtconnection._wait_for_running, + "running") + + """ else case """ + self.libvirtconnection._wait_for_running("else") + + def test_finish_migration(self): + """Test for nova.virt.libvirt.connection.LivirtConnection + .finish_migration. """ + + disk_info = [{'type': 'qcow2', 'path': '/test/disk', + 'local_gb': 10, 'backing_file': '/base/disk'}, + {'type': 'raw', 'path': '/test/disk.local', + 'local_gb': 10, 'backing_file': '/base/disk.local'}] + disk_info_text = utils.dumps(disk_info) + + def fake_extend(path, size): + pass + + def fake_to_xml(instance, network_info): + return "" + + def fake_plug_vifs(instance, network_info): + pass + + def fake_create_image(context, inst, libvirt_xml, suffix='', + disk_images=None, network_info=None, + block_device_info=None): + pass + + def fake_create_new_domain(xml): + return None + + def fake_execute(*args, **kwargs): + pass + + self.flags(use_cow_images=True) + self.stubs.Set(connection.disk, 'extend', fake_extend) + self.stubs.Set(self.libvirtconnection, 'to_xml', fake_to_xml) + self.stubs.Set(self.libvirtconnection, 'plug_vifs', fake_plug_vifs) + self.stubs.Set(self.libvirtconnection, '_create_image', + fake_create_image) + self.stubs.Set(self.libvirtconnection, '_create_new_domain', + fake_create_new_domain) + self.stubs.Set(utils, 'execute', fake_execute) + fw = self.NullFirewallDriver(None) + self.stubs.Set(self.libvirtconnection, 'firewall_driver', fw) + + ins_ref = self._create_instance() + + ref = self.libvirtconnection.finish_migration( + context.get_admin_context(), None, ins_ref, + disk_info_text, None, None, None) + self.assertTrue(isinstance(ref, eventlet.event.Event)) + + def test_finish_revert_migration(self): + """Test for nova.virt.libvirt.connection.LivirtConnection + .finish_revert_migration. """ + + def fake_execute(*args, **kwargs): + pass + + def fake_plug_vifs(instance, network_info): + pass + + def fake_create_new_domain(xml): + return None + + self.stubs.Set(self.libvirtconnection, 'plug_vifs', fake_plug_vifs) + self.stubs.Set(utils, 'execute', fake_execute) + fw = self.NullFirewallDriver(None) + self.stubs.Set(self.libvirtconnection, 'firewall_driver', fw) + self.stubs.Set(self.libvirtconnection, '_create_new_domain', + fake_create_new_domain) + + ins_ref = self._create_instance() + libvirt_xml_path = os.path.join(flags.FLAGS.instances_path, + ins_ref['name'], 'libvirt.xml') + f = open(libvirt_xml_path, 'w') + f.close() + + ref = self.libvirtconnection.finish_revert_migration(ins_ref, None) + self.assertTrue(isinstance(ref, eventlet.event.Event)) diff --git a/nova/tests/test_virt_drivers.py b/nova/tests/test_virt_drivers.py index cf6632bda..41c5d118e 100644 --- a/nova/tests/test_virt_drivers.py +++ b/nova/tests/test_virt_drivers.py @@ -175,7 +175,8 @@ class _VirtDriverTestCase(test.TestCase): instance_ref, network_info = self._get_running_instance() instance_type_ref = test_utils.get_test_instance_type() self.connection.migrate_disk_and_power_off( - self.ctxt, instance_ref, 'dest_host', instance_type_ref) + self.ctxt, instance_ref, 'dest_host', instance_type_ref, + network_info) @catch_notimplementederror def test_pause(self): @@ -465,3 +466,9 @@ class LibvirtConnTestCase(_VirtDriverTestCase): nova.virt.libvirt.connection.libvirt_utils = self.saved_libvirt nova.virt.libvirt.firewall.libvirt = self.saved_libvirt super(LibvirtConnTestCase, self).tearDown() + + @test.skip_test("Test nothing, but this method " + "needed to override superclass.") + def test_migrate_disk_and_power_off(self): + # there is lack of fake stuff to execute this method. so pass. + pass diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index f3343519e..2b1f99f7b 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -694,7 +694,7 @@ class XenAPIVMTestCase(test.TestCase): conn = xenapi_conn.get_connection(False) conn._vmops = VMOpsMock() - conn.finish_revert_migration(instance) + conn.finish_revert_migration(instance, None) self.assertTrue(conn._vmops.finish_revert_migration_called) def _create_instance(self, instance_id=1, spawn=True): @@ -849,7 +849,7 @@ class XenAPIMigrateInstance(test.TestCase): stubs.stubout_session(self.stubs, stubs.FakeSessionForMigrationTests) conn = xenapi_conn.get_connection(False) conn.migrate_disk_and_power_off(self.context, instance, - '127.0.0.1', instance_type) + '127.0.0.1', instance_type, None) def test_migrate_disk_and_power_off_passes_exceptions(self): instance = db.instance_create(self.context, self.instance_values) @@ -863,7 +863,8 @@ class XenAPIMigrateInstance(test.TestCase): conn = xenapi_conn.get_connection(False) self.assertRaises(exception.MigrationError, conn.migrate_disk_and_power_off, - self.context, instance, '127.0.0.1', instance_type) + self.context, instance, + '127.0.0.1', instance_type, None) def test_revert_migrate(self): instance = db.instance_create(self.context, self.instance_values) @@ -910,7 +911,7 @@ class XenAPIMigrateInstance(test.TestCase): self.assertEqual(self.called, True) self.assertEqual(self.fake_vm_start_called, True) - conn.finish_revert_migration(instance) + conn.finish_revert_migration(instance, network_info) self.assertEqual(self.fake_finish_revert_migration_called, True) def test_finish_migrate(self): 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/vmwareapi/network_utils.py b/nova/virt/vmwareapi/network_utils.py index fb1873224..8fbe02dc3 100644 --- a/nova/virt/vmwareapi/network_utils.py +++ b/nova/virt/vmwareapi/network_utils.py @@ -125,10 +125,10 @@ def get_vlanid_and_vswitch_for_portgroup(session, pg_name): "get_dynamic_property", host_mor, "HostSystem", "config.network.portgroup") if not port_grps_on_host_ret: - excep = ("ESX SOAP server returned an empty port group " - "for the host system in its response") + excep = _("ESX SOAP server returned an empty port group " + "for the host system in its response") LOG.exception(excep) - raise exception.Error(_(excep)) + raise exception.Error(excep) port_grps_on_host = port_grps_on_host_ret.HostPortGroup for p_gp in port_grps_on_host: if p_gp.spec.name == pg_name: 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) |