Merge "Add History panel"
This commit is contained in:
commit
651158dfea
@ -112,6 +112,20 @@ class Stack(base.APIResourceWrapper):
|
||||
if stack.id == stack_id:
|
||||
return stack
|
||||
|
||||
@classmethod
|
||||
@handle_errors(_("Unable to retrieve stack"))
|
||||
def get_by_plan(cls, request, plan):
|
||||
"""Return the Heat Stack associated with an OvercloudPlan
|
||||
|
||||
:return: Heat Stack associated with the plan; or None
|
||||
if no Stack is associated, or no Stack can be
|
||||
found
|
||||
:rtype: tuskar_ui.api.heat.Stack or None
|
||||
"""
|
||||
for stack in Stack.list(request):
|
||||
if stack.plan and (stack.plan.id == plan.id):
|
||||
return stack
|
||||
|
||||
@memoized.memoized
|
||||
def resources(self, with_joins=True):
|
||||
"""Return a list of all Resources associated with the Stack
|
||||
|
@ -24,6 +24,7 @@ class BasePanels(horizon.PanelGroup):
|
||||
'plans',
|
||||
'nodes',
|
||||
'flavors',
|
||||
'history',
|
||||
)
|
||||
|
||||
|
||||
|
0
tuskar_ui/infrastructure/history/__init__.py
Normal file
0
tuskar_ui/infrastructure/history/__init__.py
Normal file
27
tuskar_ui/infrastructure/history/panel.py
Normal file
27
tuskar_ui/infrastructure/history/panel.py
Normal file
@ -0,0 +1,27 @@
|
||||
# -*- coding: utf8 -*-
|
||||
#
|
||||
# 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.utils.translation import ugettext_lazy as _
|
||||
|
||||
import horizon
|
||||
|
||||
from tuskar_ui.infrastructure import dashboard
|
||||
|
||||
|
||||
class History(horizon.Panel):
|
||||
name = _("History")
|
||||
slug = "history"
|
||||
|
||||
|
||||
dashboard.Infrastructure.register(History)
|
37
tuskar_ui/infrastructure/history/tables.py
Normal file
37
tuskar_ui/infrastructure/history/tables.py
Normal file
@ -0,0 +1,37 @@
|
||||
# -*- coding: utf8 -*-
|
||||
#
|
||||
# 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.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import tables
|
||||
|
||||
|
||||
class HistoryTable(tables.DataTable):
|
||||
|
||||
timestamp = tables.Column('event_time',
|
||||
verbose_name=_("Timestamp"),
|
||||
attrs={'data-type': 'timestamp'})
|
||||
resource_name = tables.Column('resource_name',
|
||||
verbose_name=_("Resource Name"))
|
||||
resource_status = tables.Column('resource_status',
|
||||
verbose_name=_("Status"))
|
||||
resource_status_reason = tables.Column('resource_status_reason',
|
||||
verbose_name=_("Reason"))
|
||||
|
||||
class Meta:
|
||||
name = "log"
|
||||
verbose_name = _("Log")
|
||||
multi_select = False
|
||||
table_actions = ()
|
||||
row_actions = ()
|
@ -0,0 +1,17 @@
|
||||
{% extends 'infrastructure/base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans 'History' %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include 'horizon/common/_page_header.html' with title=_('History') %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<h4>{% trans "History" %}</h4>
|
||||
{{ table.render }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
39
tuskar_ui/infrastructure/history/tests.py
Normal file
39
tuskar_ui/infrastructure/history/tests.py
Normal file
@ -0,0 +1,39 @@
|
||||
# -*- coding: utf8 -*-
|
||||
#
|
||||
# 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.core import urlresolvers
|
||||
|
||||
from mock import patch, call # noqa
|
||||
|
||||
from openstack_dashboard.test.test_data import utils
|
||||
from tuskar_ui.test import helpers as test
|
||||
from tuskar_ui.test.test_data import heat_data
|
||||
|
||||
|
||||
TEST_DATA = utils.TestDataContainer()
|
||||
heat_data.data(TEST_DATA)
|
||||
INDEX_URL = urlresolvers.reverse(
|
||||
'horizon:infrastructure:history:index')
|
||||
|
||||
|
||||
class HistoryTest(test.BaseAdminViewTests):
|
||||
|
||||
def test_index(self):
|
||||
events = TEST_DATA.heatclient_events.list()
|
||||
|
||||
with patch('tuskar_ui.api.heat.Stack.events',
|
||||
return_value=events):
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
||||
self.assertTemplateUsed(res, 'infrastructure/history/index.html')
|
23
tuskar_ui/infrastructure/history/urls.py
Normal file
23
tuskar_ui/infrastructure/history/urls.py
Normal file
@ -0,0 +1,23 @@
|
||||
# -*- coding: utf8 -*-
|
||||
#
|
||||
# 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.conf import urls
|
||||
|
||||
from tuskar_ui.infrastructure.history import views
|
||||
|
||||
|
||||
urlpatterns = urls.patterns(
|
||||
'',
|
||||
urls.url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
)
|
30
tuskar_ui/infrastructure/history/views.py
Normal file
30
tuskar_ui/infrastructure/history/views.py
Normal file
@ -0,0 +1,30 @@
|
||||
# -*- coding: utf8 -*-
|
||||
#
|
||||
# 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 horizon import tables as horizon_tables
|
||||
|
||||
from tuskar_ui import api
|
||||
from tuskar_ui.infrastructure.history import tables
|
||||
|
||||
|
||||
class IndexView(horizon_tables.DataTableView):
|
||||
table_class = tables.HistoryTable
|
||||
template_name = "infrastructure/history/index.html"
|
||||
|
||||
def get_data(self):
|
||||
plan = api.tuskar.OvercloudPlan.get_the_plan(self.request)
|
||||
if plan:
|
||||
stack = api.heat.Stack.get_by_plan(self.request, plan)
|
||||
if stack:
|
||||
return stack.events
|
@ -44,23 +44,3 @@ class ConfigurationTable(tables.DataTable):
|
||||
|
||||
def get_object_id(self, datum):
|
||||
return datum[0]
|
||||
|
||||
|
||||
class LogTable(tables.DataTable):
|
||||
|
||||
timestamp = tables.Column('event_time',
|
||||
verbose_name=_("Timestamp"),
|
||||
attrs={'data-type': 'timestamp'})
|
||||
resource_name = tables.Column('resource_name',
|
||||
verbose_name=_("Resource Name"))
|
||||
resource_status = tables.Column('resource_status',
|
||||
verbose_name=_("Status"))
|
||||
resource_status_reason = tables.Column('resource_status_reason',
|
||||
verbose_name=_("Reason"))
|
||||
|
||||
class Meta:
|
||||
name = "log"
|
||||
verbose_name = _("Log")
|
||||
multi_select = False
|
||||
table_actions = ()
|
||||
row_actions = ()
|
||||
|
@ -149,25 +149,13 @@ class ConfigurationTab(tabs.TableTab):
|
||||
stack.parameters.items()]
|
||||
|
||||
|
||||
class LogTab(tabs.TableTab):
|
||||
table_classes = (tables.LogTable,)
|
||||
name = _("Log")
|
||||
slug = "log"
|
||||
template_name = "horizon/common/_detail_table.html"
|
||||
preload = False
|
||||
|
||||
def get_log_data(self):
|
||||
stack = self.tab_group.kwargs['stack']
|
||||
return stack.events
|
||||
|
||||
|
||||
class UndeployInProgressTabs(tabs.TabGroup):
|
||||
slug = "undeploy_in_progress"
|
||||
tabs = (UndeployInProgressTab, LogTab)
|
||||
tabs = (UndeployInProgressTab,)
|
||||
sticky = True
|
||||
|
||||
|
||||
class DetailTabs(tabs.TabGroup):
|
||||
slug = "detail"
|
||||
tabs = (OverviewTab, ConfigurationTab, LogTab)
|
||||
tabs = (OverviewTab, ConfigurationTab,)
|
||||
sticky = True
|
||||
|
@ -33,11 +33,8 @@ DETAIL_URL = urlresolvers.reverse(
|
||||
UNDEPLOY_IN_PROGRESS_URL = urlresolvers.reverse(
|
||||
'horizon:infrastructure:overcloud:undeploy_in_progress',
|
||||
args=('overcloud',))
|
||||
UNDEPLOY_IN_PROGRESS_URL_LOG_TAB = (
|
||||
UNDEPLOY_IN_PROGRESS_URL + "?tab=undeploy_in_progress__log")
|
||||
DETAIL_URL_CONFIGURATION_TAB = (DETAIL_URL +
|
||||
"?tab=detail__configuration")
|
||||
DETAIL_URL_LOG_TAB = (DETAIL_URL + "?tab=detail__log")
|
||||
DELETE_URL = urlresolvers.reverse(
|
||||
'horizon:infrastructure:overcloud:undeploy_confirmation',
|
||||
args=('stack-id-1',))
|
||||
@ -145,21 +142,6 @@ class OvercloudTests(test.BaseAdminViewTests):
|
||||
self.assertTemplateUsed(
|
||||
res, 'horizon/common/_detail_table.html')
|
||||
|
||||
def test_detail_get_log_tab(self):
|
||||
with contextlib.nested(
|
||||
_mock_plan(),
|
||||
patch('tuskar_ui.api.heat.Stack.events',
|
||||
return_value=[]),
|
||||
):
|
||||
res = self.client.get(DETAIL_URL_LOG_TAB)
|
||||
|
||||
self.assertTemplateUsed(
|
||||
res, 'infrastructure/overcloud/detail.html')
|
||||
self.assertTemplateNotUsed(
|
||||
res, 'infrastructure/overcloud/_detail_overview.html')
|
||||
self.assertTemplateUsed(
|
||||
res, 'horizon/common/_detail_table.html')
|
||||
|
||||
def test_delete_get(self):
|
||||
res = self.client.get(DELETE_URL)
|
||||
self.assertTemplateUsed(
|
||||
@ -201,22 +183,3 @@ class OvercloudTests(test.BaseAdminViewTests):
|
||||
res = self.client.get(UNDEPLOY_IN_PROGRESS_URL)
|
||||
|
||||
self.assertRedirectsNoFollow(res, DETAIL_URL)
|
||||
|
||||
def test_undeploy_in_progress_log_tab(self):
|
||||
with contextlib.nested(
|
||||
_mock_plan(),
|
||||
patch('tuskar_ui.api.heat.Stack.is_deleting',
|
||||
return_value=True),
|
||||
patch('tuskar_ui.api.heat.Stack.is_deployed',
|
||||
return_value=False),
|
||||
patch('tuskar_ui.api.heat.Stack.events',
|
||||
return_value=[]),
|
||||
):
|
||||
res = self.client.get(UNDEPLOY_IN_PROGRESS_URL_LOG_TAB)
|
||||
|
||||
self.assertTemplateUsed(
|
||||
res, 'infrastructure/overcloud/detail.html')
|
||||
self.assertTemplateNotUsed(
|
||||
res, 'infrastructure/overcloud/_undeploy_in_progress.html')
|
||||
self.assertTemplateUsed(
|
||||
res, 'horizon/common/_detail_table.html')
|
||||
|
Loading…
x
Reference in New Issue
Block a user