Update db layer to expose multiple image locations
* The DB API now exposes a 'locations' image attribute rather than 'location'. The new field is guaranteed to be a list of zero of more items * The v1 and v2 APIs only look for the first item in the list of locations. * Related to bp multiple-image-locations Change-Id: I830b383d8a8e50a01e461658fb9abe384de1a353
This commit is contained in:
parent
4028e74ef4
commit
222a00fef9
|
@ -227,7 +227,7 @@ class ImmutableImageProxy(object):
|
|||
min_disk = _immutable_attr('base', 'min_disk')
|
||||
min_ram = _immutable_attr('base', 'min_ram')
|
||||
protected = _immutable_attr('base', 'protected')
|
||||
location = _immutable_attr('base', 'location')
|
||||
locations = _immutable_attr('base', 'locations')
|
||||
checksum = _immutable_attr('base', 'checksum')
|
||||
owner = _immutable_attr('base', 'owner')
|
||||
disk_format = _immutable_attr('base', 'disk_format')
|
||||
|
|
|
@ -20,10 +20,9 @@ from glance.common import exception
|
|||
|
||||
def update_image_read_acl(req, store_api, db_api, image):
|
||||
"""Helper function to set ACL permissions on images in the image store"""
|
||||
location_uri = image['location']
|
||||
public = image['is_public']
|
||||
image_id = image['id']
|
||||
if location_uri:
|
||||
if image['locations']:
|
||||
try:
|
||||
read_tenants = []
|
||||
write_tenants = []
|
||||
|
@ -34,9 +33,10 @@ def update_image_read_acl(req, store_api, db_api, image):
|
|||
write_tenants.append(member['member'])
|
||||
else:
|
||||
read_tenants.append(member['member'])
|
||||
store_api.set_acls(req.context, location_uri, public=public,
|
||||
read_tenants=read_tenants,
|
||||
write_tenants=write_tenants)
|
||||
for location in image['locations']:
|
||||
store_api.set_acls(req.context, location, public=public,
|
||||
read_tenants=read_tenants,
|
||||
write_tenants=write_tenants)
|
||||
except exception.UnknownScheme:
|
||||
msg = _("Store for image_id not found: %s") % image_id
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg,
|
||||
|
|
|
@ -93,7 +93,7 @@ class ImageDataController(object):
|
|||
except exception.Forbidden as e:
|
||||
raise webob.exc.HTTPForbidden(explanation=unicode(e))
|
||||
|
||||
if not image.location:
|
||||
if not image.locations:
|
||||
reason = _("No image data could be found")
|
||||
raise webob.exc.HTTPNotFound(reason)
|
||||
return image
|
||||
|
|
|
@ -152,10 +152,9 @@ class ImageMembersController(object):
|
|||
raise webob.exc.HTTPForbidden(explanation=unicode(e))
|
||||
|
||||
def _update_store_acls(self, req, image):
|
||||
location_uri = image.location
|
||||
public = image.visibility == 'public'
|
||||
member_repo = image.get_member_repo()
|
||||
if location_uri:
|
||||
if image.locations:
|
||||
try:
|
||||
read_tenants = []
|
||||
write_tenants = []
|
||||
|
@ -163,9 +162,10 @@ class ImageMembersController(object):
|
|||
if members:
|
||||
for member in members:
|
||||
read_tenants.append(member.member_id)
|
||||
glance.store.set_acls(req.context, location_uri, public=public,
|
||||
read_tenants=read_tenants,
|
||||
write_tenants=write_tenants)
|
||||
for location in image.locations:
|
||||
glance.store.set_acls(req.context, location, public=public,
|
||||
read_tenants=read_tenants,
|
||||
write_tenants=write_tenants)
|
||||
except exception.UnknownScheme:
|
||||
msg = _("Store for image not found: %s") % image_id
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg,
|
||||
|
|
|
@ -173,8 +173,8 @@ class RequestDeserializer(wsgi.JSONRequestDeserializer):
|
|||
_disallowed_properties = ['direct_url', 'self', 'file', 'schema']
|
||||
_readonly_properties = ['created_at', 'updated_at', 'status', 'checksum',
|
||||
'size', 'direct_url', 'self', 'file', 'schema']
|
||||
_reserved_properties = ['owner', 'is_public', 'location', 'deleted',
|
||||
'deleted_at']
|
||||
_reserved_properties = ['owner', 'is_public', 'location', 'locations',
|
||||
'deleted', 'deleted_at']
|
||||
_base_properties = ['checksum', 'created_at', 'container_format',
|
||||
'disk_format', 'id', 'min_disk', 'min_ram', 'name',
|
||||
'size', 'status', 'tags', 'updated_at', 'visibility',
|
||||
|
@ -431,8 +431,8 @@ class ResponseSerializer(wsgi.JSONResponseSerializer):
|
|||
image_view['id'] = image.image_id
|
||||
image_view['created_at'] = timeutils.isotime(image.created_at)
|
||||
image_view['updated_at'] = timeutils.isotime(image.updated_at)
|
||||
if CONF.show_image_direct_url and image.location is not None: # domain
|
||||
image_view['direct_url'] = image.location
|
||||
if CONF.show_image_direct_url and image.locations: # domain
|
||||
image_view['direct_url'] = image.locations[0]
|
||||
image_view['tags'] = list(image.tags)
|
||||
image_view['self'] = self._get_image_href(image)
|
||||
image_view['file'] = self._get_image_href(image, 'file')
|
||||
|
|
|
@ -58,7 +58,7 @@ BASE_MODEL_ATTRS = set(['id', 'created_at', 'updated_at', 'deleted_at',
|
|||
IMAGE_ATTRS = BASE_MODEL_ATTRS | set(['name', 'status', 'size',
|
||||
'disk_format', 'container_format',
|
||||
'min_disk', 'min_ram', 'is_public',
|
||||
'location', 'checksum', 'owner',
|
||||
'locations', 'checksum', 'owner',
|
||||
'protected'])
|
||||
|
||||
|
||||
|
@ -109,7 +109,7 @@ class ImageRepo(object):
|
|||
min_disk=db_image['min_disk'],
|
||||
min_ram=db_image['min_ram'],
|
||||
protected=db_image['protected'],
|
||||
location=db_image['location'],
|
||||
locations=db_image['locations'],
|
||||
checksum=db_image['checksum'],
|
||||
owner=db_image['owner'],
|
||||
disk_format=db_image['disk_format'],
|
||||
|
@ -128,7 +128,7 @@ class ImageRepo(object):
|
|||
'min_disk': image.min_disk,
|
||||
'min_ram': image.min_ram,
|
||||
'protected': image.protected,
|
||||
'location': image.location,
|
||||
'locations': image.locations,
|
||||
'checksum': image.checksum,
|
||||
'owner': image.owner,
|
||||
'disk_format': image.disk_format,
|
||||
|
|
|
@ -96,7 +96,7 @@ def _image_format(image_id, **values):
|
|||
'id': image_id,
|
||||
'name': None,
|
||||
'owner': None,
|
||||
'location': None,
|
||||
'locations': [],
|
||||
'status': 'queued',
|
||||
'protected': False,
|
||||
'is_public': False,
|
||||
|
@ -349,7 +349,7 @@ def image_create(context, image_values):
|
|||
raise exception.Invalid('status is a required attribute')
|
||||
|
||||
allowed_keys = set(['id', 'name', 'status', 'min_ram', 'min_disk', 'size',
|
||||
'checksum', 'location', 'owner', 'protected',
|
||||
'checksum', 'locations', 'owner', 'protected',
|
||||
'is_public', 'container_format', 'disk_format',
|
||||
'created_at', 'updated_at', 'deleted_at', 'deleted',
|
||||
'properties', 'tags'])
|
||||
|
|
|
@ -249,11 +249,13 @@ def image_destroy(context, image_id):
|
|||
"""Destroy the image or raise if it does not exist."""
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
image_ref = image_get(context, image_id, session=session)
|
||||
image_ref = _image_get(context, image_id, session=session)
|
||||
|
||||
# Perform authorization check
|
||||
check_mutate_authorization(context, image_ref)
|
||||
|
||||
_image_locations_set(image_ref.id, [], session)
|
||||
|
||||
image_ref.delete(session=session)
|
||||
|
||||
for prop_ref in image_ref.properties:
|
||||
|
@ -263,20 +265,23 @@ def image_destroy(context, image_id):
|
|||
for memb_ref in members:
|
||||
_image_member_delete(context, memb_ref, session)
|
||||
|
||||
return image_ref
|
||||
return _normalize_locations(image_ref)
|
||||
|
||||
|
||||
def _limit_image_locations(image):
|
||||
#NOTE(bcwaldon): mock this out until we support multiple images above
|
||||
# the sqlalchemy db layer
|
||||
if len(image.locations) > 0:
|
||||
image.location = image.locations[0].value
|
||||
else:
|
||||
image.location = None
|
||||
def _normalize_locations(image):
|
||||
undeleted_locations = filter(lambda x: not x.deleted, image['locations'])
|
||||
image['locations'] = [loc['value'] for loc in undeleted_locations]
|
||||
return image
|
||||
|
||||
|
||||
def image_get(context, image_id, session=None, force_show_deleted=False):
|
||||
image = _image_get(context, image_id, session=session,
|
||||
force_show_deleted=force_show_deleted)
|
||||
image = _normalize_locations(image.to_dict())
|
||||
return image
|
||||
|
||||
|
||||
def _image_get(context, image_id, session=None, force_show_deleted=False):
|
||||
"""Get an image or raise if it does not exist."""
|
||||
session = session or get_session()
|
||||
|
||||
|
@ -299,11 +304,7 @@ def image_get(context, image_id, session=None, force_show_deleted=False):
|
|||
if not is_image_visible(context, image):
|
||||
raise exception.Forbidden("Image not visible to you")
|
||||
|
||||
#NOTE(bcwaldon): mock this out until we support multiple images above
|
||||
# the sqlalchemy db layer
|
||||
image.location = _image_location_get(image_id, session)
|
||||
|
||||
return _limit_image_locations(image)
|
||||
return image
|
||||
|
||||
|
||||
def is_image_mutable(context, image):
|
||||
|
@ -588,15 +589,15 @@ def image_get_all(context, filters=None, marker=None, limit=None,
|
|||
|
||||
marker_image = None
|
||||
if marker is not None:
|
||||
marker_image = image_get(context, marker,
|
||||
force_show_deleted=showing_deleted)
|
||||
marker_image = _image_get(context, marker,
|
||||
force_show_deleted=showing_deleted)
|
||||
|
||||
query = paginate_query(query, models.Image, limit,
|
||||
[sort_key, 'created_at', 'id'],
|
||||
marker=marker_image,
|
||||
sort_dir=sort_dir)
|
||||
|
||||
return [_limit_image_locations(image) for image in query.all()]
|
||||
return [_normalize_locations(image.to_dict()) for image in query.all()]
|
||||
|
||||
|
||||
def _drop_protected_attrs(model_class, values):
|
||||
|
@ -656,13 +657,13 @@ def _image_update(context, values, image_id, purge_props=False):
|
|||
properties = values.pop('properties', {})
|
||||
|
||||
try:
|
||||
location = values.pop('location')
|
||||
location_provided = True
|
||||
locations = values.pop('locations')
|
||||
locations_provided = True
|
||||
except KeyError:
|
||||
location_provided = False
|
||||
locations_provided = False
|
||||
|
||||
if image_id:
|
||||
image_ref = image_get(context, image_id, session=session)
|
||||
image_ref = _image_get(context, image_id, session=session)
|
||||
|
||||
# Perform authorization check
|
||||
check_mutate_authorization(context, image_ref)
|
||||
|
@ -708,32 +709,21 @@ def _image_update(context, values, image_id, purge_props=False):
|
|||
_set_properties_for_image(context, image_ref, properties, purge_props,
|
||||
session)
|
||||
|
||||
if location_provided:
|
||||
_image_location_set(image_ref.id, location, session)
|
||||
if locations_provided:
|
||||
_image_locations_set(image_ref.id, locations, session)
|
||||
|
||||
return image_get(context, image_ref.id)
|
||||
|
||||
|
||||
def _image_location_get(image_id, session):
|
||||
location = session.query(models.ImageLocation)\
|
||||
.filter_by(image_id=image_id)\
|
||||
.filter_by(deleted=False)\
|
||||
.first()
|
||||
try:
|
||||
return location['value']
|
||||
except TypeError:
|
||||
return None
|
||||
|
||||
|
||||
def _image_location_set(image_id, location, session):
|
||||
locations = session.query(models.ImageLocation)\
|
||||
.filter_by(image_id=image_id)\
|
||||
.filter_by(deleted=False)\
|
||||
.all()
|
||||
for location_ref in locations:
|
||||
def _image_locations_set(image_id, locations, session):
|
||||
location_refs = session.query(models.ImageLocation)\
|
||||
.filter_by(image_id=image_id)\
|
||||
.filter_by(deleted=False)\
|
||||
.all()
|
||||
for location_ref in location_refs:
|
||||
location_ref.delete(session=session)
|
||||
|
||||
if location is not None:
|
||||
for location in locations:
|
||||
location_ref = models.ImageLocation(image_id=image_id, value=location)
|
||||
location_ref.save()
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ from glance.openstack.common import uuidutils
|
|||
class ImageFactory(object):
|
||||
_readonly_properties = ['created_at', 'updated_at', 'status', 'checksum',
|
||||
'size']
|
||||
_reserved_properties = ['owner', 'is_public', 'location',
|
||||
_reserved_properties = ['owner', 'is_public', 'locations',
|
||||
'deleted', 'deleted_at', 'direct_url', 'self',
|
||||
'file', 'schema']
|
||||
|
||||
|
@ -76,7 +76,7 @@ class Image(object):
|
|||
self.min_disk = kwargs.pop('min_disk', 0)
|
||||
self.min_ram = kwargs.pop('min_ram', 0)
|
||||
self.protected = kwargs.pop('protected', False)
|
||||
self.location = kwargs.pop('location', None)
|
||||
self.locations = kwargs.pop('locations', [])
|
||||
self.checksum = kwargs.pop('checksum', None)
|
||||
self.owner = kwargs.pop('owner', None)
|
||||
self.disk_format = kwargs.pop('disk_format', None)
|
||||
|
@ -166,7 +166,7 @@ class ImageProxy(object):
|
|||
min_disk = _proxy('base', 'min_disk')
|
||||
min_ram = _proxy('base', 'min_ram')
|
||||
protected = _proxy('base', 'protected')
|
||||
location = _proxy('base', 'location')
|
||||
locations = _proxy('base', 'locations')
|
||||
checksum = _proxy('base', 'checksum')
|
||||
owner = _proxy('base', 'owner')
|
||||
disk_format = _proxy('base', 'disk_format')
|
||||
|
|
|
@ -351,6 +351,9 @@ class Controller(object):
|
|||
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 = self.db_api.image_create(req.context, image_data)
|
||||
msg = _("Successfully created image %(id)s")
|
||||
|
@ -383,6 +386,9 @@ class Controller(object):
|
|||
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: "
|
||||
|
@ -421,6 +427,14 @@ class Controller(object):
|
|||
content_type='text/plain')
|
||||
|
||||
|
||||
def _limit_locations(image):
|
||||
locations = image.pop('locations', [])
|
||||
try:
|
||||
image['location'] = locations[0]
|
||||
except IndexError:
|
||||
image['location'] = None
|
||||
|
||||
|
||||
def make_image_dict(image):
|
||||
"""
|
||||
Create a dict representation of an image which we can use to
|
||||
|
@ -438,8 +452,9 @@ def make_image_dict(image):
|
|||
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
|
||||
|
||||
|
||||
|
|
|
@ -332,15 +332,16 @@ class ImageProxy(glance.domain.ImageProxy):
|
|||
|
||||
def delete(self):
|
||||
self.image.delete()
|
||||
if self.image.location:
|
||||
if self.image.locations:
|
||||
if CONF.delayed_delete:
|
||||
self.image.status = 'pending_delete'
|
||||
self.store_api.schedule_delayed_delete_from_backend(
|
||||
self.image.location, self.image.image_id)
|
||||
for location in self.image.locations:
|
||||
self.store_api.schedule_delayed_delete_from_backend(
|
||||
location, self.image.image_id)
|
||||
else:
|
||||
self.store_api.safe_delete_from_backend(self.image.location,
|
||||
self.context,
|
||||
self.image.image_id)
|
||||
for location in self.image.locations:
|
||||
self.store_api.safe_delete_from_backend(
|
||||
location, self.context, self.image.image_id)
|
||||
|
||||
def set_data(self, data, size=None):
|
||||
if size is None:
|
||||
|
@ -348,14 +349,14 @@ class ImageProxy(glance.domain.ImageProxy):
|
|||
location, size, checksum = self.store_api.add_to_backend(
|
||||
self.context, CONF.default_store,
|
||||
self.image.image_id, data, size)
|
||||
self.image.location = location
|
||||
self.image.locations = [location]
|
||||
self.image.size = size
|
||||
self.image.checksum = checksum
|
||||
self.image.status = 'active'
|
||||
|
||||
def get_data(self):
|
||||
if not self.image.location:
|
||||
if not self.image.locations:
|
||||
raise exception.NotFound(_("No image data could be found"))
|
||||
data, size = self.store_api.get_from_backend(self.context,
|
||||
self.image.location)
|
||||
self.image.locations[0])
|
||||
return data
|
||||
|
|
|
@ -53,7 +53,7 @@ def build_image_fixture(**kwargs):
|
|||
'min_disk': 5,
|
||||
'min_ram': 256,
|
||||
'size': 19,
|
||||
'location': "file:///tmp/glance-tests/2",
|
||||
'locations': ["file:///tmp/glance-tests/2"],
|
||||
'properties': {},
|
||||
}
|
||||
image.update(kwargs)
|
||||
|
@ -125,7 +125,7 @@ class DriverTests(object):
|
|||
self.assertEqual(None, image['size'])
|
||||
self.assertEqual(None, image['checksum'])
|
||||
self.assertEqual(None, image['disk_format'])
|
||||
self.assertEqual(None, image['location'])
|
||||
self.assertEqual([], image['locations'])
|
||||
self.assertEqual(False, image['protected'])
|
||||
self.assertEqual(False, image['deleted'])
|
||||
self.assertEqual(None, image['deleted_at'])
|
||||
|
@ -145,6 +145,11 @@ class DriverTests(object):
|
|||
self.db_api.image_create,
|
||||
self.context, {'id': UUID1, 'status': 'queued'})
|
||||
|
||||
def test_image_create_with_locations(self):
|
||||
fixture = {'status': 'queued', 'locations': ['a', 'b']}
|
||||
image = self.db_api.image_create(self.context, fixture)
|
||||
self.assertEqual(['a', 'b'], image['locations'])
|
||||
|
||||
def test_image_create_properties(self):
|
||||
fixture = {'status': 'queued', 'properties': {'ping': 'pong'}}
|
||||
image = self.db_api.image_create(self.context, fixture)
|
||||
|
@ -164,6 +169,11 @@ class DriverTests(object):
|
|||
self.assertEqual('queued', image['status'])
|
||||
self.assertNotEqual(image['created_at'], image['updated_at'])
|
||||
|
||||
def test_image_update_with_locations(self):
|
||||
fixture = {'locations': ['a', 'b']}
|
||||
image = self.db_api.image_update(self.adm_context, UUID3, fixture)
|
||||
self.assertEqual(['a', 'b'], image['locations'])
|
||||
|
||||
def test_image_update(self):
|
||||
fixture = {'status': 'queued', 'properties': {'ping': 'pong'}}
|
||||
image = self.db_api.image_update(self.adm_context, UUID3, fixture)
|
||||
|
@ -411,6 +421,13 @@ class DriverTests(object):
|
|||
images = self.db_api.image_get_all(self.context, limit=2)
|
||||
self.assertEquals(2, len(images))
|
||||
|
||||
def test_image_destroy(self):
|
||||
image = self.db_api.image_destroy(self.adm_context, UUID3)
|
||||
self.assertTrue(image['deleted'])
|
||||
self.assertTrue(image['deleted_at'])
|
||||
self.assertRaises(exception.NotFound, self.db_api.image_get,
|
||||
self.context, UUID3)
|
||||
|
||||
def test_image_get_multiple_members(self):
|
||||
TENANT1 = uuidutils.generate_uuid()
|
||||
TENANT2 = uuidutils.generate_uuid()
|
||||
|
|
|
@ -639,8 +639,8 @@ class TestImmutableImage(utils.BaseTestCase):
|
|||
def test_change_updated_at(self):
|
||||
self._test_change('updated_at', timeutils.utcnow())
|
||||
|
||||
def test_change_location(self):
|
||||
self._test_change('location', 'http://a/b/c')
|
||||
def test_change_locations(self):
|
||||
self._test_change('locations', ['http://a/b/c'])
|
||||
|
||||
def test_change_size(self):
|
||||
self._test_change('size', 32)
|
||||
|
|
|
@ -45,7 +45,7 @@ def _db_fixture(id, **kwargs):
|
|||
'status': 'queued',
|
||||
'tags': [],
|
||||
'size': None,
|
||||
'location': None,
|
||||
'locations': [],
|
||||
'protected': False,
|
||||
'disk_format': None,
|
||||
'container_format': None,
|
||||
|
|
|
@ -449,7 +449,7 @@ class TestImageNotifications(utils.BaseTestCase):
|
|||
visibility='public', container_format='ami',
|
||||
tags=['one', 'two'], disk_format='ami', min_ram=128,
|
||||
min_disk=10, checksum='ca425b88f047ce8ec45ee90e813ada91',
|
||||
location='http://127.0.0.1')
|
||||
locations=['http://127.0.0.1'])
|
||||
self.context = glance.context.RequestContext(tenant=TENANT2,
|
||||
user=USER1)
|
||||
self.image_repo_stub = ImageRepoStub()
|
||||
|
|
|
@ -34,10 +34,10 @@ class ImageRepoStub(object):
|
|||
|
||||
|
||||
class ImageStub(object):
|
||||
def __init__(self, image_id, status, location):
|
||||
def __init__(self, image_id, status, locations):
|
||||
self.image_id = image_id
|
||||
self.status = status
|
||||
self.location = location
|
||||
self.locations = locations
|
||||
|
||||
def delete(self):
|
||||
self.status = 'deleted'
|
||||
|
@ -45,20 +45,21 @@ class ImageStub(object):
|
|||
|
||||
class TestStoreImage(utils.BaseTestCase):
|
||||
def setUp(self):
|
||||
location = '%s/%s' % (BASE_URI, UUID1)
|
||||
self.image_stub = ImageStub(UUID1, 'active', location)
|
||||
locations = ['%s/%s' % (BASE_URI, UUID1)]
|
||||
self.image_stub = ImageStub(UUID1, 'active', locations)
|
||||
self.image_repo_stub = ImageRepoStub()
|
||||
self.store_api = unit_test_utils.FakeStoreAPI()
|
||||
super(TestStoreImage, self).setUp()
|
||||
|
||||
def test_image_delete(self):
|
||||
image = glance.store.ImageProxy(self.image_stub, {}, self.store_api)
|
||||
location = image.locations[0]
|
||||
self.assertEquals(image.status, 'active')
|
||||
self.store_api.get_from_backend({}, image.location) # no exception
|
||||
self.store_api.get_from_backend({}, location)
|
||||
image.delete()
|
||||
self.assertEquals(image.status, 'deleted')
|
||||
self.assertRaises(exception.NotFound,
|
||||
self.store_api.get_from_backend, {}, image.location)
|
||||
self.store_api.get_from_backend, {}, location)
|
||||
|
||||
def test_image_delayed_delete(self):
|
||||
self.config(delayed_delete=True)
|
||||
|
@ -66,7 +67,7 @@ class TestStoreImage(utils.BaseTestCase):
|
|||
self.assertEquals(image.status, 'active')
|
||||
image.delete()
|
||||
self.assertEquals(image.status, 'pending_delete')
|
||||
self.store_api.get_from_backend({}, image.location) # no exception
|
||||
self.store_api.get_from_backend({}, image.locations[0]) # no exception
|
||||
|
||||
def test_image_get_data(self):
|
||||
image = glance.store.ImageProxy(self.image_stub, {}, self.store_api)
|
||||
|
@ -74,23 +75,23 @@ class TestStoreImage(utils.BaseTestCase):
|
|||
|
||||
def test_image_set_data(self):
|
||||
context = glance.context.RequestContext(user=USER1)
|
||||
image_stub = ImageStub(UUID2, status='queued', location=None)
|
||||
image_stub = ImageStub(UUID2, status='queued', locations=[])
|
||||
image = glance.store.ImageProxy(image_stub, context, self.store_api)
|
||||
image.set_data('YYYY', 4)
|
||||
self.assertEquals(image.size, 4)
|
||||
#NOTE(markwash): FakeStore returns image_id for location
|
||||
self.assertEquals(image.location, UUID2)
|
||||
self.assertEquals(image.locations, [UUID2])
|
||||
self.assertEquals(image.checksum, 'Z')
|
||||
self.assertEquals(image.status, 'active')
|
||||
|
||||
def test_image_set_data_unknown_size(self):
|
||||
context = glance.context.RequestContext(user=USER1)
|
||||
image_stub = ImageStub(UUID2, status='queued', location=None)
|
||||
image_stub = ImageStub(UUID2, status='queued', locations=[])
|
||||
image = glance.store.ImageProxy(image_stub, context, self.store_api)
|
||||
image.set_data('YYYY', None)
|
||||
self.assertEquals(image.size, 4)
|
||||
#NOTE(markwash): FakeStore returns image_id for location
|
||||
self.assertEquals(image.location, UUID2)
|
||||
self.assertEquals(image.locations, [UUID2])
|
||||
self.assertEquals(image.checksum, 'Z')
|
||||
self.assertEquals(image.status, 'active')
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ class FakeDB(object):
|
|||
def init_db():
|
||||
images = [
|
||||
{'id': UUID1, 'owner': TENANT1, 'status': 'queued',
|
||||
'location': '%s/%s' % (BASE_URI, UUID1)},
|
||||
'locations': ['%s/%s' % (BASE_URI, UUID1)]},
|
||||
{'id': UUID2, 'owner': TENANT1, 'status': 'queued'},
|
||||
]
|
||||
[simple_db.image_create(None, image) for image in images]
|
||||
|
|
|
@ -125,7 +125,7 @@ class TestRegistryAPI(base.IsolatedUnitTest):
|
|||
'min_disk': 0,
|
||||
'min_ram': 0,
|
||||
'size': 13,
|
||||
'location': "file:///%s/%s" % (self.test_dir, UUID1),
|
||||
'locations': ["file:///%s/%s" % (self.test_dir, UUID1)],
|
||||
'properties': {'type': 'kernel'}},
|
||||
{'id': UUID2,
|
||||
'name': 'fake image #2',
|
||||
|
@ -141,7 +141,7 @@ class TestRegistryAPI(base.IsolatedUnitTest):
|
|||
'min_disk': 5,
|
||||
'min_ram': 256,
|
||||
'size': 19,
|
||||
'location': "file:///%s/%s" % (self.test_dir, UUID2),
|
||||
'locations': ["file:///%s/%s" % (self.test_dir, UUID2)],
|
||||
'properties': {}}]
|
||||
self.context = glance.context.RequestContext(is_admin=True)
|
||||
db_api.configure_db()
|
||||
|
@ -1943,7 +1943,7 @@ class TestGlanceAPI(base.IsolatedUnitTest):
|
|||
'deleted': False,
|
||||
'checksum': None,
|
||||
'size': 13,
|
||||
'location': "file:///%s/%s" % (self.test_dir, UUID1),
|
||||
'locations': ["file:///%s/%s" % (self.test_dir, UUID1)],
|
||||
'properties': {'type': 'kernel'}},
|
||||
{'id': UUID2,
|
||||
'name': 'fake image #2',
|
||||
|
@ -1957,7 +1957,7 @@ class TestGlanceAPI(base.IsolatedUnitTest):
|
|||
'deleted': False,
|
||||
'checksum': None,
|
||||
'size': 19,
|
||||
'location': "file:///%s/%s" % (self.test_dir, UUID2),
|
||||
'locations': ["file:///%s/%s" % (self.test_dir, UUID2)],
|
||||
'properties': {}}]
|
||||
self.context = glance.context.RequestContext(is_admin=True)
|
||||
db_api.configure_db()
|
||||
|
|
|
@ -35,12 +35,12 @@ class Raise(object):
|
|||
|
||||
class FakeImage(object):
|
||||
def __init__(self, image_id=None, data=None, checksum=None, size=0,
|
||||
location=None):
|
||||
locations=None):
|
||||
self.image_id = image_id
|
||||
self.data = data
|
||||
self.checksum = checksum
|
||||
self.size = size
|
||||
self.location = location
|
||||
self.locations = locations
|
||||
|
||||
def get_data(self):
|
||||
return self.data
|
||||
|
@ -84,7 +84,7 @@ class TestImagesController(base.StoreClearingUnitTest):
|
|||
|
||||
def test_download(self):
|
||||
request = unit_test_utils.get_fake_request()
|
||||
image = FakeImage('abcd', location='http://example.com/image')
|
||||
image = FakeImage('abcd', locations=['http://example.com/image'])
|
||||
self.image_repo.result = image
|
||||
image = self.controller.download(request, unit_test_utils.UUID1)
|
||||
self.assertEqual(image.image_id, 'abcd')
|
||||
|
|
|
@ -56,7 +56,7 @@ def _db_fixture(id, **kwargs):
|
|||
'status': 'queued',
|
||||
'tags': [],
|
||||
'size': None,
|
||||
'location': None,
|
||||
'locations': [],
|
||||
'protected': False,
|
||||
'disk_format': None,
|
||||
'container_format': None,
|
||||
|
@ -106,7 +106,8 @@ class TestImageMembersController(test_utils.BaseTestCase):
|
|||
self.db.reset()
|
||||
self.images = [
|
||||
_db_fixture(UUID1, owner=TENANT1, name='1', size=256,
|
||||
is_public=True, location='%s/%s' % (BASE_URI, UUID1)),
|
||||
is_public=True,
|
||||
locations=['%s/%s' % (BASE_URI, UUID1)]),
|
||||
_db_fixture(UUID2, owner=TENANT1, name='2', size=512),
|
||||
_db_fixture(UUID3, owner=TENANT3, name='3', size=512),
|
||||
_db_fixture(UUID4, owner=TENANT4, name='4', size=1024),
|
||||
|
|
|
@ -59,7 +59,7 @@ def _db_fixture(id, **kwargs):
|
|||
'status': 'queued',
|
||||
'tags': [],
|
||||
'size': None,
|
||||
'location': None,
|
||||
'locations': [],
|
||||
'protected': False,
|
||||
'disk_format': None,
|
||||
'container_format': None,
|
||||
|
@ -80,7 +80,7 @@ def _domain_fixture(id, **kwargs):
|
|||
'owner': None,
|
||||
'status': 'queued',
|
||||
'size': None,
|
||||
'location': None,
|
||||
'locations': [],
|
||||
'protected': False,
|
||||
'disk_format': None,
|
||||
'container_format': None,
|
||||
|
@ -121,7 +121,8 @@ class TestImagesController(test_utils.BaseTestCase):
|
|||
self.db.reset()
|
||||
self.images = [
|
||||
_db_fixture(UUID1, owner=TENANT1, name='1', size=256,
|
||||
is_public=True, location='%s/%s' % (BASE_URI, UUID1)),
|
||||
is_public=True,
|
||||
locations=['%s/%s' % (BASE_URI, UUID1)]),
|
||||
_db_fixture(UUID2, owner=TENANT1, name='2',
|
||||
size=512, is_public=True),
|
||||
_db_fixture(UUID3, owner=TENANT3, name='3',
|
||||
|
@ -1046,7 +1047,7 @@ class TestImagesDeserializer(test_utils.BaseTestCase):
|
|||
samples = {
|
||||
'owner': TENANT1,
|
||||
'is_public': True,
|
||||
'location': '/a/b/c/d',
|
||||
'locations': ['/a/b/c/d'],
|
||||
'deleted': False,
|
||||
'deleted_at': ISOTIME,
|
||||
}
|
||||
|
@ -1876,7 +1877,7 @@ class TestImagesSerializerDirectUrl(test_utils.BaseTestCase):
|
|||
self.active_image = _domain_fixture(
|
||||
UUID1, name='image-1', visibility='public',
|
||||
status='active', size=1024, created_at=DATETIME,
|
||||
updated_at=DATETIME, location='http://some/fake/location')
|
||||
updated_at=DATETIME, locations=['http://some/fake/location'])
|
||||
|
||||
self.queued_image = _domain_fixture(
|
||||
UUID2, name='image-2', status='active',
|
||||
|
|
Loading…
Reference in New Issue