diff options
| author | Michael Still <mikal@stillhq.com> | 2012-04-18 07:37:09 +1000 |
|---|---|---|
| committer | Michael Still <mikal@stillhq.com> | 2012-04-26 09:57:01 +1000 |
| commit | 181744d10a2e5b3f4bb33674c84fde5039e05396 (patch) | |
| tree | 63c7d6b5cc1feea4947c613eee3be4a748d3431c | |
| parent | caa1b282c701d5e9b9e02ffdb07d432d9b35ed13 (diff) | |
| download | nova-181744d10a2e5b3f4bb33674c84fde5039e05396.tar.gz nova-181744d10a2e5b3f4bb33674c84fde5039e05396.tar.xz nova-181744d10a2e5b3f4bb33674c84fde5039e05396.zip | |
Make the filename that image hashes are written to configurable.
This is a baby step towards storing more than just a checksum in
these files. The specific use case is I need to store whether or
not the image was prefetched in here as well.
Change-Id: Ia1d67ac1ac766f22c6ecb814182150a789c91095
| -rw-r--r-- | nova/tests/test_imagecache.py | 71 | ||||
| -rw-r--r-- | nova/virt/libvirt/imagecache.py | 43 |
2 files changed, 109 insertions, 5 deletions
diff --git a/nova/tests/test_imagecache.py b/nova/tests/test_imagecache.py index 219d003bb..6de3722eb 100644 --- a/nova/tests/test_imagecache.py +++ b/nova/tests/test_imagecache.py @@ -59,6 +59,10 @@ class ImageCacheManagerTestCase(test.TestCase): def test_read_stored_checksum(self): with utils.tempdir() as tmpdir: + self.flags(instances_path=tmpdir) + self.flags(image_info_filename_pattern=('$instances_path/' + '%(image)s.sha1')) + fname = os.path.join(tmpdir, 'aaa') csum_input = 'fdghkfhkgjjksfdgjksjkghsdf' @@ -86,6 +90,8 @@ class ImageCacheManagerTestCase(test.TestCase): self.stubs.Set(os.path, 'isfile', lambda x: True) base_dir = '/var/lib/nova/instances/_base' + self.flags(instances_path='/var/lib/nova/instances') + image_cache_manager = imagecache.ImageCacheManager() image_cache_manager._list_base_images(base_dir) @@ -299,6 +305,10 @@ class ImageCacheManagerTestCase(test.TestCase): 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.sha1')) + fname = os.path.join(tmpdir, 'aaa') f = open(fname, 'w') @@ -342,6 +352,10 @@ class ImageCacheManagerTestCase(test.TestCase): """Make a base file for testing.""" with utils.tempdir() as tmpdir: + self.flags(instances_path=tmpdir) + self.flags(image_info_filename_pattern=('$instances_path/' + '%(image)s.sha1')) + fname = os.path.join(tmpdir, 'aaa') base_file = open(fname, 'w') @@ -679,3 +693,60 @@ class ImageCacheManagerTestCase(test.TestCase): self.flags(instances_path='/tmp/no/such/dir/name/please') image_cache_manager = imagecache.ImageCacheManager() image_cache_manager.verify_base_images(None) + + def test_is_valid_info_file(self): + hashed = 'e97222e91fc4241f49a7f520d1dcf446751129b3' + + self.flags(instances_path='/tmp/no/such/dir/name/please') + self.flags(image_info_filename_pattern=('$instances_path/_base/' + '%(image)s.info')) + base_filename = os.path.join(FLAGS.instances_path, '_base', hashed) + + self.assertFalse(imagecache.is_valid_info_file('banana')) + self.assertFalse(imagecache.is_valid_info_file( + os.path.join(FLAGS.instances_path, '_base', '00000001'))) + self.assertFalse(imagecache.is_valid_info_file(base_filename)) + self.assertFalse(imagecache.is_valid_info_file(base_filename + + '.sha1')) + self.assertTrue(imagecache.is_valid_info_file(base_filename + '.info')) + + 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')) + self.flags(remove_unused_base_images=True) + + # Ensure there is a base directory + os.mkdir(os.path.join(tmpdir, '_base')) + + # 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'}]) + + 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 + '.sha1') + os.utime(base_filename + '.sha1', (old, old)) + + image_cache_manager = imagecache.ImageCacheManager() + image_cache_manager.verify_base_images(None) + + self.assertTrue(os.path.exists(base_filename)) + self.assertTrue(os.path.exists(base_filename + '.info')) diff --git a/nova/virt/libvirt/imagecache.py b/nova/virt/libvirt/imagecache.py index adf821400..5c8eba66f 100644 --- a/nova/virt/libvirt/imagecache.py +++ b/nova/virt/libvirt/imagecache.py @@ -55,6 +55,10 @@ imagecache_opts = [ cfg.BoolOpt('checksum_base_images', default=False, help='Write a checksum for files in _base to disk'), + cfg.StrOpt('image_info_filename_pattern', + default='$instances_path/$base_dir_name/%(image)s.sha1', + help='Allows image information files to be stored in ' + 'non-standard locations'), ] flags.DECLARE('instances_path', 'nova.compute.manager') @@ -63,12 +67,41 @@ FLAGS = flags.FLAGS FLAGS.register_opts(imagecache_opts) -def read_stored_checksum(base_file): +def get_info_filename(base_path): + """Construct a filename for storing addtional information about a base + image. + + Returns a filename. + """ + + base_file = os.path.basename(base_path) + return (FLAGS.image_info_filename_pattern + % {'image': base_file}) + + +def is_valid_info_file(path): + """Test if a given path matches the pattern for info files.""" + + digest_size = hashlib.sha1().digestsize * 2 + regexp = (FLAGS.image_info_filename_pattern + % {'instances_path': FLAGS.instances_path, + 'image': ('([0-9a-f]{%(digest_size)d}|' + '[0-9a-f]{%(digest_size)d}_sm|' + '[0-9a-f]{%(digest_size)d}_[0-9]+)' + % {'digest_size': digest_size})}) + m = re.match(regexp, path) + if m: + return True + return False + + +def read_stored_checksum(base_path): """Read the checksum which was created at image fetch time. Returns the checksum (as hex) or None. """ - checksum_file = '%s.sha1' % base_file + + checksum_file = get_info_filename(base_path) if not os.path.exists(checksum_file): return None @@ -81,7 +114,7 @@ def read_stored_checksum(base_file): def write_stored_checksum(target): """Write a checksum to disk for a file in _base.""" - checksum_filename = '%s.sha1' % target + checksum_filename = get_info_filename(target) if os.path.exists(target) and not os.path.exists(checksum_filename): # NOTE(mikal): Create the checksum file first to exclude possible # overlap in checksum operations. An empty checksum file is ignored if @@ -137,7 +170,7 @@ class ImageCacheManager(object): elif (len(ent) > digest_size + 2 and ent[digest_size] == '_' and - not ent.endswith('.sha1')): + not is_valid_info_file(os.path.join(base_dir, ent))): self._store_image(base_dir, ent, original=False) def _list_running_instances(self, context): @@ -283,7 +316,7 @@ class ImageCacheManager(object): LOG.info(_('Removing base file: %s'), base_file) try: os.remove(base_file) - signature = base_file + '.sha1' + signature = get_info_filename(base_file) if os.path.exists(signature): os.remove(signature) except OSError, e: |
