Merge "Add pagination to stack list"

This commit is contained in:
Jenkins 2014-04-08 09:59:24 +00:00 committed by Gerrit Code Review
commit c0fb123953
6 changed files with 129 additions and 47 deletions

View File

@ -16,6 +16,7 @@ import logging
from django.conf import settings from django.conf import settings
from heatclient import client as heat_client from heatclient import client as heat_client
from horizon.utils import functions as utils
from openstack_dashboard.api import base from openstack_dashboard.api import base
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -52,8 +53,29 @@ def heatclient(request, password=None):
return client return client
def stacks_list(request): def stacks_list(request, marker=None, paginate=False):
return [stack for stack in heatclient(request).stacks.list()] limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
page_size = utils.get_page_size(request)
if paginate:
request_size = page_size + 1
else:
request_size = limit
kwargs = {}
if marker:
kwargs['marker'] = marker
stacks_iter = heatclient(request).stacks.list(limit=request_size,
**kwargs)
has_more_data = False
stacks = list(stacks_iter)
if paginate:
if len(stacks) > page_size:
stacks.pop()
has_more_data = True
return (stacks, has_more_data)
def stack_delete(request, stack_id): def stack_delete(request, stack_id):

View File

@ -109,6 +109,7 @@ class StacksTable(tables.DataTable):
class Meta: class Meta:
name = "stacks" name = "stacks"
verbose_name = _("Stacks") verbose_name = _("Stacks")
pagination_param = 'stack_marker'
status_columns = ["status", ] status_columns = ["status", ]
row_class = StacksUpdateRow row_class = StacksUpdateRow
table_actions = (LaunchStack, DeleteStack,) table_actions = (LaunchStack, DeleteStack,)

View File

@ -14,9 +14,11 @@
import json import json
from django.conf import settings
from django.core import exceptions from django.core import exceptions
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django import http from django import http
from django.test.utils import override_settings # noqa
from mox import IsA # noqa from mox import IsA # noqa
@ -25,6 +27,7 @@ from openstack_dashboard.test import helpers as test
from openstack_dashboard.dashboards.project.stacks import forms from openstack_dashboard.dashboards.project.stacks import forms
from openstack_dashboard.dashboards.project.stacks import mappings from openstack_dashboard.dashboards.project.stacks import mappings
from openstack_dashboard.dashboards.project.stacks import tables
INDEX_URL = reverse('horizon:project:stacks:index') INDEX_URL = reverse('horizon:project:stacks:index')
@ -93,20 +96,59 @@ class MappingsTests(test.TestCase):
class StackTests(test.TestCase): class StackTests(test.TestCase):
@override_settings(API_RESULT_PAGE_SIZE=2)
@test.create_stubs({api.heat: ('stacks_list',)}) @test.create_stubs({api.heat: ('stacks_list',)})
def test_index(self): def test_index_paginated(self):
stacks = self.stacks.list() stacks = self.stacks.list()[:5]
# import pdb; pdb.set_trace()
api.heat.stacks_list(IsA(http.HttpRequest)) \ api.heat.stacks_list(IsA(http.HttpRequest),
.AndReturn(stacks) marker=None,
paginate=True) \
.AndReturn([stacks,
True])
api.heat.stacks_list(IsA(http.HttpRequest),
marker=None,
paginate=True) \
.AndReturn([stacks[:2],
True])
api.heat.stacks_list(IsA(http.HttpRequest),
marker=stacks[2].id,
paginate=True) \
.AndReturn([stacks[2:4],
True])
api.heat.stacks_list(IsA(http.HttpRequest),
marker=stacks[4].id,
paginate=True) \
.AndReturn([stacks[4:],
True])
self.mox.ReplayAll() self.mox.ReplayAll()
res = self.client.get(INDEX_URL) url = reverse('horizon:project:stacks:index')
res = self.client.get(url)
# get all
self.assertEqual(len(res.context['stacks_table'].data),
len(stacks))
self.assertTemplateUsed(res, 'project/stacks/index.html') self.assertTemplateUsed(res, 'project/stacks/index.html')
self.assertIn('table', res.context)
resp_stacks = res.context['table'].data res = self.client.get(url)
self.assertEqual(len(resp_stacks), len(stacks)) # get first page with 2 items
self.assertEqual(len(res.context['stacks_table'].data),
settings.API_RESULT_PAGE_SIZE)
url = "%s?%s=%s" % (reverse('horizon:project:stacks:index'),
tables.StacksTable._meta.pagination_param, stacks[2].id)
res = self.client.get(url)
# get second page (items 2-4)
self.assertEqual(len(res.context['stacks_table'].data),
settings.API_RESULT_PAGE_SIZE)
url = "%s?%s=%s" % (reverse('horizon:project:stacks:index'),
tables.StacksTable._meta.pagination_param, stacks[4].id)
res = self.client.get(url)
# get third page (item 5)
self.assertEqual(len(res.context['stacks_table'].data),
1)
@test.create_stubs({api.heat: ('stack_create', 'template_validate')}) @test.create_stubs({api.heat: ('stack_create', 'template_validate')})
def test_launch_stack(self): def test_launch_stack(self):

View File

@ -46,13 +46,25 @@ class IndexView(tables.DataTableView):
table_class = project_tables.StacksTable table_class = project_tables.StacksTable
template_name = 'project/stacks/index.html' template_name = 'project/stacks/index.html'
def __init__(self, *args, **kwargs):
super(IndexView, self).__init__(*args, **kwargs)
self._more = None
def has_more_data(self, table):
return self._more
def get_data(self): def get_data(self):
request = self.request stacks = []
marker = self.request.GET.get(
project_tables.StacksTable._meta.pagination_param)
try: try:
stacks = api.heat.stacks_list(self.request) stacks, self._more = api.heat.stacks_list(self.request,
marker=marker,
paginate=True)
except Exception: except Exception:
exceptions.handle(request, _('Unable to retrieve stack list.')) self._more = False
stacks = [] msg = _('Unable to retrieve stack list.')
exceptions.handle(self.request, msg)
return stacks return stacks

View File

@ -12,6 +12,9 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from django.conf import settings
from django.test.utils import override_settings # noqa
from openstack_dashboard import api from openstack_dashboard import api
from openstack_dashboard.test import helpers as test from openstack_dashboard.test import helpers as test
@ -19,13 +22,15 @@ from openstack_dashboard.test import helpers as test
class HeatApiTests(test.APITestCase): class HeatApiTests(test.APITestCase):
def test_stack_list(self): def test_stack_list(self):
api_stacks = self.stacks.list() api_stacks = self.stacks.list()
limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
heatclient = self.stub_heatclient() heatclient = self.stub_heatclient()
heatclient.stacks = self.mox.CreateMockAnything() heatclient.stacks = self.mox.CreateMockAnything()
heatclient.stacks.list().AndReturn(iter(api_stacks)) heatclient.stacks.list(limit=limit).AndReturn(iter(api_stacks))
self.mox.ReplayAll() self.mox.ReplayAll()
stacks = api.heat.stacks_list(self.request) stacks, has_more = api.heat.stacks_list(self.request)
self.assertItemsEqual(stacks, api_stacks) self.assertItemsEqual(stacks, api_stacks)
self.assertFalse(has_more)
def test_template_get(self): def test_template_get(self):
api_stacks = self.stacks.list() api_stacks = self.stacks.list()

View File

@ -329,36 +329,36 @@ def data(TEST):
TEST.stack_templates = utils.TestDataContainer() TEST.stack_templates = utils.TestDataContainer()
TEST.stack_environments = utils.TestDataContainer() TEST.stack_environments = utils.TestDataContainer()
# Stacks for i in range(10):
stack1 = { stack_data = {
"description": "No description", "description": "No description",
"links": [{ "links": [{
"href": "http://192.168.1.70:8004/v1/" "href": "http://192.168.1.70:8004/v1/"
"051c727ee67040d6a7b7812708485a97/" "051c727ee67040d6a7b7812708485a97/"
"stacks/stack-1211-38/" "stacks/stack-1211-38/"
"05b4f39f-ea96-4d91-910c-e758c078a089", "05b4f39f-ea96-4d91-910c-e758c078a089",
"rel": "self" "rel": "self"
}], }],
"parameters": { "parameters": {
'DBUsername': '******', 'DBUsername': '******',
'InstanceType': 'm1.small', 'InstanceType': 'm1.small',
'AWS::StackId': 'AWS::StackId':
'arn:openstack:heat::2ce287:stacks/teststack/88553ec', 'arn:openstack:heat::2ce287:stacks/teststack/88553ec',
'DBRootPassword': '******', 'DBRootPassword': '******',
'AWS::StackName': 'teststack', 'AWS::StackName': "teststack{0}".format(i),
'DBPassword': '******', 'DBPassword': '******',
'AWS::Region': 'ap-southeast-1', 'AWS::Region': 'ap-southeast-1',
'DBName': u'wordpress' 'DBName': u'wordpress'
}, },
"stack_status_reason": "Stack successfully created", "stack_status_reason": "Stack successfully created",
"stack_name": "stack-test", "stack_name": "stack-test{0}".format(i),
"creation_time": "2013-04-22T00:11:39Z", "creation_time": "2013-04-22T00:11:39Z",
"updated_time": "null", "updated_time": "2013-04-22T00:11:39Z",
"stack_status": "CREATE_COMPLETE", "stack_status": "CREATE_COMPLETE",
"id": "05b4f39f-ea96-4d91-910c-e758c078a089" "id": "05b4f39f-ea96-4d91-910c-e758c078a089{0}".format(i)
} }
stack = stacks.Stack(stacks.StackManager(None), stack1) stack = stacks.Stack(stacks.StackManager(None), stack_data)
TEST.stacks.add(stack) TEST.stacks.add(stack)
TEST.stack_templates.add(Template(TEMPLATE, VALIDATE)) TEST.stack_templates.add(Template(TEMPLATE, VALIDATE))
TEST.stack_environments.add(Environment(ENVIRONMENT)) TEST.stack_environments.add(Environment(ENVIRONMENT))