summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/exception.py4
-rw-r--r--nova/virt/xenapi/imageupload/glance.py57
-rwxr-xr-xplugins/xenserver/xenapi/etc/xapi.d/plugins/glance32
3 files changed, 69 insertions, 24 deletions
diff --git a/nova/exception.py b/nova/exception.py
index cad1c5c02..d1037aabc 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -1080,6 +1080,10 @@ class CouldNotFetchImage(NovaException):
message = _("Could not fetch image %(image_id)s")
+class CouldNotUploadImage(NovaException):
+ message = _("Could not upload image %(image_id)s")
+
+
class TaskAlreadyRunning(NovaException):
message = _("Task %(task_name)s is already running on host %(host)s")
diff --git a/nova/virt/xenapi/imageupload/glance.py b/nova/virt/xenapi/imageupload/glance.py
index 5ea75db16..1a4f7da59 100644
--- a/nova/virt/xenapi/imageupload/glance.py
+++ b/nova/virt/xenapi/imageupload/glance.py
@@ -13,8 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+import time
+
from oslo.config import cfg
+from nova import exception
from nova.image import glance
import nova.openstack.common.log as logging
from nova.virt.xenapi import vm_utils
@@ -22,6 +25,7 @@ from nova.virt.xenapi import vm_utils
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
+CONF.import_opt('glance_num_retries', 'nova.image.glance')
class GlanceStore(object):
@@ -32,24 +36,49 @@ class GlanceStore(object):
"""
# NOTE(sirp): Currently we only support uploading images as VHD, there
# is no RAW equivalent (yet)
- LOG.debug(_("Asking xapi to upload to glance %(vdi_uuids)s as"
- " ID %(image_id)s"), locals(), instance=instance)
-
+ max_attempts = CONF.glance_num_retries + 1
+ sleep_time = 0.5
glance_api_servers = glance.get_api_servers()
- glance_host, glance_port, glance_use_ssl = glance_api_servers.next()
-
properties = {
'auto_disk_config': instance['auto_disk_config'],
'os_type': instance['os_type'] or CONF.default_os_type,
}
- params = {'vdi_uuids': vdi_uuids,
- 'image_id': image_id,
- 'glance_host': glance_host,
- 'glance_port': glance_port,
- 'glance_use_ssl': glance_use_ssl,
- 'sr_path': vm_utils.get_sr_path(session),
- 'auth_token': getattr(context, 'auth_token', None),
- 'properties': properties}
+ for attempt_num in xrange(1, max_attempts + 1):
+
+ (glance_host,
+ glance_port,
+ glance_use_ssl) = glance_api_servers.next()
+
+ try:
+
+ params = {'vdi_uuids': vdi_uuids,
+ 'image_id': image_id,
+ 'glance_host': glance_host,
+ 'glance_port': glance_port,
+ 'glance_use_ssl': glance_use_ssl,
+ 'sr_path': vm_utils.get_sr_path(session),
+ 'auth_token': getattr(context, 'auth_token', None),
+ 'properties': properties}
+
+ LOG.debug(_("Asking xapi to upload to glance %(vdi_uuids)s as"
+ " ID %(image_id)s"
+ " glance server: %(glance_host)s:%(glance_port)d"
+ " attempt %(attempt_num)d/%(max_attempts)d"),
+ locals(), instance=instance)
+
+ return session.call_plugin_serialized('glance',
+ 'upload_vhd',
+ **params)
+
+ except session.XenAPI.Failure as exc:
+ _type, _method, error = exc.details[:3]
+ if error == 'RetryableError':
+ LOG.error(_('upload_vhd failed: %r') %
+ (exc.details[3:],))
+ else:
+ raise
+ time.sleep(sleep_time)
+ sleep_time = min(2 * sleep_time, 15)
- session.call_plugin_serialized('glance', 'upload_vhd', **params)
+ raise exception.CouldNotUploadImage(image_id=image_id)
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance
index 924bf10d7..47b12bd60 100755
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance
@@ -126,14 +126,18 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port,
url = '%s://%s:%s/v1/images/%s' % (scheme, glance_host, glance_port,
image_id)
logging.info("Writing image data to %s" % url)
- if glance_use_ssl:
- conn = httplib.HTTPSConnection(glance_host, glance_port)
- else:
- conn = httplib.HTTPConnection(glance_host, glance_port)
- # NOTE(sirp): httplib under python2.4 won't accept a file-like object
- # to request
- conn.putrequest('PUT', '/v1/images/%s' % image_id)
+ try:
+ if glance_use_ssl:
+ conn = httplib.HTTPSConnection(glance_host, glance_port)
+ else:
+ conn = httplib.HTTPConnection(glance_host, glance_port)
+
+ # NOTE(sirp): httplib under python2.4 won't accept a file-like object
+ # to request
+ conn.putrequest('PUT', '/v1/images/%s' % image_id)
+ except Exception, error:
+ raise RetryableError(error)
# NOTE(sirp): There is some confusion around OVF. Here's a summary of
# where we currently stand:
@@ -172,12 +176,18 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port,
def send_chunked_transfer_encoded(chunk):
chunk_len = len(chunk)
callback_data['bytes_written'] += chunk_len
- conn.send("%x\r\n%s\r\n" % (chunk_len, chunk))
+ try:
+ conn.send("%x\r\n%s\r\n" % (chunk_len, chunk))
+ except Exception, error:
+ raise RetryableError(error)
utils.create_tarball(
None, staging_path, callback=send_chunked_transfer_encoded)
- conn.send("0\r\n\r\n") # Chunked-Transfer terminator
+ try:
+ conn.send("0\r\n\r\n") # Chunked-Transfer terminator
+ except Exception, error:
+ raise RetryableError(error)
bytes_written = callback_data['bytes_written']
logging.info("Wrote %d bytes to %s" % (bytes_written, url))
@@ -187,9 +197,11 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port,
logging.error("Unexpected response while writing image data to %s: "
"Response Status: %i, Response body: %s"
% (url, resp.status, resp.read()))
- raise Exception("Unexpected response [%i] while uploading image [%s] "
+ raise RetryableError("Unexpected response [%i] while uploading "
+ "image [%s] "
"to glance host [%s:%s]"
% (resp.status, image_id, glance_host, glance_port))
+
conn.close()