summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
authorJohannes Erdfelt <johannes.erdfelt@rackspace.com>2012-03-01 18:49:44 +0000
committerJohannes Erdfelt <johannes.erdfelt@rackspace.com>2012-03-02 19:14:13 +0000
commitc4a2e17dcfbd7b6434a7dfae3c7a3e5f30a3fc87 (patch)
tree02618692c7d92734f14776f626a5f941c4316c94 /nova
parent8a530832c599f8866e98947976d74a5332d877af (diff)
downloadnova-c4a2e17dcfbd7b6434a7dfae3c7a3e5f30a3fc87.tar.gz
nova-c4a2e17dcfbd7b6434a7dfae3c7a3e5f30a3fc87.tar.xz
nova-c4a2e17dcfbd7b6434a7dfae3c7a3e5f30a3fc87.zip
Retry download_vhd with different glance host each time
Fixes bug 944096 Change-Id: I33aa3774ba7f266e85f09c6c569fdd0f895478b4
Diffstat (limited to 'nova')
-rw-r--r--nova/exception.py4
-rw-r--r--nova/virt/xenapi/vm_utils.py69
2 files changed, 51 insertions, 22 deletions
diff --git a/nova/exception.py b/nova/exception.py
index 43d16642f..c781170b7 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -1015,3 +1015,7 @@ class InstanceNotFound(NotFound):
class InvalidInstanceIDMalformed(Invalid):
message = _("Invalid id: %(val)s (expecting \"i-...\").")
+
+
+class CouldNotFetchImage(NovaException):
+ message = _("Could not fetch image %(image)s")
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index 83103d6f2..0321d0d59 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -692,6 +692,48 @@ class VMHelper(HelperBase):
session, instance, image, image_type)
@classmethod
+ def _retry_glance_download_vhd(cls, context, session, instance, image):
+ # NOTE(sirp): The Glance plugin runs under Python 2.4
+ # which does not have the `uuid` module. To work around this,
+ # we generate the uuids here (under Python 2.6+) and
+ # pass them as arguments
+ uuid_stack = [str(uuid.uuid4()) for i in xrange(3)]
+
+ max_attempts = FLAGS.glance_num_retries + 1
+ sleep_time = 0.5
+ for attempt_num in xrange(1, max_attempts + 1):
+ glance_host, glance_port = glance.pick_glance_api_server()
+ params = {'image_id': image,
+ 'glance_host': glance_host,
+ 'glance_port': glance_port,
+ 'uuid_stack': uuid_stack,
+ 'sr_path': cls.get_sr_path(session),
+ 'num_retries': 0,
+ 'auth_token': getattr(context, 'auth_token', None)}
+ kwargs = {'params': pickle.dumps(params)}
+
+ LOG.info(_('download_vhd %(image)s '
+ 'attempt %(attempt_num)d/%(max_attempts)d '
+ 'from %(glance_host)s:%(glance_port)s') % locals())
+
+ task = session.async_call_plugin('glance', 'download_vhd', kwargs)
+ try:
+ result = session.wait_for_task(task, instance['uuid'])
+ return json.loads(result)
+ except cls.XenAPI.Failure as exc:
+ _type, method, error = exc.details[:3]
+ if error == 'RetryableError':
+ LOG.error(_('download_vhd failed: %r') %
+ (exc.details[3:],))
+ else:
+ raise
+
+ time.sleep(sleep_time)
+ sleep_time = min(2 * sleep_time, 15)
+
+ raise exception.CouldNotFetchImage(image=image)
+
+ @classmethod
def _fetch_image_glance_vhd(cls, context, session, instance, image,
image_type):
"""Tell glance to download an image and put the VHDs into the SR
@@ -703,29 +745,12 @@ class VMHelper(HelperBase):
% locals())
sr_ref = cls.safe_find_sr(session)
- # NOTE(sirp): The Glance plugin runs under Python 2.4
- # which does not have the `uuid` module. To work around this,
- # we generate the uuids here (under Python 2.6+) and
- # pass them as arguments
- uuid_stack = [str(uuid.uuid4()) for i in xrange(3)]
+ vdis = cls._retry_glance_download_vhd(context, session, instance,
+ image)
- glance_host, glance_port = glance.pick_glance_api_server()
- params = {'image_id': image,
- 'glance_host': glance_host,
- 'glance_port': glance_port,
- 'uuid_stack': uuid_stack,
- 'sr_path': cls.get_sr_path(session),
- 'num_retries': FLAGS.glance_num_retries,
- 'auth_token': getattr(context, 'auth_token', None)}
-
- kwargs = {'params': pickle.dumps(params)}
- task = session.async_call_plugin('glance', 'download_vhd', kwargs)
- result = session.wait_for_task(task, instance['uuid'])
- # 'download_vhd' will return a json encoded string containing
- # a list of dictionaries describing VDIs. The dictionary will
- # contain 'vdi_type' and 'vdi_uuid' keys. 'vdi_type' can be
- # 'os' or 'swap' right now.
- vdis = json.loads(result)
+ # 'download_vhd' will return a list of dictionaries describing VDIs.
+ # The dictionary will contain 'vdi_type' and 'vdi_uuid' keys.
+ # 'vdi_type' can be 'os' or 'swap' right now.
for vdi in vdis:
LOG.debug(_("xapi 'download_vhd' returned VDI of "
"type '%(vdi_type)s' with UUID '%(vdi_uuid)s'" % vdi))