Merge "Lazy update stores information"

This commit is contained in:
Zuul 2019-08-20 17:05:28 +00:00 committed by Gerrit Code Review
commit cee9526c98
3 changed files with 84 additions and 3 deletions

View File

@ -15,11 +15,34 @@
# under the License.
import copy
import functools
from oslo_config import cfg
from oslo_log import log as logging
from glance.common import exception
from glance.common import store_utils
import glance.domain.proxy
from glance.i18n import _
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
def lazy_update_store_info(func):
"""Update store information in location metadata"""
@functools.wraps(func)
def wrapped(context, image, **kwargs):
image_repo = kwargs.get('image_repo')
if CONF.enabled_backends:
store_utils.update_store_in_locations(
image.locations, image.image_id)
image_repo.save(image)
return func(context, image, **kwargs)
return wrapped
def is_image_mutable(context, image):
"""Return True if the image is mutable in this context."""
@ -32,7 +55,8 @@ def is_image_mutable(context, image):
return image.owner == context.owner
def proxy_image(context, image):
@lazy_update_store_info
def proxy_image(context, image, image_repo=None):
if is_image_mutable(context, image):
return ImageProxy(image, context)
else:
@ -105,11 +129,12 @@ class ImageRepoProxy(glance.domain.proxy.Repo):
def get(self, image_id):
image = self.image_repo.get(image_id)
return proxy_image(self.context, image)
return proxy_image(self.context, image, image_repo=self.image_repo)
def list(self, *args, **kwargs):
images = self.image_repo.list(*args, **kwargs)
return [proxy_image(self.context, i) for i in images]
return [proxy_image(self.context, i,
image_repo=self.image_repo) for i in images]
def _validate_image_accepts_members(visibility):

View File

@ -147,3 +147,41 @@ def validate_external_location(uri):
return (scheme in known_schemes and
scheme not in RESTRICTED_URI_SCHEMAS)
def _get_store_id_from_uri(uri):
scheme = urlparse.urlparse(uri).scheme
location_map = store_api.location.SCHEME_TO_CLS_BACKEND_MAP
url_matched = False
if scheme not in location_map:
LOG.warning("Unknown scheme '%(scheme)s' found in uri '%(uri)s'", {
'scheme': scheme, 'uri': uri})
return
for store in location_map[scheme]:
store_instance = location_map[scheme][store]['store']
if uri.startswith(store_instance.url_prefix):
url_matched = True
break
if url_matched:
return store
else:
LOG.warning("Invalid location uri %s", uri)
return
def update_store_in_locations(locations, image_id):
for loc in locations:
store_id = _get_store_id_from_uri(loc['url'])
if store_id:
if 'store' in loc['metadata']:
old_store = loc['metadata']['store']
if old_store != store_id:
LOG.debug("Store '%(old)s' has changed to "
"'%(new)s' by operator, updating "
"the same in the location of image "
"'%(id)s'", {'old': old_store,
'new': store_id,
'id': image_id})
loc['metadata']['store'] = store_id

View File

@ -32,6 +32,7 @@ import webob
import glance.api.v2.image_actions
import glance.api.v2.images
from glance.common import exception
from glance.common import store_utils
from glance import domain
import glance.schema
from glance.tests.unit import base
@ -4704,6 +4705,9 @@ class TestMultiImagesController(base.MultiIsolatedUnitTest):
tags=['redhat', '64bit', 'power'],
properties={'hypervisor_type': 'kvm', 'foo': 'bar',
'bar': 'foo'},
locations=[{'url': 'file://%s/%s' % (self.test_dir,
UUID2),
'metadata': {}, 'status': 'active'}],
created_at=DATETIME + datetime.timedelta(seconds=1)),
_db_fixture(UUID3, owner=TENANT3, checksum=CHKSUM1,
name='3', size=512, virtual_size=2048,
@ -4740,6 +4744,20 @@ class TestMultiImagesController(base.MultiIsolatedUnitTest):
request, UUID1,
{'method': {'name': 'glance-direct'}})
def test_image_lazy_loading_store(self):
# assert existing image does not have store in metadata
existing_image = self.images[1]
self.assertNotIn('store', existing_image['locations'][0]['metadata'])
# assert: store information will be added by lazy loading
request = unit_test_utils.get_fake_request()
with mock.patch.object(store_utils,
"_get_store_id_from_uri") as mock_uri:
mock_uri.return_value = "fast"
image = self.controller.show(request, UUID2)
for loc in image.locations:
self.assertIn('store', loc['metadata'])
def test_image_import_invalid_backend_in_request_header(self):
request = unit_test_utils.get_fake_request()
request.headers['x-image-meta-store'] = 'dummy'