Added fix for Bug #813291: POST to /images setting x-image-meta-id to an already existing image id causes a 500 error.

I came up with about 3 or 4 different ways of resolving this bug, and all tests pass. Let me know if you think this should be resolved in a different way.

This branch also includes a test in tests/functional/test_httplib2_api.py that shows the 500 error.
This commit is contained in:
Justin Shepherd 2011-07-21 12:42:38 +00:00 committed by Tarmac
commit bd96e2043c
2 changed files with 53 additions and 1 deletions

View File

@ -24,6 +24,7 @@ Defines interface for DB access
import logging
from sqlalchemy import asc, create_engine, desc
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import exc
from sqlalchemy.orm import joinedload
@ -273,7 +274,11 @@ def _image_update(context, values, image_id, purge_props=False):
# idiotic.
validate_image(image_ref.to_dict())
image_ref.save(session=session)
try:
image_ref.save(session=session)
except IntegrityError, e:
raise exception.Duplicate("Image ID %s already exists!"
% values['id'])
_set_properties_for_image(context, image_ref, properties, purge_props,
session)

View File

@ -1029,3 +1029,50 @@ class TestApiHttplib2(functional.FunctionalTest):
self.assertEqual(data['images'][2]['id'], 2)
self.stop_servers()
def test_duplicate_image_upload(self):
"""
Upload initial image, then attempt to upload duplicate image
"""
self.cleanup()
self.start_servers()
# 0. GET /images
# Verify no public images
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
http = httplib2.Http()
response, content = http.request(path, 'GET')
self.assertEqual(response.status, 200)
self.assertEqual(content, '{"images": []}')
# 1. POST /images with public image named Image1
headers = {'Content-Type': 'application/octet-stream',
'X-Image-Meta-Name': 'Image1',
'X-Image-Meta-Status': 'active',
'X-Image-Meta-Container-Format': 'ovf',
'X-Image-Meta-Disk-Format': 'vdi',
'X-Image-Meta-Size': '19',
'X-Image-Meta-Is-Public': 'True'}
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
http = httplib2.Http()
response, content = http.request(path, 'POST', headers=headers)
self.assertEqual(response.status, 201)
# 2. POST /images with public image named Image1, and ID: 1
headers = {'Content-Type': 'application/octet-stream',
'X-Image-Meta-Name': 'Image1 Update',
'X-Image-Meta-Status': 'active',
'X-Image-Meta-Container-Format': 'ovf',
'X-Image-Meta-Disk-Format': 'vdi',
'X-Image-Meta-Size': '19',
'X-Image-Meta-Id': '1',
'X-Image-Meta-Is-Public': 'True'}
path = "http://%s:%d/v1/images" % ("0.0.0.0", self.api_port)
http = httplib2.Http()
response, content = http.request(path, 'POST', headers=headers)
self.assertEqual(response.status, 409)
expected = "An image with identifier 1 already exists"
self.assertTrue(expected in content,
"Could not find '%s' in '%s'" % (expected, content))
self.stop_servers()