Recache or rebuild missing images on hard_reboot
The primary purpose of this change is to provide the ability to re-cache missing backing files on hard_reboot. The old pre_block_migration function was already performing a very similar operation. That function has been refactored to be idempotent and renamed to _create_images_and_backing. The pre_block_migration function is a wrapper, with some additional checking, around the renamed function. Image backend was also adjusted to look for either a missing backing file or disk image, recaching or creating accordingly. It should also be idempotent, never clobbering existing images. Change-Id: Icf4c488d6db59e732b463d08d0606b428ee1e7b9
This commit is contained in:
		@@ -486,7 +486,8 @@ class HyperVAPITestCase(test.TestCase):
 | 
				
			|||||||
                                     constants.HYPERV_VM_STATE_REBOOT)
 | 
					                                     constants.HYPERV_VM_STATE_REBOOT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self._mox.ReplayAll()
 | 
					        self._mox.ReplayAll()
 | 
				
			||||||
        self._conn.reboot(self._instance_data, network_info, None)
 | 
					        self._conn.reboot(self._context, self._instance_data, network_info,
 | 
				
			||||||
 | 
					                          None)
 | 
				
			||||||
        self._mox.VerifyAll()
 | 
					        self._mox.VerifyAll()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_destroy(self):
 | 
					    def test_destroy(self):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,8 +55,8 @@ class _ImageTestCase(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def test_cache(self):
 | 
					    def test_cache(self):
 | 
				
			||||||
        self.mox.StubOutWithMock(os.path, 'exists')
 | 
					        self.mox.StubOutWithMock(os.path, 'exists')
 | 
				
			||||||
        os.path.exists(self.PATH).AndReturn(False)
 | 
					 | 
				
			||||||
        os.path.exists(self.TEMPLATE_DIR).AndReturn(False)
 | 
					        os.path.exists(self.TEMPLATE_DIR).AndReturn(False)
 | 
				
			||||||
 | 
					        os.path.exists(self.PATH).AndReturn(False)
 | 
				
			||||||
        os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
 | 
					        os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
 | 
				
			||||||
        fn = self.mox.CreateMockAnything()
 | 
					        fn = self.mox.CreateMockAnything()
 | 
				
			||||||
        fn(target=self.TEMPLATE_PATH)
 | 
					        fn(target=self.TEMPLATE_PATH)
 | 
				
			||||||
@@ -72,7 +72,9 @@ class _ImageTestCase(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def test_cache_image_exists(self):
 | 
					    def test_cache_image_exists(self):
 | 
				
			||||||
        self.mox.StubOutWithMock(os.path, 'exists')
 | 
					        self.mox.StubOutWithMock(os.path, 'exists')
 | 
				
			||||||
 | 
					        os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
 | 
				
			||||||
        os.path.exists(self.PATH).AndReturn(True)
 | 
					        os.path.exists(self.PATH).AndReturn(True)
 | 
				
			||||||
 | 
					        os.path.exists(self.TEMPLATE_PATH).AndReturn(True)
 | 
				
			||||||
        self.mox.ReplayAll()
 | 
					        self.mox.ReplayAll()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        image = self.image_class(self.INSTANCE, self.NAME)
 | 
					        image = self.image_class(self.INSTANCE, self.NAME)
 | 
				
			||||||
@@ -82,8 +84,8 @@ class _ImageTestCase(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def test_cache_base_dir_exists(self):
 | 
					    def test_cache_base_dir_exists(self):
 | 
				
			||||||
        self.mox.StubOutWithMock(os.path, 'exists')
 | 
					        self.mox.StubOutWithMock(os.path, 'exists')
 | 
				
			||||||
        os.path.exists(self.PATH).AndReturn(False)
 | 
					 | 
				
			||||||
        os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
 | 
					        os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
 | 
				
			||||||
 | 
					        os.path.exists(self.PATH).AndReturn(False)
 | 
				
			||||||
        os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
 | 
					        os.path.exists(self.TEMPLATE_PATH).AndReturn(False)
 | 
				
			||||||
        fn = self.mox.CreateMockAnything()
 | 
					        fn = self.mox.CreateMockAnything()
 | 
				
			||||||
        fn(target=self.TEMPLATE_PATH)
 | 
					        fn(target=self.TEMPLATE_PATH)
 | 
				
			||||||
@@ -98,8 +100,8 @@ class _ImageTestCase(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def test_cache_template_exists(self):
 | 
					    def test_cache_template_exists(self):
 | 
				
			||||||
        self.mox.StubOutWithMock(os.path, 'exists')
 | 
					        self.mox.StubOutWithMock(os.path, 'exists')
 | 
				
			||||||
        os.path.exists(self.PATH).AndReturn(False)
 | 
					 | 
				
			||||||
        os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
 | 
					        os.path.exists(self.TEMPLATE_DIR).AndReturn(True)
 | 
				
			||||||
 | 
					        os.path.exists(self.PATH).AndReturn(False)
 | 
				
			||||||
        os.path.exists(self.TEMPLATE_PATH).AndReturn(True)
 | 
					        os.path.exists(self.TEMPLATE_PATH).AndReturn(True)
 | 
				
			||||||
        fn = self.mox.CreateMockAnything()
 | 
					        fn = self.mox.CreateMockAnything()
 | 
				
			||||||
        self.mox.ReplayAll()
 | 
					        self.mox.ReplayAll()
 | 
				
			||||||
@@ -195,7 +197,6 @@ class Qcow2TestCase(_ImageTestCase, test.TestCase):
 | 
				
			|||||||
    def test_create_image_with_size(self):
 | 
					    def test_create_image_with_size(self):
 | 
				
			||||||
        fn = self.prepare_mocks()
 | 
					        fn = self.prepare_mocks()
 | 
				
			||||||
        fn(target=self.TEMPLATE_PATH)
 | 
					        fn(target=self.TEMPLATE_PATH)
 | 
				
			||||||
        self.mox.StubOutWithMock(os.path, 'exists')
 | 
					 | 
				
			||||||
        imagebackend.libvirt_utils.create_cow_image(self.TEMPLATE_PATH,
 | 
					        imagebackend.libvirt_utils.create_cow_image(self.TEMPLATE_PATH,
 | 
				
			||||||
                                                    self.PATH)
 | 
					                                                    self.PATH)
 | 
				
			||||||
        imagebackend.disk.extend(self.PATH, self.SIZE)
 | 
					        imagebackend.disk.extend(self.PATH, self.SIZE)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4206,7 +4206,7 @@ class LibvirtDriverTestCase(test.TestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        self.counter = 0
 | 
					        self.counter = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def fake_get_instance_disk_info(instance):
 | 
					        def fake_get_instance_disk_info(instance, xml=None):
 | 
				
			||||||
            return '[]'
 | 
					            return '[]'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def fake_destroy(instance):
 | 
					        def fake_destroy(instance):
 | 
				
			||||||
@@ -4251,7 +4251,7 @@ class LibvirtDriverTestCase(test.TestCase):
 | 
				
			|||||||
                      'disk_size':'83886080'}]
 | 
					                      'disk_size':'83886080'}]
 | 
				
			||||||
        disk_info_text = jsonutils.dumps(disk_info)
 | 
					        disk_info_text = jsonutils.dumps(disk_info)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def fake_get_instance_disk_info(instance):
 | 
					        def fake_get_instance_disk_info(instance, xml=None):
 | 
				
			||||||
            return disk_info_text
 | 
					            return disk_info_text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        def fake_destroy(instance):
 | 
					        def fake_destroy(instance):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -104,6 +104,13 @@ class _FakeDriverBackendTestCase(object):
 | 
				
			|||||||
        def fake_make_drive(_self, _path):
 | 
					        def fake_make_drive(_self, _path):
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def fake_get_instance_disk_info(_self, instance, xml=None):
 | 
				
			||||||
 | 
					            return '[]'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.stubs.Set(nova.virt.libvirt.driver.LibvirtDriver,
 | 
				
			||||||
 | 
					                       'get_instance_disk_info',
 | 
				
			||||||
 | 
					                       fake_get_instance_disk_info)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.stubs.Set(nova.virt.libvirt.driver.disk,
 | 
					        self.stubs.Set(nova.virt.libvirt.driver.disk,
 | 
				
			||||||
                       'extend', fake_extend)
 | 
					                       'extend', fake_extend)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -227,7 +234,8 @@ class _VirtDriverTestCase(_FakeDriverBackendTestCase):
 | 
				
			|||||||
    def test_reboot(self):
 | 
					    def test_reboot(self):
 | 
				
			||||||
        reboot_type = "SOFT"
 | 
					        reboot_type = "SOFT"
 | 
				
			||||||
        instance_ref, network_info = self._get_running_instance()
 | 
					        instance_ref, network_info = self._get_running_instance()
 | 
				
			||||||
        self.connection.reboot(instance_ref, network_info, reboot_type)
 | 
					        self.connection.reboot(self.ctxt, instance_ref, network_info,
 | 
				
			||||||
 | 
					                               reboot_type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @catch_notimplementederror
 | 
					    @catch_notimplementederror
 | 
				
			||||||
    def test_get_host_ip_addr(self):
 | 
					    def test_get_host_ip_addr(self):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -199,14 +199,16 @@ class VMwareAPIVMTestCase(test.TestCase):
 | 
				
			|||||||
        info = self.conn.get_info({'name': 1})
 | 
					        info = self.conn.get_info({'name': 1})
 | 
				
			||||||
        self._check_vm_info(info, power_state.RUNNING)
 | 
					        self._check_vm_info(info, power_state.RUNNING)
 | 
				
			||||||
        reboot_type = "SOFT"
 | 
					        reboot_type = "SOFT"
 | 
				
			||||||
        self.conn.reboot(self.instance, self.network_info, reboot_type)
 | 
					        self.conn.reboot(self.context, self.instance, self.network_info,
 | 
				
			||||||
 | 
					                         reboot_type)
 | 
				
			||||||
        info = self.conn.get_info({'name': 1})
 | 
					        info = self.conn.get_info({'name': 1})
 | 
				
			||||||
        self._check_vm_info(info, power_state.RUNNING)
 | 
					        self._check_vm_info(info, power_state.RUNNING)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_reboot_non_existent(self):
 | 
					    def test_reboot_non_existent(self):
 | 
				
			||||||
        self._create_instance_in_the_db()
 | 
					        self._create_instance_in_the_db()
 | 
				
			||||||
        self.assertRaises(exception.InstanceNotFound, self.conn.reboot,
 | 
					        self.assertRaises(exception.InstanceNotFound, self.conn.reboot,
 | 
				
			||||||
                          self.instance, self.network_info, 'SOFT')
 | 
					                          self.context, self.instance, self.network_info,
 | 
				
			||||||
 | 
					                          'SOFT')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_reboot_not_poweredon(self):
 | 
					    def test_reboot_not_poweredon(self):
 | 
				
			||||||
        self._create_vm()
 | 
					        self._create_vm()
 | 
				
			||||||
@@ -216,7 +218,8 @@ class VMwareAPIVMTestCase(test.TestCase):
 | 
				
			|||||||
        info = self.conn.get_info({'name': 1})
 | 
					        info = self.conn.get_info({'name': 1})
 | 
				
			||||||
        self._check_vm_info(info, power_state.SUSPENDED)
 | 
					        self._check_vm_info(info, power_state.SUSPENDED)
 | 
				
			||||||
        self.assertRaises(exception.InstanceRebootFailure, self.conn.reboot,
 | 
					        self.assertRaises(exception.InstanceRebootFailure, self.conn.reboot,
 | 
				
			||||||
                          self.instance, self.network_info, 'SOFT')
 | 
					                          self.context, self.instance, self.network_info,
 | 
				
			||||||
 | 
					                          'SOFT')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_suspend(self):
 | 
					    def test_suspend(self):
 | 
				
			||||||
        self._create_vm()
 | 
					        self._create_vm()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -954,12 +954,12 @@ class XenAPIVMTestCase(stubs.XenAPITestBase):
 | 
				
			|||||||
    def test_reboot_hard(self):
 | 
					    def test_reboot_hard(self):
 | 
				
			||||||
        instance = self._create_instance()
 | 
					        instance = self._create_instance()
 | 
				
			||||||
        conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
 | 
					        conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
 | 
				
			||||||
        conn.reboot(instance, None, "HARD")
 | 
					        conn.reboot(self.context, instance, None, "HARD")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_reboot_soft(self):
 | 
					    def test_reboot_soft(self):
 | 
				
			||||||
        instance = self._create_instance()
 | 
					        instance = self._create_instance()
 | 
				
			||||||
        conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
 | 
					        conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
 | 
				
			||||||
        conn.reboot(instance, None, "SOFT")
 | 
					        conn.reboot(self.context, instance, None, "SOFT")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_reboot_halted(self):
 | 
					    def test_reboot_halted(self):
 | 
				
			||||||
        session = xenapi_conn.XenAPISession('test_url', 'root', 'test_pass',
 | 
					        session = xenapi_conn.XenAPISession('test_url', 'root', 'test_pass',
 | 
				
			||||||
@@ -967,7 +967,7 @@ class XenAPIVMTestCase(stubs.XenAPITestBase):
 | 
				
			|||||||
        instance = self._create_instance(spawn=False)
 | 
					        instance = self._create_instance(spawn=False)
 | 
				
			||||||
        conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
 | 
					        conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
 | 
				
			||||||
        xenapi_fake.create_vm(instance['name'], 'Halted')
 | 
					        xenapi_fake.create_vm(instance['name'], 'Halted')
 | 
				
			||||||
        conn.reboot(instance, None, "SOFT")
 | 
					        conn.reboot(self.context, instance, None, "SOFT")
 | 
				
			||||||
        vm_ref = vm_utils.lookup(session, instance['name'])
 | 
					        vm_ref = vm_utils.lookup(session, instance['name'])
 | 
				
			||||||
        vm = xenapi_fake.get_record('VM', vm_ref)
 | 
					        vm = xenapi_fake.get_record('VM', vm_ref)
 | 
				
			||||||
        self.assertEquals(vm['power_state'], 'Running')
 | 
					        self.assertEquals(vm['power_state'], 'Running')
 | 
				
			||||||
@@ -976,8 +976,8 @@ class XenAPIVMTestCase(stubs.XenAPITestBase):
 | 
				
			|||||||
        instance = self._create_instance(spawn=False)
 | 
					        instance = self._create_instance(spawn=False)
 | 
				
			||||||
        conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
 | 
					        conn = xenapi_conn.XenAPIDriver(fake.FakeVirtAPI(), False)
 | 
				
			||||||
        xenapi_fake.create_vm(instance['name'], 'Unknown')
 | 
					        xenapi_fake.create_vm(instance['name'], 'Unknown')
 | 
				
			||||||
        self.assertRaises(xenapi_fake.Failure, conn.reboot, instance,
 | 
					        self.assertRaises(xenapi_fake.Failure, conn.reboot, self.context,
 | 
				
			||||||
                None, "SOFT")
 | 
					                          instance, None, "SOFT")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _test_maintenance_mode(self, find_host, find_aggregate):
 | 
					    def _test_maintenance_mode(self, find_host, find_aggregate):
 | 
				
			||||||
        real_call_xenapi = self.conn._session.call_xenapi
 | 
					        real_call_xenapi = self.conn._session.call_xenapi
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user