Merge "GlanceImageService static methods to module scope"
This commit is contained in:
@@ -251,7 +251,7 @@ class GlanceImageService(object):
|
|||||||
|
|
||||||
def detail(self, context, **kwargs):
|
def detail(self, context, **kwargs):
|
||||||
"""Calls out to Glance for a list of detailed image information."""
|
"""Calls out to Glance for a list of detailed image information."""
|
||||||
params = self._extract_query_params(kwargs)
|
params = _extract_query_params(kwargs)
|
||||||
try:
|
try:
|
||||||
images = self._client.call(context, 1, 'list', **params)
|
images = self._client.call(context, 1, 'list', **params)
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -259,26 +259,11 @@ class GlanceImageService(object):
|
|||||||
|
|
||||||
_images = []
|
_images = []
|
||||||
for image in images:
|
for image in images:
|
||||||
if self._is_image_available(context, image):
|
if _is_image_available(context, image):
|
||||||
_images.append(self._translate_from_glance(image))
|
_images.append(_translate_from_glance(image))
|
||||||
|
|
||||||
return _images
|
return _images
|
||||||
|
|
||||||
def _extract_query_params(self, params):
|
|
||||||
_params = {}
|
|
||||||
accepted_params = ('filters', 'marker', 'limit',
|
|
||||||
'page_size', 'sort_key', 'sort_dir')
|
|
||||||
for param in accepted_params:
|
|
||||||
if params.get(param):
|
|
||||||
_params[param] = params.get(param)
|
|
||||||
|
|
||||||
# ensure filters is a dict
|
|
||||||
_params.setdefault('filters', {})
|
|
||||||
# NOTE(vish): don't filter out private images
|
|
||||||
_params['filters'].setdefault('is_public', 'none')
|
|
||||||
|
|
||||||
return _params
|
|
||||||
|
|
||||||
def show(self, context, image_id):
|
def show(self, context, image_id):
|
||||||
"""Returns a dict with image data for the given opaque image id."""
|
"""Returns a dict with image data for the given opaque image id."""
|
||||||
try:
|
try:
|
||||||
@@ -286,10 +271,10 @@ class GlanceImageService(object):
|
|||||||
except Exception:
|
except Exception:
|
||||||
_reraise_translated_image_exception(image_id)
|
_reraise_translated_image_exception(image_id)
|
||||||
|
|
||||||
if not self._is_image_available(context, image):
|
if not _is_image_available(context, image):
|
||||||
raise exception.ImageNotFound(image_id=image_id)
|
raise exception.ImageNotFound(image_id=image_id)
|
||||||
|
|
||||||
base_image_meta = self._translate_from_glance(image)
|
base_image_meta = _translate_from_glance(image)
|
||||||
return base_image_meta
|
return base_image_meta
|
||||||
|
|
||||||
def _get_locations(self, context, image_id):
|
def _get_locations(self, context, image_id):
|
||||||
@@ -302,7 +287,7 @@ class GlanceImageService(object):
|
|||||||
except Exception:
|
except Exception:
|
||||||
_reraise_translated_image_exception(image_id)
|
_reraise_translated_image_exception(image_id)
|
||||||
|
|
||||||
if not self._is_image_available(context, image_meta):
|
if not _is_image_available(context, image_meta):
|
||||||
raise exception.ImageNotFound(image_id=image_id)
|
raise exception.ImageNotFound(image_id=image_id)
|
||||||
|
|
||||||
locations = getattr(image_meta, 'locations', [])
|
locations = getattr(image_meta, 'locations', [])
|
||||||
@@ -362,7 +347,7 @@ class GlanceImageService(object):
|
|||||||
|
|
||||||
def create(self, context, image_meta, data=None):
|
def create(self, context, image_meta, data=None):
|
||||||
"""Store the image data and return the new image object."""
|
"""Store the image data and return the new image object."""
|
||||||
sent_service_image_meta = self._translate_to_glance(image_meta)
|
sent_service_image_meta = _translate_to_glance(image_meta)
|
||||||
|
|
||||||
if data:
|
if data:
|
||||||
sent_service_image_meta['data'] = data
|
sent_service_image_meta['data'] = data
|
||||||
@@ -373,12 +358,12 @@ class GlanceImageService(object):
|
|||||||
except glanceclient.exc.HTTPException:
|
except glanceclient.exc.HTTPException:
|
||||||
_reraise_translated_exception()
|
_reraise_translated_exception()
|
||||||
|
|
||||||
return self._translate_from_glance(recv_service_image_meta)
|
return _translate_from_glance(recv_service_image_meta)
|
||||||
|
|
||||||
def update(self, context, image_id, image_meta, data=None,
|
def update(self, context, image_id, image_meta, data=None,
|
||||||
purge_props=True):
|
purge_props=True):
|
||||||
"""Modify the given image with the new data."""
|
"""Modify the given image with the new data."""
|
||||||
image_meta = self._translate_to_glance(image_meta)
|
image_meta = _translate_to_glance(image_meta)
|
||||||
image_meta['purge_props'] = purge_props
|
image_meta['purge_props'] = purge_props
|
||||||
#NOTE(bcwaldon): id is not an editable field, but it is likely to be
|
#NOTE(bcwaldon): id is not an editable field, but it is likely to be
|
||||||
# passed in by calling code. Let's be nice and ignore it.
|
# passed in by calling code. Let's be nice and ignore it.
|
||||||
@@ -391,7 +376,7 @@ class GlanceImageService(object):
|
|||||||
except Exception:
|
except Exception:
|
||||||
_reraise_translated_image_exception(image_id)
|
_reraise_translated_image_exception(image_id)
|
||||||
else:
|
else:
|
||||||
return self._translate_from_glance(image_meta)
|
return _translate_from_glance(image_meta)
|
||||||
|
|
||||||
def delete(self, context, image_id):
|
def delete(self, context, image_id):
|
||||||
"""Delete the given image.
|
"""Delete the given image.
|
||||||
@@ -409,59 +394,75 @@ class GlanceImageService(object):
|
|||||||
raise exception.ImageNotAuthorized(image_id=image_id)
|
raise exception.ImageNotAuthorized(image_id=image_id)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _translate_to_glance(image_meta):
|
|
||||||
image_meta = _convert_to_string(image_meta)
|
|
||||||
image_meta = _remove_read_only(image_meta)
|
|
||||||
return image_meta
|
|
||||||
|
|
||||||
@staticmethod
|
def _extract_query_params(params):
|
||||||
def _translate_from_glance(image):
|
_params = {}
|
||||||
image_meta = _extract_attributes(image)
|
accepted_params = ('filters', 'marker', 'limit',
|
||||||
image_meta = _convert_timestamps_to_datetimes(image_meta)
|
'page_size', 'sort_key', 'sort_dir')
|
||||||
image_meta = _convert_from_string(image_meta)
|
for param in accepted_params:
|
||||||
return image_meta
|
if params.get(param):
|
||||||
|
_params[param] = params.get(param)
|
||||||
|
|
||||||
@staticmethod
|
# ensure filters is a dict
|
||||||
def _is_image_available(context, image):
|
_params.setdefault('filters', {})
|
||||||
"""Check image availability.
|
# NOTE(vish): don't filter out private images
|
||||||
|
_params['filters'].setdefault('is_public', 'none')
|
||||||
|
|
||||||
This check is needed in case Nova and Glance are deployed
|
return _params
|
||||||
without authentication turned on.
|
|
||||||
"""
|
|
||||||
# The presence of an auth token implies this is an authenticated
|
|
||||||
# request and we need not handle the noauth use-case.
|
|
||||||
if hasattr(context, 'auth_token') and context.auth_token:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _is_image_public(image):
|
|
||||||
# NOTE(jaypipes) V2 Glance API replaced the is_public attribute
|
|
||||||
# with a visibility attribute. We do this here to prevent the
|
|
||||||
# glanceclient for a V2 image model from throwing an
|
|
||||||
# exception from warlock when trying to access an is_public
|
|
||||||
# attribute.
|
|
||||||
if hasattr(image, 'visibility'):
|
|
||||||
return str(image.visibility).lower() == 'public'
|
|
||||||
else:
|
|
||||||
return image.is_public
|
|
||||||
|
|
||||||
if context.is_admin or _is_image_public(image):
|
def _is_image_available(context, image):
|
||||||
return True
|
"""Check image availability.
|
||||||
|
|
||||||
properties = image.properties
|
This check is needed in case Nova and Glance are deployed
|
||||||
|
without authentication turned on.
|
||||||
|
"""
|
||||||
|
# The presence of an auth token implies this is an authenticated
|
||||||
|
# request and we need not handle the noauth use-case.
|
||||||
|
if hasattr(context, 'auth_token') and context.auth_token:
|
||||||
|
return True
|
||||||
|
|
||||||
if context.project_id and ('owner_id' in properties):
|
def _is_image_public(image):
|
||||||
return str(properties['owner_id']) == str(context.project_id)
|
# NOTE(jaypipes) V2 Glance API replaced the is_public attribute
|
||||||
|
# with a visibility attribute. We do this here to prevent the
|
||||||
|
# glanceclient for a V2 image model from throwing an
|
||||||
|
# exception from warlock when trying to access an is_public
|
||||||
|
# attribute.
|
||||||
|
if hasattr(image, 'visibility'):
|
||||||
|
return str(image.visibility).lower() == 'public'
|
||||||
|
else:
|
||||||
|
return image.is_public
|
||||||
|
|
||||||
if context.project_id and ('project_id' in properties):
|
if context.is_admin or _is_image_public(image):
|
||||||
return str(properties['project_id']) == str(context.project_id)
|
return True
|
||||||
|
|
||||||
try:
|
properties = image.properties
|
||||||
user_id = properties['user_id']
|
|
||||||
except KeyError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return str(user_id) == str(context.user_id)
|
if context.project_id and ('owner_id' in properties):
|
||||||
|
return str(properties['owner_id']) == str(context.project_id)
|
||||||
|
|
||||||
|
if context.project_id and ('project_id' in properties):
|
||||||
|
return str(properties['project_id']) == str(context.project_id)
|
||||||
|
|
||||||
|
try:
|
||||||
|
user_id = properties['user_id']
|
||||||
|
except KeyError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return str(user_id) == str(context.user_id)
|
||||||
|
|
||||||
|
|
||||||
|
def _translate_to_glance(image_meta):
|
||||||
|
image_meta = _convert_to_string(image_meta)
|
||||||
|
image_meta = _remove_read_only(image_meta)
|
||||||
|
return image_meta
|
||||||
|
|
||||||
|
|
||||||
|
def _translate_from_glance(image):
|
||||||
|
image_meta = _extract_attributes(image)
|
||||||
|
image_meta = _convert_timestamps_to_datetimes(image_meta)
|
||||||
|
image_meta = _convert_from_string(image_meta)
|
||||||
|
return image_meta
|
||||||
|
|
||||||
|
|
||||||
def _convert_timestamps_to_datetimes(image_meta):
|
def _convert_timestamps_to_datetimes(image_meta):
|
||||||
|
@@ -782,7 +782,7 @@ class TestIsImageAvailable(test.NoDBTestCase):
|
|||||||
ctx = mock.MagicMock(auth_token=True)
|
ctx = mock.MagicMock(auth_token=True)
|
||||||
img = mock.MagicMock()
|
img = mock.MagicMock()
|
||||||
|
|
||||||
res = glance.GlanceImageService._is_image_available(ctx, img)
|
res = glance._is_image_available(ctx, img)
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
img.assert_not_called()
|
img.assert_not_called()
|
||||||
|
|
||||||
@@ -790,7 +790,7 @@ class TestIsImageAvailable(test.NoDBTestCase):
|
|||||||
ctx = mock.MagicMock(auth_token=False, is_admin=True)
|
ctx = mock.MagicMock(auth_token=False, is_admin=True)
|
||||||
img = mock.MagicMock()
|
img = mock.MagicMock()
|
||||||
|
|
||||||
res = glance.GlanceImageService._is_image_available(ctx, img)
|
res = glance._is_image_available(ctx, img)
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
img.assert_not_called()
|
img.assert_not_called()
|
||||||
|
|
||||||
@@ -803,7 +803,7 @@ class TestIsImageAvailable(test.NoDBTestCase):
|
|||||||
img = mock.MagicMock(visibility='PUBLIC',
|
img = mock.MagicMock(visibility='PUBLIC',
|
||||||
spec=TestIsImageAvailable.ImageSpecV2)
|
spec=TestIsImageAvailable.ImageSpecV2)
|
||||||
|
|
||||||
res = glance.GlanceImageService._is_image_available(ctx, img)
|
res = glance._is_image_available(ctx, img)
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
|
|
||||||
def test_v1_is_public(self):
|
def test_v1_is_public(self):
|
||||||
@@ -811,7 +811,7 @@ class TestIsImageAvailable(test.NoDBTestCase):
|
|||||||
img = mock.MagicMock(is_public=True,
|
img = mock.MagicMock(is_public=True,
|
||||||
spec=TestIsImageAvailable.ImageSpecV1)
|
spec=TestIsImageAvailable.ImageSpecV1)
|
||||||
|
|
||||||
res = glance.GlanceImageService._is_image_available(ctx, img)
|
res = glance._is_image_available(ctx, img)
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
|
|
||||||
def test_project_is_owner(self):
|
def test_project_is_owner(self):
|
||||||
@@ -823,14 +823,14 @@ class TestIsImageAvailable(test.NoDBTestCase):
|
|||||||
img = mock.MagicMock(visibility='private', properties=props,
|
img = mock.MagicMock(visibility='private', properties=props,
|
||||||
spec=TestIsImageAvailable.ImageSpecV2)
|
spec=TestIsImageAvailable.ImageSpecV2)
|
||||||
|
|
||||||
res = glance.GlanceImageService._is_image_available(ctx, img)
|
res = glance._is_image_available(ctx, img)
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
|
|
||||||
ctx.reset_mock()
|
ctx.reset_mock()
|
||||||
img = mock.MagicMock(is_public=False, properties=props,
|
img = mock.MagicMock(is_public=False, properties=props,
|
||||||
spec=TestIsImageAvailable.ImageSpecV1)
|
spec=TestIsImageAvailable.ImageSpecV1)
|
||||||
|
|
||||||
res = glance.GlanceImageService._is_image_available(ctx, img)
|
res = glance._is_image_available(ctx, img)
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
|
|
||||||
def test_project_context_matches_project_prop(self):
|
def test_project_context_matches_project_prop(self):
|
||||||
@@ -842,14 +842,14 @@ class TestIsImageAvailable(test.NoDBTestCase):
|
|||||||
img = mock.MagicMock(visibility='private', properties=props,
|
img = mock.MagicMock(visibility='private', properties=props,
|
||||||
spec=TestIsImageAvailable.ImageSpecV2)
|
spec=TestIsImageAvailable.ImageSpecV2)
|
||||||
|
|
||||||
res = glance.GlanceImageService._is_image_available(ctx, img)
|
res = glance._is_image_available(ctx, img)
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
|
|
||||||
ctx.reset_mock()
|
ctx.reset_mock()
|
||||||
img = mock.MagicMock(is_public=False, properties=props,
|
img = mock.MagicMock(is_public=False, properties=props,
|
||||||
spec=TestIsImageAvailable.ImageSpecV1)
|
spec=TestIsImageAvailable.ImageSpecV1)
|
||||||
|
|
||||||
res = glance.GlanceImageService._is_image_available(ctx, img)
|
res = glance._is_image_available(ctx, img)
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
|
|
||||||
def test_no_user_in_props(self):
|
def test_no_user_in_props(self):
|
||||||
@@ -860,14 +860,14 @@ class TestIsImageAvailable(test.NoDBTestCase):
|
|||||||
img = mock.MagicMock(visibility='private', properties=props,
|
img = mock.MagicMock(visibility='private', properties=props,
|
||||||
spec=TestIsImageAvailable.ImageSpecV2)
|
spec=TestIsImageAvailable.ImageSpecV2)
|
||||||
|
|
||||||
res = glance.GlanceImageService._is_image_available(ctx, img)
|
res = glance._is_image_available(ctx, img)
|
||||||
self.assertFalse(res)
|
self.assertFalse(res)
|
||||||
|
|
||||||
ctx.reset_mock()
|
ctx.reset_mock()
|
||||||
img = mock.MagicMock(is_public=False, properties=props,
|
img = mock.MagicMock(is_public=False, properties=props,
|
||||||
spec=TestIsImageAvailable.ImageSpecV1)
|
spec=TestIsImageAvailable.ImageSpecV1)
|
||||||
|
|
||||||
res = glance.GlanceImageService._is_image_available(ctx, img)
|
res = glance._is_image_available(ctx, img)
|
||||||
self.assertFalse(res)
|
self.assertFalse(res)
|
||||||
|
|
||||||
def test_user_matches_context(self):
|
def test_user_matches_context(self):
|
||||||
@@ -879,14 +879,14 @@ class TestIsImageAvailable(test.NoDBTestCase):
|
|||||||
img = mock.MagicMock(visibility='private', properties=props,
|
img = mock.MagicMock(visibility='private', properties=props,
|
||||||
spec=TestIsImageAvailable.ImageSpecV2)
|
spec=TestIsImageAvailable.ImageSpecV2)
|
||||||
|
|
||||||
res = glance.GlanceImageService._is_image_available(ctx, img)
|
res = glance._is_image_available(ctx, img)
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
|
|
||||||
ctx.reset_mock()
|
ctx.reset_mock()
|
||||||
img = mock.MagicMock(is_public=False, properties=props,
|
img = mock.MagicMock(is_public=False, properties=props,
|
||||||
spec=TestIsImageAvailable.ImageSpecV1)
|
spec=TestIsImageAvailable.ImageSpecV1)
|
||||||
|
|
||||||
res = glance.GlanceImageService._is_image_available(ctx, img)
|
res = glance._is_image_available(ctx, img)
|
||||||
self.assertTrue(res)
|
self.assertTrue(res)
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user