summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Still <mikal@stillhq.com>2012-04-18 07:37:09 +1000
committerMichael Still <mikal@stillhq.com>2012-04-26 09:57:01 +1000
commit181744d10a2e5b3f4bb33674c84fde5039e05396 (patch)
tree63c7d6b5cc1feea4947c613eee3be4a748d3431c
parentcaa1b282c701d5e9b9e02ffdb07d432d9b35ed13 (diff)
downloadnova-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.py71
-rw-r--r--nova/virt/libvirt/imagecache.py43
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: