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):
|
def image_list_detailed(request, marker=None, filters=None):
|
||||||
filters = filters or {}
|
|
||||||
limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
|
limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
|
||||||
images = glanceclient(request).images.list(limit=limit + 1,
|
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 20)
|
||||||
marker=marker,
|
kwargs = {'filters': filters or {}}
|
||||||
filters=filters)
|
if marker:
|
||||||
if(len(images) > limit):
|
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)
|
return (images[0:-1], True)
|
||||||
else:
|
else:
|
||||||
return (images, False)
|
return (images, False)
|
||||||
@ -89,11 +93,4 @@ def image_create(request, **kwargs):
|
|||||||
def snapshot_list_detailed(request, marker=None, extra_filters=None):
|
def snapshot_list_detailed(request, marker=None, extra_filters=None):
|
||||||
filters = {'property-image_type': 'snapshot'}
|
filters = {'property-image_type': 'snapshot'}
|
||||||
filters.update(extra_filters or {})
|
filters.update(extra_filters or {})
|
||||||
limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
|
return image_list_detailed(request, marker, filters)
|
||||||
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)
|
|
||||||
|
@ -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()
|
images = self.images.list()
|
||||||
filters = {'property-image_type': 'snapshot'}
|
filters = {'property-image_type': 'snapshot'}
|
||||||
limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
|
limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
|
||||||
|
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 20)
|
||||||
|
|
||||||
glanceclient = self.stub_glanceclient()
|
glanceclient = self.stub_glanceclient()
|
||||||
glanceclient.images = self.mox.CreateMockAnything()
|
glanceclient.images = self.mox.CreateMockAnything()
|
||||||
glanceclient.images.list(filters=filters,
|
glanceclient.images.list(page_size=page_size,
|
||||||
limit=limit + 1,
|
limit=limit,
|
||||||
marker=None).AndReturn(images)
|
filters=filters,).AndReturn(images)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
# No assertions are necessary. Verification is handled by mox.
|
# No assertions are necessary. Verification is handled by mox.
|
||||||
api.glance.snapshot_list_detailed(self.request)
|
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)
|
TEST.snapshots.add(snapshot)
|
||||||
|
|
||||||
# Images
|
# Images
|
||||||
image_dict = {'id': '1',
|
image_dict = {'id': '007e7d55-fe1e-4c5c-bf08-44b4a4964822',
|
||||||
'name': 'public_image',
|
'name': 'public_image',
|
||||||
'status': "active",
|
'status': "active",
|
||||||
'owner': TEST.tenant.id,
|
'owner': TEST.tenant.id,
|
||||||
@ -56,11 +56,34 @@ def data(TEST):
|
|||||||
'properties': {'image_type': u'image'}}
|
'properties': {'image_type': u'image'}}
|
||||||
public_image = Image(ImageManager(None), image_dict)
|
public_image = Image(ImageManager(None), image_dict)
|
||||||
|
|
||||||
image_dict = {'id': '2',
|
image_dict = {'id': 'a001c047-22f8-47d0-80a1-8ec94a9524fe',
|
||||||
'name': 'private_image',
|
'name': 'private_image',
|
||||||
'status': "active",
|
'status': "active",
|
||||||
'owner': TEST.tenant.id,
|
'owner': TEST.tenant.id,
|
||||||
'container_format': 'aki'}
|
'container_format': 'aki'}
|
||||||
private_image = Image(ImageManager(None), image_dict)
|
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'.
|
# external to the OpenStack environment. The default is 'internalURL'.
|
||||||
#OPENSTACK_ENDPOINT_TYPE = "publicURL"
|
#OPENSTACK_ENDPOINT_TYPE = "publicURL"
|
||||||
|
|
||||||
# The number of Swift containers and objects to display on a single page before
|
# The number of objects (Swift containers/objects or images) to display
|
||||||
# providing a paging element (a "more" link) to paginate results.
|
# on a single page before providing a paging element (a "more" link)
|
||||||
|
# to paginate results.
|
||||||
API_RESULT_LIMIT = 1000
|
API_RESULT_LIMIT = 1000
|
||||||
|
API_RESULT_PAGE_SIZE = 20
|
||||||
|
|
||||||
# The timezone of the server. This should correspond with the timezone
|
# The timezone of the server. This should correspond with the timezone
|
||||||
# of your entire OpenStack installation, and hopefully be in UTC.
|
# of your entire OpenStack installation, and hopefully be in UTC.
|
||||||
|
Loading…
Reference in New Issue
Block a user