def test_remove_base_file_original(self): with self._make_base_file() as fname: image_cache_manager = imagecache.ImageCacheManager() image_cache_manager.originals = [fname] image_cache_manager._remove_base_file(fname) info_fname = imagecache.get_info_filename(fname) # Files are initially too new to delete self.assertTrue(os.path.exists(fname)) self.assertTrue(os.path.exists(info_fname)) # This file should stay longer than a resized image os.utime(fname, (-1, time.time() - 3601)) image_cache_manager._remove_base_file(fname) self.assertTrue(os.path.exists(fname)) self.assertTrue(os.path.exists(info_fname)) # Originals don't stay forever though os.utime(fname, (-1, time.time() - 3600 * 25)) image_cache_manager._remove_base_file(fname) self.assertFalse(os.path.exists(fname)) self.assertFalse(os.path.exists(info_fname))
def test_verify_checksum_invalid(self): img = {'container_format': 'ami', 'id': '42'} self.flags(checksum_base_images=True) with self._intercept_log_messages() as stream: with utils.tempdir() as tmpdir: self.flags(instances_path=tmpdir) self.flags(image_info_filename_pattern=('$instances_path/' '%(image)s.info')) fname, info_fname, testdata = self._make_checksum(tmpdir) # Checksum is invalid, but is in valid json f = open(info_fname, 'w') f.write('{"sha1": "banana"}') f.close() image_cache_manager = imagecache.ImageCacheManager() res = image_cache_manager._verify_checksum(img, fname) self.assertFalse(res) log = stream.getvalue() self.assertNotEqual(log.find('image verification failed'), -1)
def test_find_base_file_all(self): fingerprint = '968dd6cc49e01aaa044ed11c0cce733e0fa44a6a' listing = ['00000001', 'ephemeral_0_20_None', '968dd6cc49e01aaa044ed11c0cce733e0fa44a6a_sm', '968dd6cc49e01aaa044ed11c0cce733e0fa44a6a_10737418240', '00000004'] self.stubs.Set(os, 'listdir', lambda x: listing) self.stubs.Set(os.path, 'exists', lambda x: True) self.stubs.Set(os.path, 'isfile', lambda x: True) base_dir = '/var/lib/nova/instances/_base' image_cache_manager = imagecache.ImageCacheManager() image_cache_manager._list_base_images(base_dir) res = list(image_cache_manager._find_base_file(base_dir, fingerprint)) base_file1 = os.path.join(base_dir, fingerprint) base_file2 = os.path.join(base_dir, fingerprint + '_sm') base_file3 = os.path.join(base_dir, fingerprint + '_10737418240') print res self.assertTrue(res == [(base_file1, False, False), (base_file2, True, False), (base_file3, False, True)])
def test_get_age_of_file_not_exists(self, mock_exists): image_cache_manager = imagecache.ImageCacheManager() exists, age = image_cache_manager._get_age_of_file('/tmp') self.assertFalse(exists) self.assertEqual(0, age)
def test_get_age_of_file(self, mock_getmtime, mock_time, mock_exists): image_cache_manager = imagecache.ImageCacheManager() exists, age = image_cache_manager._get_age_of_file('/tmp') self.assertTrue(exists) self.assertEqual(1000000, age)
def test_verify_base_images_no_base(self): self.flags(instances_path='/tmp/no/such/dir/name/please') image_cache_manager = imagecache.ImageCacheManager() image_cache_manager.update(None, [])
def test_verify_base_images(self, mock_lock, mock_utime): hashed_1 = '356a192b7913b04c54574d18c28d46e6395428ab' hashed_21 = '472b07b9fcf2c2451e8781e944bf5f77cd8457c8' hashed_22 = '12c6fc06c99a462375eeb3f43dfd832b08ca9e17' hashed_42 = '92cfceb39d57d914ed8b14d0e37643de0797ae56' self.flags(instances_path='/instance_path', image_cache_subdirectory_name='_base') base_file_list = [ '00000001', 'ephemeral_0_20_None', 'e97222e91fc4241f49a7f520d1dcf446751129b3_sm', 'e09c675c2d1cfac32dae3c2d83689c8c94bc693b_sm', hashed_42, hashed_1, hashed_21, hashed_22, '%s_5368709120' % hashed_1, '%s_10737418240' % hashed_1, '00000004' ] def fq_path(path): return os.path.join('/instance_path/_base/', path) # Fake base directory existence orig_exists = os.path.exists def exists(path): # The python coverage tool got angry with my overly broad mocks if not path.startswith('/instance_path'): return orig_exists(path) if path in [ '/instance_path', '/instance_path/_base', '/instance_path/instance-1/disk', '/instance_path/instance-2/disk', '/instance_path/instance-3/disk', '/instance_path/_base/%s.info' % hashed_42 ]: return True for p in base_file_list: if path == fq_path(p): return True if path == fq_path(p) + '.info': return False if path in [ '/instance_path/_base/%s_sm' % i for i in [hashed_1, hashed_21, hashed_22, hashed_42] ]: return False self.fail('Unexpected path existence check: %s' % path) self.stub_out('os.path.exists', lambda x: exists(x)) # Fake up some instances in the instances directory orig_listdir = os.listdir def listdir(path): # The python coverage tool got angry with my overly broad mocks if not path.startswith('/instance_path'): return orig_listdir(path) if path == '/instance_path': return ['instance-1', 'instance-2', 'instance-3', '_base'] if path == '/instance_path/_base': return base_file_list self.fail('Unexpected directory listed: %s' % path) self.stub_out('os.listdir', lambda x: listdir(x)) # Fake isfile for these faked images in _base orig_isfile = os.path.isfile def isfile(path): # The python coverage tool got angry with my overly broad mocks if not path.startswith('/instance_path'): return orig_isfile(path) for p in base_file_list: if path == fq_path(p): return True self.fail('Unexpected isfile call: %s' % path) self.stub_out('os.path.isfile', lambda x: isfile(x)) # Fake the database call which lists running instances instances = [{ 'image_ref': '1', 'host': CONF.host, 'name': 'instance-1', 'uuid': uuids.instance_1, 'vm_state': '', 'task_state': '' }, { 'image_ref': '1', 'kernel_id': '21', 'ramdisk_id': '22', 'host': CONF.host, 'name': 'instance-2', 'uuid': uuids.instance_2, 'vm_state': '', 'task_state': '' }] all_instances = [ fake_instance.fake_instance_obj(None, **instance) for instance in instances ] image_cache_manager = imagecache.ImageCacheManager() # Fake the utils call which finds the backing image def get_disk_backing_file(path): if path in [ '/instance_path/instance-1/disk', '/instance_path/instance-2/disk' ]: return fq_path('%s_5368709120' % hashed_1) self.fail('Unexpected backing file lookup: %s' % path) self.stub_out('nova.virt.libvirt.utils.get_disk_backing_file', lambda x: get_disk_backing_file(x)) # Fake getmtime as well orig_getmtime = os.path.getmtime def getmtime(path): if not path.startswith('/instance_path'): return orig_getmtime(path) return 1000000 self.stub_out('os.path.getmtime', lambda x: getmtime(x)) # Make sure we don't accidentally remove a real file orig_remove = os.remove def remove(path): if not path.startswith('/instance_path'): return orig_remove(path) # Don't try to remove fake files return self.stub_out('os.remove', lambda x: remove(x)) with mock.patch.object(objects.block_device.BlockDeviceMappingList, 'bdms_by_instance_uuid', return_value={}) as mock_bdms: ctxt = context.get_admin_context() # And finally we can make the call we're actually testing... # The argument here should be a context, but it is mocked out image_cache_manager.update(ctxt, all_instances) # Verify active = [ fq_path(hashed_1), fq_path('%s_5368709120' % hashed_1), fq_path(hashed_21), fq_path(hashed_22) ] for act in active: self.assertIn(act, image_cache_manager.active_base_files) self.assertEqual(len(image_cache_manager.active_base_files), len(active)) for rem in [ fq_path('e97222e91fc4241f49a7f520d1dcf446751129b3_sm'), fq_path('e09c675c2d1cfac32dae3c2d83689c8c94bc693b_sm'), fq_path(hashed_42), fq_path('%s_10737418240' % hashed_1) ]: self.assertIn(rem, image_cache_manager.removable_base_files) mock_bdms.assert_called_once_with( ctxt, [uuids.instance_1, uuids.instance_2])
def test_verify_base_images(self): hashed_1 = '356a192b7913b04c54574d18c28d46e6395428ab' hashed_42 = '92cfceb39d57d914ed8b14d0e37643de0797ae56' self.flags(instances_path='/instance_path') self.flags(remove_unused_base_images=True) base_file_list = [ '00000001', 'ephemeral_0_20_None', 'e97222e91fc4241f49a7f520d1dcf446751129b3_sm', 'e09c675c2d1cfac32dae3c2d83689c8c94bc693b_sm', hashed_42, hashed_1, '%s_5368709120' % hashed_1, '%s_10737418240' % hashed_1, '00000004' ] def fq_path(path): return os.path.join('/instance_path/_base/', path) # Fake base directory existance orig_exists = os.path.exists def exists(path): # The python coverage tool got angry with my overly broad mocks if not path.startswith('/instance_path'): return orig_exists(path) if path in [ '/instance_path', '/instance_path/_base', '/instance_path/instance-1/disk', '/instance_path/instance-2/disk', '/instance_path/instance-3/disk', '/instance_path/_base/%s.sha1' % hashed_42 ]: return True for p in base_file_list: if path == fq_path(p): return True if path == fq_path(p) + '.sha1': return False if path in [ '/instance_path/_base/%s_sm' % hashed_1, '/instance_path/_base/%s_sm' % hashed_42 ]: return False self.fail('Unexpected path existance check: %s' % path) self.stubs.Set(os.path, 'exists', lambda x: exists(x)) self.stubs.Set(virtutils, 'chown', lambda x, y: None) # We need to stub utime as well orig_utime = os.utime self.stubs.Set(os, 'utime', lambda x, y: None) # Fake up some instances in the instances directory orig_listdir = os.listdir def listdir(path): # The python coverage tool got angry with my overly broad mocks if not path.startswith('/instance_path'): return orig_list(path) if path == '/instance_path': return ['instance-1', 'instance-2', 'instance-3', '_base'] if path == '/instance_path/_base': return base_file_list self.fail('Unexpected directory listed: %s' % path) self.stubs.Set(os, 'listdir', lambda x: listdir(x)) # Fake isfile for these faked images in _base orig_isfile = os.path.isfile def isfile(path): # The python coverage tool got angry with my overly broad mocks if not path.startswith('/instance_path'): return orig_isfile(path) for p in base_file_list: if path == fq_path(p): return True self.fail('Unexpected isfile call: %s' % path) self.stubs.Set(os.path, 'isfile', lambda x: isfile(x)) # Fake the database call which lists running instances self.stubs.Set( db, 'instance_get_all', lambda x: [{ 'image_ref': '1', 'host': FLAGS.host, 'name': 'instance-1', 'uuid': '123' }, { 'image_ref': '1', 'host': FLAGS.host, 'name': 'instance-2', 'uuid': '456' }]) image_cache_manager = imagecache.ImageCacheManager() # Fake the utils call which finds the backing image def get_disk_backing_file(path): if path in [ '/instance_path/instance-1/disk', '/instance_path/instance-2/disk' ]: return fq_path('%s_5368709120' % hashed_1) self.fail('Unexpected backing file lookup: %s' % path) self.stubs.Set(virtutils, 'get_disk_backing_file', lambda x: get_disk_backing_file(x)) # Fake out verifying checksums, as that is tested elsewhere self.stubs.Set(image_cache_manager, '_verify_checksum', lambda x, y: y == hashed_42) # Fake getmtime as well orig_getmtime = os.path.getmtime def getmtime(path): if not path.startswith('/instance_path'): return orig_getmtime(path) return 1000000 self.stubs.Set(os.path, 'getmtime', lambda x: getmtime(x)) # Make sure we don't accidentally remove a real file orig_remove = os.remove def remove(path): if not path.startswith('/instance_path'): return orig_remove(path) # Don't try to remove fake files return self.stubs.Set(os, 'remove', lambda x: remove(x)) # And finally we can make the call we're actually testing... # The argument here should be a context, but it is mocked out image_cache_manager.verify_base_images(None) # Verify active = [fq_path(hashed_1), fq_path('%s_5368709120' % hashed_1)] self.assertEquals(image_cache_manager.active_base_files, active) for rem in [ fq_path('e97222e91fc4241f49a7f520d1dcf446751129b3_sm'), fq_path('e09c675c2d1cfac32dae3c2d83689c8c94bc693b_sm'), fq_path(hashed_42), fq_path('%s_10737418240' % hashed_1) ]: self.assertTrue(rem in image_cache_manager.removable_base_files) # Ensure there are no "corrupt" images as well self.assertTrue(len(image_cache_manager.corrupt_base_files), 0)
def test_configured_checksum_path(self): with utils.tempdir() as tmpdir: self.flags(instances_path=tmpdir) self.flags(image_info_filename_pattern=('$instances_path/' '%(image)s.info'), group='libvirt') # Ensure there is a base directory os.mkdir(os.path.join(tmpdir, '_base')) # Fake the database call which lists running instances instances = [{ 'image_ref': '1', 'host': CONF.host, 'name': 'instance-1', 'uuid': '123', 'vm_state': '', 'task_state': '' }, { 'image_ref': '1', 'host': CONF.host, 'name': 'instance-2', 'uuid': '456', 'vm_state': '', 'task_state': '' }] all_instances = [] for instance in instances: all_instances.append( fake_instance.fake_instance_obj(None, **instance)) def touch(filename): f = open(filename, 'w') f.write('Touched') f.close() old = time.time() - (25 * 3600) hashed = 'e97222e91fc4241f49a7f520d1dcf446751129b3' base_filename = os.path.join(tmpdir, hashed) touch(base_filename) touch(base_filename + '.info') os.utime(base_filename + '.info', (old, old)) touch(base_filename + '.info') os.utime(base_filename + '.info', (old, old)) self.mox.StubOutWithMock( objects.block_device.BlockDeviceMappingList, 'bdms_by_instance_uuid') ctxt = context.get_admin_context() objects.block_device.BlockDeviceMappingList.bdms_by_instance_uuid( ctxt, ['123', '456']).AndReturn({}) self.mox.ReplayAll() image_cache_manager = imagecache.ImageCacheManager() image_cache_manager.update(ctxt, all_instances) self.assertTrue(os.path.exists(base_filename)) self.assertTrue(os.path.exists(base_filename + '.info'))