# This patch is taken from community. Fix is present in version 2015.2.2
# This fix could be found in following URL
# https://review.openstack.org/gitweb?p=openstack/glance.git;a=commit;h=f1260cc771ee068651aa62b972bef49d9af81eb0
--- glance-2013.2.3.orginal/glance/api/authorization.py 2015-02-20 03:57:20.678874000 -0600
+++ glance-2013.2.3//glance/api/authorization.py 2015-02-20 04:07:24.881647830 -0600
@@ -119,10 +119,10 @@
raise exception.Forbidden(message
% self.image.image_id)
- def save(self, image_member):
+ def save(self, image_member, from_state=None):
if (self.context.is_admin or
self.context.owner == image_member.member_id):
- updated_member = self.member_repo.save(image_member)
+ updated_member = self.member_repo.save(image_member, from_state=from_state)
return proxy_member(self.context, updated_member)
else:
message = _("You cannot update image member %s")
--- glance-2013.2.3.orginal/glance/api/policy.py 2015-02-20 03:57:20.670610060 -0600
+++ glance-2013.2.3//glance/api/policy.py 2015-02-20 04:33:34.232748980 -0600
@@ -174,9 +174,9 @@
self.policy.enforce(self.context, 'get_images', {})
return super(ImageRepoProxy, self).list(*args, **kwargs)
- def save(self, image):
+ def save(self, image, from_state=None):
self.policy.enforce(self.context, 'modify_image', {})
- return super(ImageRepoProxy, self).save(image)
+ return super(ImageRepoProxy, self).save(image, from_state=from_state)
def add(self, image):
self.policy.enforce(self.context, 'add_image', {})
@@ -271,9 +271,9 @@
self.policy.enforce(self.context, 'get_member', {})
return self.member_repo.get(member_id)
- def save(self, member):
+ def save(self, member, from_state=None):
self.policy.enforce(self.context, 'modify_member', {})
- return self.member_repo.save(member)
+ return self.member_repo.save(member, from_state=from_state)
def list(self, *args, **kwargs):
self.policy.enforce(self.context, 'get_members', {})
--- glance-2013.2.3.old/glance/api/v1/upload_utils.py 2014-04-03 11:43:55.000000000 -0700
+++ glance-2013.2.3/glance/api/v1/upload_utils.py 2015-03-08 23:28:12.600039932 -0700
@@ -139,13 +139,24 @@
update_data = {'checksum': checksum,
'size': size}
try:
- image_meta = registry.update_image_metadata(req.context,
- image_id,
- update_data)
-
- except exception.NotFound as e:
- msg = _("Image %s could not be found after upload. The image may "
- "have been deleted during the upload.") % image_id
+ try:
+ state = 'saving'
+ image_meta = registry.update_image_metadata(req.context,
+ image_id,
+ update_data,
+ from_state=state)
+ image = registry.get_image_metadata(req.context, image_id)
+ if image['status'] == 'deleted':
+ raise exception.NotFound()
+ except exception.Duplicate:
+ image = registry.get_image_metadata(req.context, image_id)
+ if image['status'] == 'deleted':
+ raise exception.NotFound()
+ else:
+ raise
+ except exception.NotFound:
+ msg = _("Image %s could not be found after upload. The image may"
+ " have been deleted during the upload.") % image_id
LOG.info(msg)
# NOTE(jculp): we need to clean up the datastore if an image
--- glance-2013.2.3.orginal/glance/api/v2/image_data.py 2015-02-20 03:57:20.678035080 -0600
+++ glance-2013.2.3//glance/api/v2/image_data.py 2015-02-20 05:49:21.505608540 -0600
@@ -24,6 +24,7 @@
import glance.domain
import glance.gateway
import glance.notifier
+from glance.openstack.common import excutils
import glance.openstack.common.log as logging
import glance.store
@@ -53,11 +54,12 @@
try:
image_repo.save(image)
image.set_data(data, size)
- image_repo.save(image)
- except exception.NotFound as e:
- msg = (_("Image %s could not be found after upload."
- "The image may have been deleted during the upload: %s")
- % (image_id, e))
+ image_repo.save(image, from_state='saving')
+ except (exception.NotFound, exception.Conflict):
+ msg = (_("Image %s could not be found after upload. "
+ "The image may have been deleted during the "
+ "upload, cleaning up the chunks uploaded.") %
+ image_id)
LOG.warn(msg)
raise webob.exc.HTTPGone(explanation=msg,
request=req,
@@ -111,6 +113,10 @@
raise webob.exc.HTTPServiceUnavailable(explanation=msg,
request=req)
+ except webob.exc.HTTPGone as e:
+ with excutils.save_and_reraise_exception():
+ LOG.error(_("Failed to upload image data due to HTTP error"))
+
except webob.exc.HTTPError as e:
LOG.error(_("Failed to upload image data due to HTTP error"))
raise
diff --git glance-2013.2.3/glance/db/__init__.py glance-2013.2.3/glance/db/__init__.py
index a59447d..379cf6f 100644 (file)
--- glance-2013.2.3/glance/db/__init__.py
+++ glance-2013.2.3/glance/db/__init__.py
@@ -162,7 +162,7 @@ class ImageRepo(object):
image.created_at = new_values['created_at']
image.updated_at = new_values['updated_at']
- def save(self, image):
+ def save(self, image, from_state=None):
image_values = self._format_image_to_db(image)
if image_values['size'] > CONF.image_size_cap:
raise exception.ImageSizeLimitExceeded
@@ -170,7 +170,8 @@ class ImageRepo(object):
new_values = self.db_api.image_update(self.context,
image.image_id,
image_values,
- purge_props=True)
+ purge_props=True,
+ from_state=from_state)
except (exception.NotFound, exception.Forbidden):
msg = _("No image found with ID %s") % image.image_id
raise exception.NotFound(msg)
@@ -263,7 +264,7 @@ class ImageMemberRepo(object):
msg = _("The specified member %s could not be found")
raise exception.NotFound(msg % image_member.id)
- def save(self, image_member):
+ def save(self, image_member, from_state=None):
image_member_values = self._format_image_member_to_db(image_member)
try:
new_values = self.db_api.image_member_update(self.context,
diff --git glance-2013.2.3/glance/domain/proxy.py glance-2013.2.3/glance/domain/proxy.py
index 89f138c..b27b448 100644 (file)
--- glance-2013.2.3/glance/domain/proxy.py
+++ glance-2013.2.3/glance/domain/proxy.py
@@ -94,9 +94,9 @@ class Repo(object):
result = self.base.add(base_item)
return self.helper.proxy(result)
- def save(self, item):
+ def save(self, item, from_state=None):
base_item = self.helper.unproxy(item)
- result = self.base.save(base_item)
+ result = self.base.save(base_item, from_state=from_state)
return self.helper.proxy(result)
def remove(self, item):
diff --git glance-2013.2.3/glance/store/__init__.py glance-2013.2.3/glance/store/__init__.py
index 273b7c7..ae3b4c8 100644 (file)
--- glance-2013.2.3/glance/store/__init__.py
+++ glance-2013.2.3/glance/store/__init__.py
@@ -446,7 +446,7 @@ class ImageRepoProxy(glance.domain.proxy.Repo):
self._set_acls(image)
return result
- def save(self, image):
+ def save(self, image, from_state=None):
result = super(ImageRepoProxy, self).save(image)
self._set_acls(image)
return result
--- glance-2013.2.3.orginal/glance/quota/__init__.py 2015-02-20 03:57:20.466150810 -0600
+++ glance-2013.2.3/glance/quota/__init__.py 2015-02-25 04:44:45.714636070 -0600
@@ -36,6 +36,28 @@
item_proxy_class=ImageProxy,
item_proxy_kwargs=proxy_kwargs)
+ def _enforce_image_property_quota(self, attempted):
+ if CONF.image_property_quota < 0:
+ # If value is negative, allow unlimited number of properties
+ return
+
+ maximum = CONF.image_property_quota
+ if attempted > maximum:
+ kwargs = {'attempted': attempted, 'maximum': maximum}
+ exc = exception.ImagePropertyLimitExceeded(**kwargs)
+ LOG.debug(six.text_type(exc))
+ raise exc
+
+ def save(self, image, from_state=None):
+ if image.added_new_properties():
+ self._enforce_image_property_quota(len(image.extra_properties))
+ return super(ImageRepoProxy, self).save(image, from_state=from_state)
+
+ def add(self, image):
+ self._enforce_image_property_quota(len(image.extra_properties))
+ return super(ImageRepoProxy, self).add(image)
+
+
class ImageFactoryProxy(glance.domain.proxy.ImageFactory):
def __init__(self, factory, context, db_api):
--- glance-2013.2.3.orginal/glance/registry/client/v1/api.py 2015-02-20 03:57:20.477473040 -0600
+++ glance-2013.2.3/glance/registry/client/v1/api.py 2015-02-26 02:15:02.437773030 -0600
@@ -164,11 +164,11 @@
def update_image_metadata(context, image_id, image_meta,
- purge_props=False):
+ purge_props=False, from_state=None):
LOG.debug(_("Updating image metadata for image %s..."), image_id)
c = get_registry_client(context)
- return c.update_image(image_id, image_meta, purge_props)
-
+ return c.update_image(image_id, image_meta, purge_props,
+ from_state=from_state)
def delete_image_metadata(context, image_id):
LOG.debug(_("Deleting image metadata for image %s..."), image_id)
--- glance-2013.2.3.orginal/glance/registry/client/v1/client.py 2015-02-20 03:57:20.477107680 -0600
+++ glance-2013.2.3/glance/registry/client/v1/client.py 2015-02-26 02:25:21.498753360 -0600
@@ -165,7 +165,8 @@
image = data['image']
return self.decrypt_metadata(image)
- def update_image(self, image_id, image_metadata, purge_props=False):
+ def update_image(self, image_id, image_metadata, purge_props=False,
+ from_state=None):
"""
Updates Registry's information about an image
"""
@@ -174,6 +175,7 @@
encrypted_metadata = self.encrypt_metadata(image_metadata['image'])
image_metadata['image'] = encrypted_metadata
+ image_metadata['from_state'] = from_state
body = json.dumps(image_metadata)
headers = {