summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/tests/test_imagecache.py6
-rw-r--r--nova/virt/libvirt/connection.py5
-rw-r--r--nova/virt/libvirt/imagecache.py53
3 files changed, 51 insertions, 13 deletions
diff --git a/nova/tests/test_imagecache.py b/nova/tests/test_imagecache.py
index 1df745cdb..224d7c2aa 100644
--- a/nova/tests/test_imagecache.py
+++ b/nova/tests/test_imagecache.py
@@ -284,6 +284,8 @@ class ImageCacheManagerTestCase(test.TestCase):
'operating system.')
img = {'container_format': 'ami', 'id': '42'}
+ self.flags(checksum_base_images=True)
+
try:
dirname = tempfile.mkdtemp()
fname = os.path.join(dirname, 'aaa')
@@ -318,6 +320,10 @@ class ImageCacheManagerTestCase(test.TestCase):
res = image_cache_manager._verify_checksum(img, fname)
self.assertEquals(res, None)
+ # Checksum requests for a file with no checksum now have the
+ # side effect of creating the checksum
+ self.assertTrue(os.path.exists('%s.sha1' % fname))
+
finally:
shutil.rmtree(dirname)
diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py
index e8fdcd792..634acdeca 100644
--- a/nova/virt/libvirt/connection.py
+++ b/nova/virt/libvirt/connection.py
@@ -921,6 +921,11 @@ class LibvirtConnection(driver.ComputeDriver):
If size is specified, we attempt to resize up to that size.
"""
+ # NOTE(mikal): Checksums aren't created here, even if the image cache
+ # manager is enabled, as that would slow down VM startup. If both
+ # cache management and checksumming are enabled, then the checksum
+ # will be created on the first pass of the image cache manager.
+
generating = 'image_id' not in kwargs
if not os.path.exists(target):
base_dir = os.path.join(FLAGS.instances_path, '_base')
diff --git a/nova/virt/libvirt/imagecache.py b/nova/virt/libvirt/imagecache.py
index bd714ea7f..6226e8d4e 100644
--- a/nova/virt/libvirt/imagecache.py
+++ b/nova/virt/libvirt/imagecache.py
@@ -55,6 +55,9 @@ imagecache_opts = [
default=(24 * 3600),
help='Unused unresized base images younger than this will not '
'be removed'),
+ cfg.BoolOpt('checksum_base_images',
+ default=False,
+ help='Write a checksum for files in _base to disk'),
]
flags.DECLARE('instances_path', 'nova.compute.manager')
@@ -77,6 +80,23 @@ def read_stored_checksum(base_file):
return stored_checksum
+def write_stored_checksum(target):
+ """Write a checksum to disk for a file in _base."""
+
+ checksum_filename = '%s.sha1' % 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
+ # encountered during verification.
+ sum_file = open(checksum_filename, 'w')
+ img_file = open(target, 'r')
+ checksum = utils.hash_file(img_file)
+ img_file.close()
+
+ sum_file.write(checksum)
+ sum_file.close()
+
+
class ImageCacheManager(object):
def __init__(self):
self.unexplained_images = []
@@ -200,13 +220,13 @@ class ImageCacheManager(object):
action occurs. This is something sysadmins should monitor for and
handle manually when it occurs.
"""
- f = open(base_file, 'r')
- current_checksum = utils.hash_file(f)
- f.close()
stored_checksum = read_stored_checksum(base_file)
-
if stored_checksum:
+ f = open(base_file, 'r')
+ current_checksum = utils.hash_file(f)
+ f.close()
+
if current_checksum != stored_checksum:
LOG.error(_('%(container_format)s-%(id)s '
'(%(base_file)s): '
@@ -225,6 +245,13 @@ class ImageCacheManager(object):
{'container_format': img['container_format'],
'id': img['id'],
'base_file': base_file})
+
+ # NOTE(mikal): If the checksum file is missing, then we should
+ # create one. We don't create checksums when we download images
+ # from glance because that would delay VM startup.
+ if FLAGS.checksum_base_images:
+ write_stored_checksum(base_file)
+
return None
def _remove_base_file(self, base_file):
@@ -335,15 +362,15 @@ class ImageCacheManager(object):
# TODO(mikal): Write a unit test for this method
# TODO(mikal): Handle "generated" images
- # The new scheme for base images is as follows -- an image is streamed
- # from the image service to _base (filename is the sha1 hash of the
- # image id). If CoW is enabled, that file is then resized to be the
- # correct size for the instance (filename is the same as the original,
- # but with an underscore and the resized size in bytes). This second
- # file is then CoW'd to the instance disk. If CoW is disabled, the
- # resize occurs as part of the copy from the cache to the instance
- # directory. Files ending in _sm are no longer created, but may remain
- # from previous versions.
+ # NOTE(mikal): The new scheme for base images is as follows -- an
+ # image is streamed from the image service to _base (filename is the
+ # sha1 hash of the image id). If CoW is enabled, that file is then
+ # resized to be the correct size for the instance (filename is the
+ # same as the original, but with an underscore and the resized size
+ # in bytes). This second file is then CoW'd to the instance disk. If
+ # CoW is disabled, the resize occurs as part of the copy from the
+ # cache to the instance directory. Files ending in _sm are no longer
+ # created, but may remain from previous versions.
self.unexplained_images = []
self.active_base_files = []