Skip to content

Commit

Permalink
Avoid dangling partial image on size/checksum mismatch
Browse files Browse the repository at this point in the history
Fixes bug 1122299

Previously, when the supplied image size or checksum didn't match
the calculated values, partial image image data was left dangling
in the backend store.

Now, we clean up when the mismatch is detected.

Change-Id: I916d78ef3b2065e87df31ec4fb405915417d68aa
  • Loading branch information
Eoghan Glynn committed Feb 11, 2013
1 parent 98d9928 commit 03dc862
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 9 deletions.
14 changes: 9 additions & 5 deletions glance/api/v1/images.py
Expand Up @@ -445,6 +445,7 @@ def _kill_mismatched(image_meta, attr, actual):
"status to 'killed'.") % locals()
LOG.error(msg)
self._safe_kill(req, image_id)
self._initiate_deletion(req, location, image_id)
raise HTTPBadRequest(explanation=msg,
content_type="text/plain",
request=req)
Expand Down Expand Up @@ -810,6 +811,13 @@ def update(self, req, id, image_meta, image_data):

return {'image_meta': image_meta}

@staticmethod
def _initiate_deletion(req, location, id):
if CONF.delayed_delete:
schedule_delayed_delete_from_backend(location, id)
else:
safe_delete_from_backend(location, req.context, id)

@utils.mutating
def delete(self, req, id):
"""
Expand Down Expand Up @@ -856,11 +864,7 @@ def delete(self, req, id):
# to delete the image if the backend doesn't yet store it.
# See https://bugs.launchpad.net/glance/+bug/747799
if image['location']:
if CONF.delayed_delete:
schedule_delayed_delete_from_backend(image['location'], id)
else:
safe_delete_from_backend(image['location'],
req.context, id)
self._initiate_deletion(req, image['location'], id)
except exception.NotFound, e:
msg = ("Failed to find image to delete: %(e)s" % locals())
for line in msg.split('\n'):
Expand Down
29 changes: 25 additions & 4 deletions glance/tests/functional/v1/test_api.py
Expand Up @@ -20,6 +20,7 @@
import datetime
import hashlib
import json
import os
import tempfile

import httplib2
Expand Down Expand Up @@ -1452,21 +1453,41 @@ def test_ownership(self):

self.stop_servers()

@skip_if_disabled
def test_mismatched_size(self):
def _do_test_mismatched_attribute(self, attribute, value):
"""
Test mismatched size.
Test mismatched attribute.
"""
self.cleanup()
self.start_servers(**self.__dict__.copy())

image_data = "*" * FIVE_KB
headers = minimal_headers('Image1')
headers['x-image-meta-size'] = str(FIVE_KB + 1)
headers[attribute] = value
path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
http = httplib2.Http()
response, content = http.request(path, 'POST', headers=headers,
body=image_data)
self.assertEqual(response.status, 400)

images_dir = os.path.join(self.test_dir, 'images')
image_count = len([name for name in os.listdir(images_dir)
if os.path.isfile(name)])
self.assertEquals(image_count, 0)

self.stop_servers()

@skip_if_disabled
def test_mismatched_size(self):
"""
Test mismatched size.
"""
self._do_test_mismatched_attribute('x-image-meta-size',
str(FIVE_KB + 1))

@skip_if_disabled
def test_mismatched_checksum(self):
"""
Test mismatched checksum.
"""
self._do_test_mismatched_attribute('x-image-meta-checksum',
'foobar')

0 comments on commit 03dc862

Please sign in to comment.