}
"""
params = self._get_query_params(req)
images = self._get_images(req.context, **params)
results = []
for image in images:
result = {}
for field in DISPLAY_FIELDS_IN_INDEX:
result[field] = image[field]
results.append(result)
LOG.info(_("Returning image list"))
return dict(images=results)
**** CubicPower OpenStack Study ****
def detail(self, req):
"""Return a filtered list of public, non-deleted images in detail
:param req: the Request object coming from the wsgi layer
:retval a mapping of the following form::
dict(images=[image_list])
Where image_list is a sequence of mappings containing
all image model fields.
"""
params = self._get_query_params(req)
images = self._get_images(req.context, **params)
image_dicts = [make_image_dict(i) for i in images]
LOG.info(_("Returning detailed image list"))
return dict(images=image_dicts)
**** CubicPower OpenStack Study ****
def _get_query_params(self, req):
"""Extract necessary query parameters from http request.
:param req: the Request object coming from the wsgi layer
:retval dictionary of filters to apply to list of images
"""
params = {
'filters': self._get_filters(req),
'limit': self._get_limit(req),
'sort_key': self._get_sort_key(req),
'sort_dir': self._get_sort_dir(req),
'marker': self._get_marker(req),
}
if req.context.is_admin:
# Only admin gets to look for non-public images
params['is_public'] = self._get_is_public(req)
for key, value in params.items():
if value is None:
del params[key]
# Fix for LP Bug #1132294
# Ensure all shared images are returned in v1
params['member_status'] = 'all'
return params
**** CubicPower OpenStack Study ****
def _get_filters(self, req):
"""Return a dictionary of query param filters from the request
:param req: the Request object coming from the wsgi layer
:retval a dict of key/value filters
"""
filters = {}
properties = {}
for param in req.params:
if param in SUPPORTED_FILTERS:
filters[param] = req.params.get(param)
if param.startswith('property-'):
_param = param[9:]
properties[_param] = req.params.get(param)
if 'changes-since' in filters:
isotime = filters['changes-since']
try:
filters['changes-since'] = timeutils.parse_isotime(isotime)
except ValueError:
raise exc.HTTPBadRequest(_("Unrecognized changes-since value"))
if 'protected' in filters:
value = self._get_bool(filters['protected'])
if value is None:
raise exc.HTTPBadRequest(_("protected must be True, or "
"False"))
filters['protected'] = value
# only allow admins to filter on 'deleted'
if req.context.is_admin:
deleted_filter = self._parse_deleted_filter(req)
if deleted_filter is not None:
filters['deleted'] = deleted_filter
elif 'changes-since' not in filters:
filters['deleted'] = False
elif 'changes-since' not in filters:
filters['deleted'] = False
if properties:
filters['properties'] = properties
return filters
**** CubicPower OpenStack Study ****
def _get_limit(self, req):
"""Parse a limit query param into something usable."""
try:
limit = int(req.params.get('limit', CONF.limit_param_default))
except ValueError:
raise exc.HTTPBadRequest(_("limit param must be an integer"))
if limit < 0:
raise exc.HTTPBadRequest(_("limit param must be positive"))
return min(CONF.api_limit_max, limit)
**** CubicPower OpenStack Study ****
def _get_marker(self, req):
"""Parse a marker query param into something usable."""
marker = req.params.get('marker', None)
if marker and not utils.is_uuid_like(marker):
msg = _('Invalid marker format')
raise exc.HTTPBadRequest(explanation=msg)
return marker
**** CubicPower OpenStack Study ****
def _get_sort_key(self, req):
"""Parse a sort key query param from the request object."""
sort_key = req.params.get('sort_key', None)
if sort_key is not None and sort_key not in SUPPORTED_SORT_KEYS:
_keys = ', '.join(SUPPORTED_SORT_KEYS)
msg = _("Unsupported sort_key. Acceptable values: %s") % (_keys,)
raise exc.HTTPBadRequest(explanation=msg)
return sort_key
**** CubicPower OpenStack Study ****
def _get_sort_dir(self, req):
"""Parse a sort direction query param from the request object."""
sort_dir = req.params.get('sort_dir', None)
if sort_dir is not None and sort_dir not in SUPPORTED_SORT_DIRS:
_keys = ', '.join(SUPPORTED_SORT_DIRS)
msg = _("Unsupported sort_dir. Acceptable values: %s") % (_keys,)
raise exc.HTTPBadRequest(explanation=msg)
return sort_dir
**** CubicPower OpenStack Study ****
def _get_bool(self, value):
value = value.lower()
if value == 'true' or value == '1':
return True
elif value == 'false' or value == '0':
return False
return None
**** CubicPower OpenStack Study ****
def _get_is_public(self, req):
"""Parse is_public into something usable."""
is_public = req.params.get('is_public', None)
if is_public is None:
# NOTE(vish): This preserves the default value of showing only
# public images.
return True
elif is_public.lower() == 'none':
return None
value = self._get_bool(is_public)
if value is None:
raise exc.HTTPBadRequest(_("is_public must be None, True, or "
"False"))
return value
**** CubicPower OpenStack Study ****
def _parse_deleted_filter(self, req):
"""Parse deleted into something usable."""
deleted = req.params.get('deleted')
if deleted is None:
return None
return strutils.bool_from_string(deleted)
**** CubicPower OpenStack Study ****
def show(self, req, id):
"""Return data about the given image id."""
try:
image = self.db_api.image_get(req.context, id)
msg = _("Successfully retrieved image %(id)s")
LOG.info(msg % {'id': id})
except exception.NotFound:
msg = _("Image %(id)s not found")
LOG.info(msg % {'id': id})
raise exc.HTTPNotFound()
except exception.Forbidden:
# If it's private and doesn't belong to them, don't let on
# that it exists
msg = _("Access denied to image %(id)s but returning 'not found'")
LOG.info(msg % {'id': id})
raise exc.HTTPNotFound()
except Exception:
LOG.exception(_("Unable to show image %s"), id)
raise
return dict(image=make_image_dict(image))
@utils.mutating
**** CubicPower OpenStack Study ****
def delete(self, req, id):
"""Deletes an existing image with the registry.
:param req: wsgi Request object
:param id: The opaque internal identifier for the image
:retval Returns 200 if delete was successful, a fault if not. On
success, the body contains the deleted image information as a mapping.
"""
try:
deleted_image = self.db_api.image_destroy(req.context, id)
msg = _("Successfully deleted image %(id)s")
LOG.info(msg % {'id': id})
return dict(image=make_image_dict(deleted_image))
except exception.ForbiddenPublicImage:
msg = _("Delete denied for public image %(id)s")
LOG.info(msg % {'id': id})
raise exc.HTTPForbidden()
except exception.Forbidden:
# If it's private and doesn't belong to them, don't let on
# that it exists
msg = _("Access denied to image %(id)s but returning 'not found'")
LOG.info(msg % {'id': id})
return exc.HTTPNotFound()
except exception.NotFound:
msg = _("Image %(id)s not found")
LOG.info(msg % {'id': id})
return exc.HTTPNotFound()
except Exception:
LOG.exception(_("Unable to delete image %s"), id)
raise
@utils.mutating
**** CubicPower OpenStack Study ****
def create(self, req, body):
"""Registers a new image with the registry.
:param req: wsgi Request object
:param body: Dictionary of information about the image
:retval Returns the newly-created image information as a mapping,
which will include the newly-created image's internal id
in the 'id' field
"""
image_data = body['image']
# Ensure the image has a status set
image_data.setdefault('status', 'active')
# Set up the image owner
if not req.context.is_admin or 'owner' not in image_data:
image_data['owner'] = req.context.owner
image_id = image_data.get('id')
if image_id and not utils.is_uuid_like(image_id):
msg = _("Rejecting image creation request for invalid image "
"id '%(bad_id)s'")
LOG.info(msg % {'bad_id': image_id})
msg = _("Invalid image id format")
return exc.HTTPBadRequest(explanation=msg)
if 'location' in image_data:
image_data['locations'] = [image_data.pop('location')]
try:
image_data = _normalize_image_location_for_db(image_data)
image_data = self.db_api.image_create(req.context, image_data)
image_data = dict(image=make_image_dict(image_data))
msg = _("Successfully created image %(id)s") % image_data['image']
LOG.info(msg)
return image_data
except exception.Duplicate:
msg = _("Image with identifier %s already exists!") % image_id
LOG.error(msg)
return exc.HTTPConflict(msg)
except exception.Invalid as e:
msg = (_("Failed to add image metadata. "
"Got error: %(e)s") % {'e': e})
LOG.error(msg)
return exc.HTTPBadRequest(msg)
except Exception:
LOG.exception(_("Unable to create image %s"), image_id)
raise
@utils.mutating
**** CubicPower OpenStack Study ****
def update(self, req, id, body):
"""Updates an existing image with the registry.
:param req: wsgi Request object
:param body: Dictionary of information about the image
:param id: The opaque internal identifier for the image
:retval Returns the updated image information as a mapping,
"""
image_data = body['image']
from_state = body.get('from_state', None)
# Prohibit modification of 'owner'
if not req.context.is_admin and 'owner' in image_data:
del image_data['owner']
if 'location' in image_data:
image_data['locations'] = [image_data.pop('location')]
purge_props = req.headers.get("X-Glance-Registry-Purge-Props", "false")
try:
LOG.debug(_("Updating image %(id)s with metadata: "
"%(image_data)r"), {'id': id,
'image_data': image_data})
image_data = _normalize_image_location_for_db(image_data)
if purge_props == "true":
purge_props = True
else:
purge_props = False
updated_image = self.db_api.image_update(req.context, id,
image_data,
purge_props=purge_props,
from_state=from_state)
msg = _("Updating metadata for image %(id)s")
LOG.info(msg % {'id': id})
return dict(image=make_image_dict(updated_image))
except exception.Invalid as e:
msg = (_("Failed to update image metadata. "
"Got error: %(e)s") % {'e': e})
LOG.error(msg)
return exc.HTTPBadRequest(msg)
except exception.NotFound:
msg = _("Image %(id)s not found")
LOG.info(msg % {'id': id})
raise exc.HTTPNotFound(body='Image not found',
request=req,
content_type='text/plain')
except exception.ForbiddenPublicImage:
msg = _("Update denied for public image %(id)s")
LOG.info(msg % {'id': id})
raise exc.HTTPForbidden()
except exception.Forbidden:
# If it's private and doesn't belong to them, don't let on
# that it exists
msg = _("Access denied to image %(id)s but returning 'not found'")
LOG.info(msg % {'id': id})
raise exc.HTTPNotFound(body='Image not found',
request=req,
content_type='text/plain')
except exception.Conflict as e:
LOG.info(unicode(e))
raise exc.HTTPConflict(body='Image operation conflicts',
request=req,
content_type='text/plain')
except Exception:
LOG.exception(_("Unable to update image %s"), id)
raise
def _limit_locations(image):
locations = image.pop('locations', [])
try:
image['location'] = locations[0]['url']
except IndexError:
image['location'] = None
image['location_data'] = locations
def make_image_dict(image):
"""Create a dict representation of an image which we can use to
serialize the image.
"""
**** CubicPower OpenStack Study ****
def _limit_locations(image):
locations = image.pop('locations', [])
try:
image['location'] = locations[0]['url']
except IndexError:
image['location'] = None
image['location_data'] = locations
**** CubicPower OpenStack Study ****
def make_image_dict(image):
"""Create a dict representation of an image which we can use to
serialize the image.
"""
**** CubicPower OpenStack Study ****
def _fetch_attrs(d, attrs):
return dict([(a, d[a]) for a in attrs
if a in d.keys()])
# TODO(sirp): should this be a dict, or a list of dicts?
# A plain dict is more convenient, but list of dicts would provide
# access to created_at, etc
properties = dict((p['name'], p['value'])
for p in image['properties'] if not p['deleted'])
image_dict = _fetch_attrs(image, glance.db.IMAGE_ATTRS)
image_dict['properties'] = properties
_limit_locations(image_dict)
return image_dict
def create_resource():
"""Images resource factory method."""
deserializer = wsgi.JSONRequestDeserializer()
serializer = wsgi.JSONResponseSerializer()
return wsgi.Resource(Controller(), deserializer, serializer)
**** CubicPower OpenStack Study ****
def create_resource():
"""Images resource factory method."""
deserializer = wsgi.JSONRequestDeserializer()
serializer = wsgi.JSONResponseSerializer()
return wsgi.Resource(Controller(), deserializer, serializer)