Disallow image uploads in v2 API when data exists

When data has already been uploaded for an image (determined by the existence
of a location attribute), reject any subsequent requests to upload data with
a 409 HTTP error code.

* Related to bp api-v2-image-upload

Change-Id: I0c4d2ebf548862ecb9c760bac9e96348f8377567
This commit is contained in:
Brian Waldon 2012-05-04 14:22:12 -07:00
parent 793bb61005
commit f9afe586b6
5 changed files with 51 additions and 10 deletions

View File

@ -43,9 +43,12 @@ class ImageDataController(base.Controller):
def upload(self, req, image_id, data):
self._get_image(req.context, image_id)
size = len(data)
try:
location, size, checksum = self.store_api.add_to_backend(
'file', image_id, data, size)
'file', image_id, data, len(data))
except exception.Duplicate:
raise webob.exc.HTTPConflict()
self.db_api.image_update(req.context, image_id, {'location': location})
def download(self, req, image_id):

View File

@ -140,3 +140,36 @@ class TestImages(functional.FunctionalTest):
self.assertEqual(0, len(images))
self.stop_servers()
def test_upload_duplicate_data(self):
# Create an image
path = self._url('/v2/images')
headers = self._headers({'content-type': 'application/json'})
data = json.dumps({'name': 'image-1'})
response = requests.post(path, headers=headers, data=data)
self.assertEqual(200, response.status_code)
# Returned image entity should have a generated id
image = json.loads(response.text)['image']
image_id = image['id']
# Upload some image data
path = self._url('/v2/images/%s/file' % image_id)
headers = self._headers()
response = requests.put(path, headers=headers, data='ZZZZZ')
self.assertEqual(200, response.status_code)
# Uploading duplicate data should be rejected with a 409
path = self._url('/v2/images/%s/file' % image_id)
headers = self._headers()
response = requests.put(path, headers=headers, data='XXX')
self.assertEqual(409, response.status_code)
# Data should not have been overwritten
path = self._url('/v2/images/%s/file' % image_id)
headers = self._headers()
response = requests.get(path, headers=headers)
self.assertEqual(200, response.status_code)
self.assertEqual(response.text, 'ZZZZZ')
self.stop_servers()

View File

@ -52,7 +52,7 @@ class FakeDB(object):
def __init__(self):
self.images = {
UUID1: self._image_format(UUID1, location='1'),
UUID1: self._image_format(UUID1, location=UUID1),
UUID2: self._image_format(UUID2),
}
self.members = {
@ -180,8 +180,7 @@ class FakeDB(object):
class FakeStoreAPI(object):
def __init__(self):
self.data = {
'1': ('XXX', 3),
'2': ('FFFFF', 5),
UUID1: ('XXX', 3),
}
def create_stores(self, conf):
@ -199,7 +198,8 @@ class FakeStoreAPI(object):
return self.get_from_backend(location)[1]
def add_to_backend(self, scheme, image_id, data, size):
location = utils.generate_uuid()
self.data[location] = (data, size)
if image_id in self.data:
raise exception.Duplicate()
self.data[image_id] = (data, size)
checksum = 'Z'
return (location, size, checksum)
return (image_id, size, checksum)

View File

@ -63,6 +63,11 @@ class TestImagesController(unittest.TestCase):
self.assertRaises(webob.exc.HTTPNotFound, self.controller.upload,
request, utils.generate_uuid(), 'YYYY')
def test_upload_data_exists(self):
request = test_utils.FakeRequest()
self.assertRaises(webob.exc.HTTPConflict, self.controller.upload,
request, test_utils.UUID1, 'YYYY')
class TestImageDataDeserializer(unittest.TestCase):
def setUp(self):

View File

@ -79,7 +79,7 @@ class TestImagesController(unittest.TestCase):
expected = {
'name': 'image-2',
'owner': test_utils.TENANT1,
'location': '1',
'location': test_utils.UUID1,
'status': 'queued',
}
self.assertEqual(expected, output)