Merge "Add pagination to stack list"
This commit is contained in:
commit
c0fb123953
@ -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):
|
||||||
|
@ -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,)
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
@ -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))
|
||||||
|
Loading…
Reference in New Issue
Block a user