Handle images which exist but can't be seen.

If the master and the slave glance have different permissions, you
can end up with a 409 exception at upload. For example:

 - the image is visible to the replication user on the master
 - the image is present on the slave, but not visible to the
   replication user

The replicator checks for the existance of the image by doing a HEAD
on http://server:port/v1/images/uuid and gets a 404 back. It therefore
decides the image doesn't exist and that it should be replicated. It
does a POST for that URL, and gets a 409 back saying that UUID is
already in use.

Resolves bug 1030396.

Change-Id: Id5fdb7977692593fd6c2e203f0440d4aa5339d92
This commit is contained in:
Michael Still 2012-07-29 10:05:45 +10:00
parent 4ac0f4f0a4
commit 7335088d89

View File

@ -52,18 +52,28 @@ COMMANDS = """Commands:
""" """
class UploadException(Exception): IMAGE_ALREADY_PRESENT_MESSAGE = _('The image %s is already present on '
pass 'the slave, but our check for it did '
'not find it. This indicates that we '
'do not have permissions to see all '
'the images on the slave server.')
class AuthenticationException(Exception): class AuthenticationException(Exception):
pass pass
class ImageAlreadyPresentException(Exception):
pass
class ServerErrorException(Exception): class ServerErrorException(Exception):
pass pass
class UploadException(Exception):
pass
class ImageService(object): class ImageService(object):
def __init__(self, conn, auth_token): def __init__(self, conn, auth_token):
""" Initialize the ImageService. """ Initialize the ImageService.
@ -111,7 +121,10 @@ class ImageService(object):
raise ServerErrorException(response.read()) raise ServerErrorException(response.read())
if code in [401, 403]: if code in [401, 403]:
raise AuthenticationException() raise AuthenticationException(response.read())
if code == 409:
raise ImageAlreadyPresentException(response.read())
if ignore_result_body: if ignore_result_body:
# NOTE: because we are pipelining requests through a single HTTP # NOTE: because we are pipelining requests through a single HTTP
@ -364,7 +377,7 @@ def replication_load(options, args):
image_uuid = ent image_uuid = ent
logging.info(_('Considering: %s') % image_uuid) logging.info(_('Considering: %s') % image_uuid)
meta_file_name = os.path.join(path, uuid) meta_file_name = os.path.join(path, image_uuid)
with open(meta_file_name) as meta_file: with open(meta_file_name) as meta_file:
meta = json.loads(meta_file.read()) meta = json.loads(meta_file.read())
@ -397,10 +410,13 @@ def replication_load(options, args):
continue continue
# Upload the image itself # Upload the image itself
with open(os.path.join(path, uuid + '.img')) as img_file: with open(os.path.join(path, image_uuid + '.img')) as img_file:
try:
headers, body = client.add_image(meta, img_file) headers, body = client.add_image(meta, img_file)
_check_upload_response_headers(headers, body) _check_upload_response_headers(headers, body)
except ImageAlreadyPresentException:
logging.error(IMAGE_ALREADY_PRESENT_MESSAGE
% image_uuid)
def replication_livecopy(options, args): def replication_livecopy(options, args):
@ -455,8 +471,12 @@ def replication_livecopy(options, args):
logging.info(_('%s is being synced') % image['id']) logging.info(_('%s is being synced') % image['id'])
if not options.metaonly: if not options.metaonly:
image_response = master_client.get_image(image['id']) image_response = master_client.get_image(image['id'])
headers, body = slave_client.add_image(image, image_response) try:
headers, body = slave_client.add_image(image,
image_response)
_check_upload_response_headers(headers, body) _check_upload_response_headers(headers, body)
except ImageAlreadyPresentException:
logging.error(IMAGE_ALREADY_PRESENT_MESSAGE % image['id'])
def replication_compare(options, args): def replication_compare(options, args):