From 68cc1cd511298208dde59878bfbef474a3625c9f Mon Sep 17 00:00:00 2001 From: Chang Bo Guo Date: Thu, 25 Apr 2013 23:40:12 -0700 Subject: Clean up failed image transfers in instance spawn Boot one instance with powervm driver, will transfer the image file to host. Need clean up failed image transfers that may occur during instance spawn. Fixes bug #1173017 Change-Id: Iff5ecd32e201333567a6a4de1d3796e78ea5dc0c --- nova/tests/virt/powervm/test_powervm.py | 67 +++++++++++++++++++++++++++++++++ nova/virt/powervm/blockdev.py | 49 ++++++++++++++---------- 2 files changed, 97 insertions(+), 19 deletions(-) diff --git a/nova/tests/virt/powervm/test_powervm.py b/nova/tests/virt/powervm/test_powervm.py index ef4ea4a43..a923d52ff 100644 --- a/nova/tests/virt/powervm/test_powervm.py +++ b/nova/tests/virt/powervm/test_powervm.py @@ -19,6 +19,7 @@ Test suite for PowerVMDriver. """ import contextlib +import os import paramiko from nova import context @@ -744,3 +745,69 @@ class PowerVMLocalVolumeAdapterTestCase(test.TestCase): self.powervm_adapter.create_volume_from_image, self.context, self.instance, self.image_id) self.assertTrue(self.delete_volume_called) + + def test_copy_image_file_wrong_checksum(self): + file_path = os.tempnam('/tmp', 'image') + remote_path = '/mnt/openstack/images' + exp_remote_path = os.path.join(remote_path, + os.path.basename(file_path)) + exp_cmd = ' '.join(['/usr/bin/rm -f', exp_remote_path]) + + def fake_md5sum_remote_file(remote_path): + return '3202937169' + + def fake_checksum_local_file(source_path): + return '3229026618' + + fake_noop = lambda *args, **kwargs: None + fake_op = self.powervm_adapter + self.stubs.Set(fake_op, 'run_vios_command', fake_noop) + self.stubs.Set(fake_op, '_md5sum_remote_file', + fake_md5sum_remote_file) + self.stubs.Set(fake_op, '_checksum_local_file', + fake_checksum_local_file) + self.stubs.Set(common, 'ftp_put_command', fake_noop) + + self.mox.StubOutWithMock(self.powervm_adapter, + 'run_vios_command_as_root') + self.powervm_adapter.run_vios_command_as_root(exp_cmd).AndReturn([]) + + self.mox.ReplayAll() + + self.assertRaises(exception.PowerVMFileTransferFailed, + self.powervm_adapter._copy_image_file, + file_path, remote_path) + + def test_checksum_local_file(self): + file_path = os.tempnam('/tmp', 'image') + img_file = file(file_path, 'w') + img_file.write('This is a test') + img_file.close() + exp_md5sum = 'ce114e4501d2f4e2dcea3e17b546f339' + + self.assertEqual(self.powervm_adapter._checksum_local_file(file_path), + exp_md5sum) + os.remove(file_path) + + def test_copy_image_file_from_host_with_wrong_checksum(self): + local_path = 'some/tmp' + remote_path = os.tempnam('/mnt/openstack/images', 'image') + + def fake_md5sum_remote_file(remote_path): + return '3202937169' + + def fake_checksum_local_file(source_path): + return '3229026618' + + fake_noop = lambda *args, **kwargs: None + fake_op = self.powervm_adapter + self.stubs.Set(fake_op, 'run_vios_command_as_root', fake_noop) + self.stubs.Set(fake_op, '_md5sum_remote_file', + fake_md5sum_remote_file) + self.stubs.Set(fake_op, '_checksum_local_file', + fake_checksum_local_file) + self.stubs.Set(common, 'ftp_get_command', fake_noop) + + self.assertRaises(exception.PowerVMFileTransferFailed, + self.powervm_adapter._copy_image_file_from_host, + remote_path, local_path) diff --git a/nova/virt/powervm/blockdev.py b/nova/virt/powervm/blockdev.py index 5e207e1f2..73099b148 100644 --- a/nova/virt/powervm/blockdev.py +++ b/nova/virt/powervm/blockdev.py @@ -384,6 +384,22 @@ class PowerVMLocalVolumeAdapter(PowerVMDiskAdapter): output = self.run_vios_command_as_root(cmd) return output[0] + def _checksum_local_file(self, source_path): + """Calculate local file checksum. + + :param source_path: source file path + :returns: string -- the md5sum of local file + """ + with open(source_path, 'r') as img_file: + hasher = hashlib.md5() + block_size = 0x10000 + buf = img_file.read(block_size) + while len(buf) > 0: + hasher.update(buf) + buf = img_file.read(block_size) + source_cksum = hasher.hexdigest() + return source_cksum + def _copy_image_file(self, source_path, remote_path, decompress=False): """Copy file to VIOS, decompress it, and return its new size and name. @@ -393,14 +409,7 @@ class PowerVMLocalVolumeAdapter(PowerVMDiskAdapter): if False (default), just copies the file """ # Calculate source image checksum - hasher = hashlib.md5() - block_size = 0x10000 - img_file = file(source_path, 'r') - buf = img_file.read(block_size) - while len(buf) > 0: - hasher.update(buf) - buf = img_file.read(block_size) - source_cksum = hasher.hexdigest() + source_cksum = self._checksum_local_file(source_path) comp_path = os.path.join(remote_path, os.path.basename(source_path)) if comp_path.endswith(".gz"): @@ -426,10 +435,18 @@ class PowerVMLocalVolumeAdapter(PowerVMDiskAdapter): output = self._md5sum_remote_file(final_path) if not output: LOG.error(_("Unable to get checksum")) - raise exception.PowerVMFileTransferFailed() + # Cleanup inconsistent remote file + cmd = "/usr/bin/rm -f %s" % final_path + self.run_vios_command_as_root(cmd) + + raise exception.PowerVMFileTransferFailed(file_path=final_path) if source_cksum != output.split(' ')[0]: LOG.error(_("Image checksums do not match")) - raise exception.PowerVMFileTransferFailed() + # Cleanup inconsistent remote file + cmd = "/usr/bin/rm -f %s" % final_path + self.run_vios_command_as_root(cmd) + + raise exception.PowerVMFileTransferFailed(file_path=final_path) if decompress: # Unzip the image @@ -509,19 +526,13 @@ class PowerVMLocalVolumeAdapter(PowerVMDiskAdapter): local_file_path) # Calculate copied image checksum - with open(local_file_path, 'r') as image_file: - hasher = hashlib.md5() - block_size = 0x10000 - buf = image_file.read(block_size) - while len(buf) > 0: - hasher.update(buf) - buf = image_file.read(block_size) - dest_chksum = hasher.hexdigest() + dest_chksum = self._checksum_local_file(local_file_path) # do comparison if source_chksum and dest_chksum != source_chksum: LOG.error(_("Image checksums do not match")) - raise exception.PowerVMFileTransferFailed() + raise exception.PowerVMFileTransferFailed( + file_path=local_file_path) # Cleanup transferred remote file cmd = "/usr/bin/rm -f %s" % copy_from_path -- cgit