Fixed the bug with images returned as generator
After a fix in Glance to support pagination, the list of images is returned as generator, while api.glance expects a list. PATCHSET 2: removed optional kwargs if None PATCHSET 3: fixed snapshot_list_detailed. Fixed bug 1027210 Change-Id: I1c68e3625c22e591776e83c742e7b94dc893f196
This commit is contained in:
parent
da7f44cdc2
commit
dec4876e24
@ -55,12 +55,16 @@ def image_get(request, image_id):
|
||||
|
||||
|
||||
def image_list_detailed(request, marker=None, filters=None):
|
||||
filters = filters or {}
|
||||
limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
|
||||
images = glanceclient(request).images.list(limit=limit + 1,
|
||||
marker=marker,
|
||||
filters=filters)
|
||||
if(len(images) > limit):
|
||||
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 20)
|
||||
kwargs = {'filters': filters or {}}
|
||||
if marker:
|
||||
kwargs['marker'] = marker
|
||||
images = list(glanceclient(request).images.list(page_size=page_size,
|
||||
limit=limit,
|
||||
**kwargs))
|
||||
# Glance returns (page_size + 1) items if more items are available
|
||||
if(len(images) > page_size):
|
||||
return (images[0:-1], True)
|
||||
else:
|
||||
return (images, False)
|
||||
@ -89,11 +93,4 @@ def image_create(request, **kwargs):
|
||||
def snapshot_list_detailed(request, marker=None, extra_filters=None):
|
||||
filters = {'property-image_type': 'snapshot'}
|
||||
filters.update(extra_filters or {})
|
||||
limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
|
||||
images = glanceclient(request).images.list(limit=limit + 1,
|
||||
marker=marker,
|
||||
filters=filters)
|
||||
if len(images) > limit:
|
||||
return (images[0:-1], True)
|
||||
else:
|
||||
return (images, False)
|
||||
return image_list_detailed(request, marker, filters)
|
||||
|
@ -0,0 +1,97 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 Nebula, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django import http
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from mox import IsA
|
||||
|
||||
from horizon import api
|
||||
from horizon import test
|
||||
from .tables import AdminImagesTable
|
||||
|
||||
|
||||
class ImagesViewTest(test.BaseAdminViewTests):
|
||||
@test.create_stubs({api: ('image_list_detailed',)})
|
||||
def test_images_list(self):
|
||||
api.image_list_detailed(IsA(http.HttpRequest),
|
||||
marker=None) \
|
||||
.AndReturn([self.images.list(),
|
||||
False])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(
|
||||
reverse('horizon:syspanel:images:index'))
|
||||
self.assertTemplateUsed(res, 'syspanel/images/index.html')
|
||||
self.assertEqual(len(res.context['images_table'].data),
|
||||
len(self.images.list()))
|
||||
|
||||
@test.create_stubs({api: ('image_list_detailed',)})
|
||||
def test_images_list_get_pagination(self):
|
||||
api.image_list_detailed(IsA(http.HttpRequest),
|
||||
marker=None) \
|
||||
.AndReturn([self.images.list(),
|
||||
True])
|
||||
api.image_list_detailed(IsA(http.HttpRequest),
|
||||
marker=None) \
|
||||
.AndReturn([self.images.list()[:2],
|
||||
True])
|
||||
api.image_list_detailed(IsA(http.HttpRequest),
|
||||
marker=self.images.list()[2].id) \
|
||||
.AndReturn([self.images.list()[2:4],
|
||||
True])
|
||||
api.image_list_detailed(IsA(http.HttpRequest),
|
||||
marker=self.images.list()[4].id) \
|
||||
.AndReturn([self.images.list()[4:],
|
||||
True])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:syspanel:images:index')
|
||||
res = self.client.get(url)
|
||||
# get all
|
||||
self.assertEqual(len(res.context['images_table'].data),
|
||||
len(self.images.list()))
|
||||
self.assertTemplateUsed(res, 'syspanel/images/index.html')
|
||||
|
||||
page_size = getattr(settings, "API_RESULT_PAGE_SIZE", None)
|
||||
settings.API_RESULT_PAGE_SIZE = 2
|
||||
|
||||
res = self.client.get(url)
|
||||
# get first page with 2 items
|
||||
self.assertEqual(len(res.context['images_table'].data),
|
||||
settings.API_RESULT_PAGE_SIZE)
|
||||
|
||||
url = "?".join([reverse('horizon:syspanel:images:index'),
|
||||
"=".join([AdminImagesTable._meta.pagination_param,
|
||||
self.images.list()[2].id])])
|
||||
res = self.client.get(url)
|
||||
# get second page (items 2-4)
|
||||
self.assertEqual(len(res.context['images_table'].data),
|
||||
settings.API_RESULT_PAGE_SIZE)
|
||||
|
||||
url = "?".join([reverse('horizon:syspanel:images:index'),
|
||||
"=".join([AdminImagesTable._meta.pagination_param,
|
||||
self.images.list()[4].id])])
|
||||
res = self.client.get(url)
|
||||
# get third page (item 5)
|
||||
self.assertEqual(len(res.context['images_table'].data),
|
||||
1)
|
||||
|
||||
# restore API_RESULT_PAGE_SIZE
|
||||
if page_size:
|
||||
settings.API_RESULT_PAGE_SIZE = page_size
|
||||
else:
|
||||
del settings.API_RESULT_PAGE_SIZE
|
@ -29,13 +29,39 @@ class GlanceApiTests(test.APITestCase):
|
||||
images = self.images.list()
|
||||
filters = {'property-image_type': 'snapshot'}
|
||||
limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
|
||||
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 20)
|
||||
|
||||
glanceclient = self.stub_glanceclient()
|
||||
glanceclient.images = self.mox.CreateMockAnything()
|
||||
glanceclient.images.list(filters=filters,
|
||||
limit=limit + 1,
|
||||
marker=None).AndReturn(images)
|
||||
glanceclient.images.list(page_size=page_size,
|
||||
limit=limit,
|
||||
filters=filters,).AndReturn(images)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
# No assertions are necessary. Verification is handled by mox.
|
||||
api.glance.snapshot_list_detailed(self.request)
|
||||
|
||||
def test_snapshot_list_detailed_pagination(self):
|
||||
images = self.images.list()
|
||||
filters = {'property-image_type': 'snapshot'}
|
||||
page_size = 2
|
||||
temp_page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', None)
|
||||
settings.API_RESULT_PAGE_SIZE = page_size
|
||||
limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
|
||||
|
||||
glanceclient = self.stub_glanceclient()
|
||||
glanceclient.images = self.mox.CreateMockAnything()
|
||||
glanceclient.images.list(limit=limit,
|
||||
page_size=page_size,
|
||||
filters=filters,) \
|
||||
.AndReturn(images[0:page_size])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
# No assertions are necessary. Verification is handled by mox.
|
||||
api.glance.snapshot_list_detailed(self.request)
|
||||
|
||||
# Restore
|
||||
if temp_page_size:
|
||||
settings.API_RESULT_PAGE_SIZE = temp_page_size
|
||||
else:
|
||||
del settings.API_RESULT_PAGE_SIZE
|
||||
|
@ -48,7 +48,7 @@ def data(TEST):
|
||||
TEST.snapshots.add(snapshot)
|
||||
|
||||
# Images
|
||||
image_dict = {'id': '1',
|
||||
image_dict = {'id': '007e7d55-fe1e-4c5c-bf08-44b4a4964822',
|
||||
'name': 'public_image',
|
||||
'status': "active",
|
||||
'owner': TEST.tenant.id,
|
||||
@ -56,11 +56,34 @@ def data(TEST):
|
||||
'properties': {'image_type': u'image'}}
|
||||
public_image = Image(ImageManager(None), image_dict)
|
||||
|
||||
image_dict = {'id': '2',
|
||||
image_dict = {'id': 'a001c047-22f8-47d0-80a1-8ec94a9524fe',
|
||||
'name': 'private_image',
|
||||
'status': "active",
|
||||
'owner': TEST.tenant.id,
|
||||
'container_format': 'aki'}
|
||||
private_image = Image(ImageManager(None), image_dict)
|
||||
|
||||
TEST.images.add(public_image, private_image)
|
||||
image_dict = {'id': '278905a6-4b52-4d1e-98f9-8c57bb25ba32',
|
||||
'name': 'public_image 2',
|
||||
'status': "active",
|
||||
'owner': TEST.tenant.id,
|
||||
'container_format': 'novaImage',
|
||||
'properties': {'image_type': u'image'}}
|
||||
public_image2 = Image(ImageManager(None), image_dict)
|
||||
|
||||
image_dict = {'id': '710a1acf-a3e3-41dd-a32d-5d6b6c86ea10',
|
||||
'name': 'private_image 2',
|
||||
'status': "active",
|
||||
'owner': TEST.tenant.id,
|
||||
'container_format': 'aki'}
|
||||
private_image2 = Image(ImageManager(None), image_dict)
|
||||
|
||||
image_dict = {'id': '7cd892fd-5652-40f3-a450-547615680132',
|
||||
'name': 'private_image 3',
|
||||
'status': "active",
|
||||
'owner': TEST.tenant.id,
|
||||
'container_format': 'aki'}
|
||||
private_image3 = Image(ImageManager(None), image_dict)
|
||||
|
||||
TEST.images.add(public_image, private_image,
|
||||
public_image2, private_image2, private_image3)
|
||||
|
@ -76,9 +76,11 @@ OPENSTACK_KEYSTONE_BACKEND = {
|
||||
# external to the OpenStack environment. The default is 'internalURL'.
|
||||
#OPENSTACK_ENDPOINT_TYPE = "publicURL"
|
||||
|
||||
# The number of Swift containers and objects to display on a single page before
|
||||
# providing a paging element (a "more" link) to paginate results.
|
||||
# The number of objects (Swift containers/objects or images) to display
|
||||
# on a single page before providing a paging element (a "more" link)
|
||||
# to paginate results.
|
||||
API_RESULT_LIMIT = 1000
|
||||
API_RESULT_PAGE_SIZE = 20
|
||||
|
||||
# The timezone of the server. This should correspond with the timezone
|
||||
# of your entire OpenStack installation, and hopefully be in UTC.
|
||||
|
Loading…
Reference in New Issue
Block a user