Restructure navigation and rename base directories
* overview is gone * deployment has been renamed overcloud * controller/compute/storage have been removed, as different tabs will be developed in a future patch * nodes now have tabbed navigation Change-Id: I7db58725dacb3d535be60be2cb31578a636d962d
This commit is contained in:
parent
ae4821b26b
commit
61f6b4e620
@ -17,33 +17,12 @@ from django.utils.translation import ugettext_lazy as _
|
||||
import horizon
|
||||
|
||||
|
||||
class InfrastructureOverview(horizon.PanelGroup):
|
||||
slug = "infrastructure_overview"
|
||||
name = _("Overview")
|
||||
class BasePanels(horizon.PanelGroup):
|
||||
slug = "infrastructure"
|
||||
name = _("Infrastructure")
|
||||
panels = (
|
||||
'overview',
|
||||
)
|
||||
|
||||
|
||||
class Deployment(horizon.PanelGroup):
|
||||
slug = "deployment"
|
||||
name = _("Deployment")
|
||||
panels = (
|
||||
'deployment.overview',
|
||||
'deployment.controller',
|
||||
'deployment.compute',
|
||||
'deployment.object_storage',
|
||||
'deployment.block_storage',
|
||||
)
|
||||
|
||||
|
||||
class Nodes(horizon.PanelGroup):
|
||||
slug = "nodes"
|
||||
name = _("Nodes")
|
||||
panels = (
|
||||
'nodes.overview',
|
||||
'nodes.resource',
|
||||
'nodes.free',
|
||||
'nodes',
|
||||
'overcloud',
|
||||
)
|
||||
|
||||
|
||||
@ -51,11 +30,9 @@ class Infrastructure(horizon.Dashboard):
|
||||
name = _("Infrastructure")
|
||||
slug = "infrastructure"
|
||||
panels = (
|
||||
InfrastructureOverview,
|
||||
Deployment,
|
||||
Nodes,
|
||||
BasePanels,
|
||||
)
|
||||
default_panel = 'overview'
|
||||
default_panel = 'overcloud'
|
||||
permissions = ('openstack.roles.admin',)
|
||||
|
||||
|
||||
|
@ -1,27 +0,0 @@
|
||||
# -*- 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 BlockStorage(horizon.Panel):
|
||||
name = _("Block Storage")
|
||||
slug = "deployment.block_storage"
|
||||
|
||||
|
||||
dashboard.Infrastructure.register(BlockStorage)
|
@ -1,23 +0,0 @@
|
||||
# -*- 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.urls import defaults
|
||||
|
||||
from tuskar_ui.infrastructure.deployment.block_storage import views
|
||||
|
||||
|
||||
urlpatterns = defaults.patterns(
|
||||
'',
|
||||
defaults.url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
)
|
@ -1,18 +0,0 @@
|
||||
# -*- 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.views import generic
|
||||
|
||||
|
||||
class IndexView(generic.TemplateView):
|
||||
template_name = 'infrastructure/base.html'
|
@ -1,27 +0,0 @@
|
||||
# -*- 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 Controller(horizon.Panel):
|
||||
name = _("Controller")
|
||||
slug = "deployment.controller"
|
||||
|
||||
|
||||
dashboard.Infrastructure.register(Controller)
|
@ -1,23 +0,0 @@
|
||||
# -*- 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.urls import defaults
|
||||
|
||||
from tuskar_ui.infrastructure.deployment.controller import views
|
||||
|
||||
|
||||
urlpatterns = defaults.patterns(
|
||||
'',
|
||||
defaults.url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
)
|
@ -1,18 +0,0 @@
|
||||
# -*- 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.views import generic
|
||||
|
||||
|
||||
class IndexView(generic.TemplateView):
|
||||
template_name = 'infrastructure/base.html'
|
@ -1,27 +0,0 @@
|
||||
# -*- 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 ObjectStorage(horizon.Panel):
|
||||
name = _("Object Storage")
|
||||
slug = "deployment.object_storage"
|
||||
|
||||
|
||||
dashboard.Infrastructure.register(ObjectStorage)
|
@ -1,23 +0,0 @@
|
||||
# -*- 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.urls import defaults
|
||||
|
||||
from tuskar_ui.infrastructure.deployment.object_storage import views
|
||||
|
||||
|
||||
urlpatterns = defaults.patterns(
|
||||
'',
|
||||
defaults.url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
)
|
@ -1,18 +0,0 @@
|
||||
# -*- 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.views import generic
|
||||
|
||||
|
||||
class IndexView(generic.TemplateView):
|
||||
template_name = 'infrastructure/base.html'
|
@ -1,27 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# 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 DeploymentOverview(horizon.Panel):
|
||||
name = _("Overview")
|
||||
slug = "deployment.overview"
|
||||
|
||||
|
||||
dashboard.Infrastructure.register(DeploymentOverview)
|
@ -1,23 +0,0 @@
|
||||
# -*- 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.urls import defaults
|
||||
|
||||
from tuskar_ui.infrastructure.deployment.overview import views
|
||||
|
||||
|
||||
urlpatterns = defaults.patterns(
|
||||
'',
|
||||
defaults.url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
)
|
@ -1,18 +0,0 @@
|
||||
# -*- 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.views import generic
|
||||
|
||||
|
||||
class IndexView(generic.TemplateView):
|
||||
template_name = 'infrastructure/base.html'
|
@ -1,26 +0,0 @@
|
||||
# -*- 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 tuskar_ui.infrastructure.nodes import tables
|
||||
|
||||
|
||||
class FreeNodesTable(tables.NodesTable):
|
||||
|
||||
class Meta:
|
||||
name = "free_nodes"
|
||||
verbose_name = _("Free Nodes")
|
||||
table_actions = ()
|
||||
row_actions = ()
|
@ -1,12 +0,0 @@
|
||||
{% extends 'infrastructure/base_nodes_table.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Free Nodes" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Free Nodes") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block name %}
|
||||
{% trans "Free Nodes" %}
|
||||
{% endblock %}
|
@ -1,58 +0,0 @@
|
||||
# -*- 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 # noqa
|
||||
|
||||
from tuskar_ui import api
|
||||
from tuskar_ui.test import helpers as test
|
||||
|
||||
|
||||
INDEX_URL = urlresolvers.reverse('horizon:infrastructure:nodes.free'
|
||||
':index')
|
||||
NODES_OVERVIEW_URL = urlresolvers.reverse('horizon:infrastructure:'
|
||||
'nodes.overview:index')
|
||||
|
||||
|
||||
class FreeNodesTests(test.BaseAdminViewTests):
|
||||
def setUp(self):
|
||||
super(FreeNodesTests, self).setUp()
|
||||
|
||||
def test_index(self):
|
||||
free_nodes = [api.Node(node)
|
||||
for node in self.ironicclient_nodes.list()]
|
||||
|
||||
with patch('tuskar_ui.api.Node', **{
|
||||
'spec_set': ['list'], # Only allow these attributes
|
||||
'list.return_value': free_nodes,
|
||||
}) as mock:
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertEqual(mock.list.call_count, 1)
|
||||
|
||||
self.maxDiff = None
|
||||
self.assertTemplateUsed(res,
|
||||
'infrastructure/nodes.free/index.html')
|
||||
self.assertItemsEqual(res.context['free_nodes_table'].data,
|
||||
free_nodes)
|
||||
|
||||
def test_index_nodes_list_exception(self):
|
||||
with patch('tuskar_ui.api.Node', **{
|
||||
'spec_set': ['list'],
|
||||
'list.side_effect': self.exceptions.tuskar,
|
||||
}) as mock:
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertEqual(mock.list.call_count, 1)
|
||||
|
||||
self.assertRedirectsNoFollow(res, NODES_OVERVIEW_URL)
|
@ -1,23 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# 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.urls import defaults
|
||||
|
||||
from tuskar_ui.infrastructure.nodes.free import views
|
||||
|
||||
|
||||
urlpatterns = defaults.patterns(
|
||||
'',
|
||||
defaults.url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
)
|
@ -1,39 +0,0 @@
|
||||
# -*- 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 django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import tables as horizon_tables
|
||||
|
||||
from tuskar_ui import api as tuskar
|
||||
from tuskar_ui.infrastructure.nodes.free import tables
|
||||
|
||||
|
||||
class IndexView(horizon_tables.DataTableView):
|
||||
table_class = tables.FreeNodesTable
|
||||
template_name = 'infrastructure/nodes.free/index.html'
|
||||
|
||||
def get_data(self):
|
||||
try:
|
||||
free_nodes = tuskar.Node.list(self.request, associated=False)
|
||||
except Exception:
|
||||
free_nodes = []
|
||||
redirect = urlresolvers.reverse(
|
||||
'horizon:infrastructure:nodes.overview:index')
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve free nodes.'),
|
||||
redirect=redirect)
|
||||
return free_nodes
|
@ -1,27 +0,0 @@
|
||||
# -*- 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 NodesOverview(horizon.Panel):
|
||||
name = _("Overview")
|
||||
slug = "nodes.overview"
|
||||
|
||||
|
||||
dashboard.Infrastructure.register(NodesOverview)
|
@ -1,36 +0,0 @@
|
||||
{% extends 'infrastructure/base.html' %}
|
||||
{% load i18n %}
|
||||
{% load url from future %}
|
||||
{% block title %}{% trans 'Nodes Overview' %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include 'horizon/common/_domain_page_header.html' with title=_('Nodes Overview') %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="{% url 'horizon:infrastructure:overview:index' %}"
|
||||
>{% trans "Infrastructure" %}</a>
|
||||
<span class="separator"></span>
|
||||
</div>
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row-fluid"><div class="span12">
|
||||
<p>
|
||||
<h4><span class="big-number">{{ nodes_total|default:0 }}</span> nodes in total</h4>
|
||||
</p>
|
||||
<hr>
|
||||
<p>
|
||||
<a href="{% url 'horizon:infrastructure:nodes.resource:index' %}"
|
||||
><span class="big-number">{{ nodes_allocated_resources|default:0 }}</span> Allocated — Resource Nodes</a>
|
||||
</p>
|
||||
<hr>
|
||||
<p>
|
||||
<a href="{% url 'horizon:infrastructure:nodes.overview:register' %}"
|
||||
class="btn ajax-modal pull-right">Register Nodes</a>
|
||||
<a href="{% url 'horizon:infrastructure:nodes.free:index' %}"
|
||||
><span class="big-number">{{ nodes_unallocated|default:0 }}</span> Unallocated Nodes</a>
|
||||
</p>
|
||||
<hr>
|
||||
<h4>Statistics</h4>
|
||||
<p>No statistics available</p>
|
||||
</div></div>
|
||||
{% endblock %}
|
@ -1,63 +0,0 @@
|
||||
# -*- 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.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views import generic
|
||||
from horizon import exceptions
|
||||
import horizon.forms
|
||||
|
||||
from tuskar_ui import api
|
||||
from tuskar_ui.infrastructure.nodes import forms
|
||||
|
||||
|
||||
class IndexView(generic.TemplateView):
|
||||
template_name = 'infrastructure/nodes.overview/index.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(IndexView, self).get_context_data(**kwargs)
|
||||
try:
|
||||
free_nodes = len(api.Node.list(self.request, associated=False))
|
||||
except Exception:
|
||||
free_nodes = 0
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve free nodes.'))
|
||||
try:
|
||||
allocated_nodes = len(api.Node.list(self.request, associated=True))
|
||||
except Exception:
|
||||
allocated_nodes = 0
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve allocated nodes.'))
|
||||
context.update({
|
||||
'nodes_total': free_nodes + allocated_nodes,
|
||||
'nodes_allocated_resources': allocated_nodes,
|
||||
'nodes_unallocated': free_nodes,
|
||||
})
|
||||
return context
|
||||
|
||||
|
||||
class RegisterView(horizon.forms.ModalFormView):
|
||||
form_class = forms.NodeFormset
|
||||
form_prefix = 'register_nodes'
|
||||
template_name = 'infrastructure/nodes.overview/register.html'
|
||||
success_url = reverse_lazy(
|
||||
'horizon:infrastructure:nodes.overview:index')
|
||||
|
||||
def get_data(self):
|
||||
return []
|
||||
|
||||
def get_form(self, form_class):
|
||||
return form_class(self.request.POST or None,
|
||||
initial=self.get_data(),
|
||||
prefix=self.form_prefix)
|
@ -19,9 +19,9 @@ import horizon
|
||||
from tuskar_ui.infrastructure import dashboard
|
||||
|
||||
|
||||
class NodesFree(horizon.Panel):
|
||||
name = _("Free Nodes")
|
||||
slug = "nodes.free"
|
||||
class Nodes(horizon.Panel):
|
||||
name = _("Nodes")
|
||||
slug = "nodes"
|
||||
|
||||
|
||||
dashboard.Infrastructure.register(NodesFree)
|
||||
dashboard.Infrastructure.register(Nodes)
|
@ -1,27 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# 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 NodesResource(horizon.Panel):
|
||||
name = _("Resource Nodes")
|
||||
slug = "nodes.resource"
|
||||
|
||||
|
||||
dashboard.Infrastructure.register(NodesResource)
|
@ -1,26 +0,0 @@
|
||||
# -*- 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 tuskar_ui.infrastructure.nodes import tables
|
||||
|
||||
|
||||
class ResourceNodesTable(tables.NodesTable):
|
||||
|
||||
class Meta:
|
||||
name = "resource_nodes"
|
||||
verbose_name = _("Resource Nodes")
|
||||
table_actions = ()
|
||||
row_actions = ()
|
@ -1,12 +0,0 @@
|
||||
{% extends 'infrastructure/base_nodes_table.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Resource Nodes" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Resource Nodes") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block name %}
|
||||
{% trans "Resource Nodes" %}
|
||||
{% endblock %}
|
@ -1,59 +0,0 @@
|
||||
# -*- 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 # noqa
|
||||
|
||||
from tuskar_ui import api
|
||||
from tuskar_ui.test import helpers as test
|
||||
|
||||
|
||||
INDEX_URL = urlresolvers.reverse('horizon:infrastructure:nodes.resource'
|
||||
':index')
|
||||
NODES_OVERVIEW_URL = urlresolvers.reverse('horizon:infrastructure:'
|
||||
'nodes.overview:index')
|
||||
|
||||
|
||||
class ResourceNodesTests(test.BaseAdminViewTests):
|
||||
def setUp(self):
|
||||
super(ResourceNodesTests, self).setUp()
|
||||
|
||||
def test_index(self):
|
||||
resource_nodes = [api.Node(node)
|
||||
for node in self.ironicclient_nodes.list()]
|
||||
|
||||
with patch('tuskar_ui.api.Node', **{
|
||||
'spec_set': ['list'], # Only allow these attributes
|
||||
'list.return_value': resource_nodes,
|
||||
}) as mock:
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertEqual(mock.list.call_count, 1)
|
||||
|
||||
self.maxDiff = None
|
||||
self.assertTemplateUsed(
|
||||
res, 'infrastructure/nodes.resource/index.html')
|
||||
|
||||
self.assertItemsEqual(res.context['resource_nodes_table'].data,
|
||||
resource_nodes)
|
||||
|
||||
def test_index_nodes_list_exception(self):
|
||||
with patch('tuskar_ui.api.Node', **{
|
||||
'spec_set': ['list'],
|
||||
'list.side_effect': self.exceptions.tuskar,
|
||||
}) as mock:
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertEqual(mock.list.call_count, 1)
|
||||
|
||||
self.assertRedirectsNoFollow(res, NODES_OVERVIEW_URL)
|
@ -1,23 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# 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.urls import defaults
|
||||
|
||||
from tuskar_ui.infrastructure.nodes.resource import views
|
||||
|
||||
|
||||
urlpatterns = defaults.patterns(
|
||||
'',
|
||||
defaults.url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
)
|
@ -1,39 +0,0 @@
|
||||
# -*- 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 django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import tables as horizon_tables
|
||||
|
||||
from tuskar_ui import api as tuskar
|
||||
from tuskar_ui.infrastructure.nodes.resource import tables
|
||||
|
||||
|
||||
class IndexView(horizon_tables.DataTableView):
|
||||
table_class = tables.ResourceNodesTable
|
||||
template_name = 'infrastructure/nodes.resource/index.html'
|
||||
|
||||
def get_data(self):
|
||||
try:
|
||||
resource_nodes = tuskar.Node.list(self.request, associated=True)
|
||||
except Exception:
|
||||
resource_nodes = []
|
||||
redirect = urlresolvers.reverse(
|
||||
'horizon:infrastructure:nodes.overview:index')
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve resource nodes.'),
|
||||
redirect=redirect)
|
||||
return resource_nodes
|
@ -54,3 +54,21 @@ class NodesTable(tables.DataTable):
|
||||
|
||||
def get_object_display(self, datum):
|
||||
return datum.uuid
|
||||
|
||||
|
||||
class FreeNodesTable(NodesTable):
|
||||
|
||||
class Meta:
|
||||
name = "free_nodes"
|
||||
verbose_name = _("Free Nodes")
|
||||
table_actions = ()
|
||||
row_actions = ()
|
||||
|
||||
|
||||
class ResourceNodesTable(NodesTable):
|
||||
|
||||
class Meta:
|
||||
name = "resource_nodes"
|
||||
verbose_name = _("Resource Nodes")
|
||||
table_actions = ()
|
||||
row_actions = ()
|
||||
|
93
tuskar_ui/infrastructure/nodes/tabs.py
Normal file
93
tuskar_ui/infrastructure/nodes/tabs.py
Normal file
@ -0,0 +1,93 @@
|
||||
# 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.core import urlresolvers
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import tabs
|
||||
|
||||
from tuskar_ui import api
|
||||
from tuskar_ui.infrastructure.nodes import tables
|
||||
|
||||
|
||||
class OverviewTab(tabs.Tab):
|
||||
name = _("Overview")
|
||||
slug = "overview"
|
||||
template_name = ("infrastructure/nodes/_overview.html")
|
||||
|
||||
def get_context_data(self, request):
|
||||
try:
|
||||
free_nodes = len(api.Node.list(request, associated=False))
|
||||
except Exception:
|
||||
free_nodes = 0
|
||||
exceptions.handle(request,
|
||||
_('Unable to retrieve free nodes.'))
|
||||
try:
|
||||
resource_nodes = len(api.Node.list(request, associated=True))
|
||||
except Exception:
|
||||
resource_nodes = 0
|
||||
exceptions.handle(request,
|
||||
_('Unable to retrieve resource nodes.'))
|
||||
return {
|
||||
'nodes_total': free_nodes + resource_nodes,
|
||||
'nodes_resources': resource_nodes,
|
||||
'nodes_free': free_nodes,
|
||||
}
|
||||
|
||||
|
||||
class ResourceTab(tabs.TableTab):
|
||||
table_classes = (tables.ResourceNodesTable,)
|
||||
name = _("Resource")
|
||||
slug = "resource"
|
||||
template_name = ("horizon/common/_detail_table.html")
|
||||
|
||||
def get_resource_nodes_data(self):
|
||||
try:
|
||||
resource_nodes = api.Node.list(self.request, associated=True)
|
||||
except Exception:
|
||||
resource_nodes = []
|
||||
redirect = urlresolvers.reverse(
|
||||
'horizon:infrastructure:nodes:index')
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve resource nodes.'),
|
||||
redirect=redirect)
|
||||
return resource_nodes
|
||||
|
||||
|
||||
class FreeTab(tabs.TableTab):
|
||||
table_classes = (tables.FreeNodesTable,)
|
||||
name = _("Free")
|
||||
slug = "free"
|
||||
template_name = ("horizon/common/_detail_table.html")
|
||||
|
||||
def get_free_nodes_data(self):
|
||||
try:
|
||||
free_nodes = api.Node.list(self.request, associated=False)
|
||||
except Exception:
|
||||
free_nodes = []
|
||||
redirect = urlresolvers.reverse(
|
||||
'horizon:infrastructure:nodes:index')
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve free nodes.'),
|
||||
redirect=redirect)
|
||||
return free_nodes
|
||||
|
||||
|
||||
class NodeTabs(tabs.TabGroup):
|
||||
slug = "nodes"
|
||||
tabs = (OverviewTab, ResourceTab, FreeTab)
|
||||
sticky = True
|
@ -3,17 +3,17 @@
|
||||
<div class="form form-inline">
|
||||
<div class="row-fluid">
|
||||
<h3 style="margin-bottom:16px">Node Detail</h3>
|
||||
{% include 'infrastructure/nodes.overview/_nodes_formset_field.html' with field=form.node_tags %}
|
||||
{% include 'infrastructure/nodes/_nodes_formset_field.html' with field=form.node_tags %}
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<h4>Power Management</h4>
|
||||
{% include 'infrastructure/nodes.overview/_nodes_formset_field.html' with field=form.ip_address required=True %}
|
||||
{% include 'infrastructure/nodes.overview/_nodes_formset_field.html' with field=form.ipmi_user %}
|
||||
{% include 'infrastructure/nodes.overview/_nodes_formset_field.html' with field=form.ipmi_password %}
|
||||
{% include 'infrastructure/nodes/_nodes_formset_field.html' with field=form.ip_address required=True %}
|
||||
{% include 'infrastructure/nodes/_nodes_formset_field.html' with field=form.ipmi_user %}
|
||||
{% include 'infrastructure/nodes/_nodes_formset_field.html' with field=form.ipmi_password %}
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<h4>Networking</h4>
|
||||
{% include 'infrastructure/nodes.overview/_nodes_formset_field.html' with field=form.mac_address required=True %}
|
||||
{% include 'infrastructure/nodes/_nodes_formset_field.html' with field=form.mac_address required=True %}
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span4">
|
||||
@ -24,9 +24,9 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="row-fluid" id="register-hardware-fields">
|
||||
{% include 'infrastructure/nodes.overview/_nodes_formset_field.html' with field=form.cpus extra_text=_('units') required=True %}
|
||||
{% include 'infrastructure/nodes.overview/_nodes_formset_field.html' with field=form.memory extra_text=_('MB') required=True %}
|
||||
{% include 'infrastructure/nodes.overview/_nodes_formset_field.html' with field=form.local_disk extra_text=_('GB') required=True %}
|
||||
{% include 'infrastructure/nodes/_nodes_formset_field.html' with field=form.cpus extra_text=_('units') required=True %}
|
||||
{% include 'infrastructure/nodes/_nodes_formset_field.html' with field=form.memory extra_text=_('MB') required=True %}
|
||||
{% include 'infrastructure/nodes/_nodes_formset_field.html' with field=form.local_disk extra_text=_('GB') required=True %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,24 @@
|
||||
{% load i18n %}
|
||||
{% load url from future%}
|
||||
|
||||
|
||||
<div class="row-fluid"><div class="span12">
|
||||
<p>
|
||||
<h4><span class="big-number">{{ nodes_total|default:0 }}</span> {% trans 'nodes in total' %}</h4>
|
||||
</p>
|
||||
<hr>
|
||||
<p>
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__resource"
|
||||
><span class="big-number">{{ nodes_resources|default:0 }}</span> {% trans 'Resource Nodes' %}</a>
|
||||
</p>
|
||||
<hr>
|
||||
<p>
|
||||
<a href="{% url 'horizon:infrastructure:nodes:register' %}"
|
||||
class="btn ajax-modal pull-right">{% trans 'Register Nodes' %}</a>
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}?tab=nodes__free"
|
||||
><span class="big-number">{{ nodes_free|default:0 }}</span> {% trans 'Free Nodes' %}</a>
|
||||
</p>
|
||||
<hr>
|
||||
<h4>{% trans 'Statistics' %}</h4>
|
||||
<p>{% trans 'No statistics available' %}</p>
|
||||
</div></div>
|
@ -3,18 +3,18 @@
|
||||
{% load url from future %}
|
||||
|
||||
{% block form_id %}register_nodes_form{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:infrastructure:nodes.overview:register' %}{% endblock %}
|
||||
{% block form_action %}{% url 'horizon:infrastructure:nodes:register' %}{% endblock %}
|
||||
{% block modal_id %}register_nodes_modal{% endblock %}
|
||||
{% block modal-header %}{% trans "Register Nodes" %}{% endblock %}
|
||||
|
||||
{% block modal-body %}
|
||||
{% include "formset_table/menu_formset.html" with formset=form form_template="infrastructure/nodes.overview/_nodes_formset_form.html" %}
|
||||
{% include "formset_table/menu_formset.html" with formset=form form_template="infrastructure/nodes/_nodes_formset_form.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block modal-footer %}
|
||||
<input class="btn btn-primary pull-right" type="submit"
|
||||
value="{% trans "Register Nodes" %}" />
|
||||
<a href="{% url 'horizon:infrastructure:nodes.overview:index' %}"
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}"
|
||||
class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||
{% endblock %}
|
||||
|
16
tuskar_ui/infrastructure/nodes/templates/nodes/index.html
Normal file
16
tuskar_ui/infrastructure/nodes/templates/nodes/index.html
Normal file
@ -0,0 +1,16 @@
|
||||
{% extends 'infrastructure/base.html' %}
|
||||
{% load i18n %}
|
||||
{% load url from future %}
|
||||
{% block title %}{% trans 'Nodes' %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include 'horizon/common/_domain_page_header.html' with title=_('Nodes') %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
{{ tab_group.render }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -7,5 +7,5 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include "infrastructure/nodes.overview/_register.html" %}
|
||||
{% include "infrastructure/nodes/_register.html" %}
|
||||
{% endblock %}
|
@ -17,28 +17,86 @@ from django.core import urlresolvers
|
||||
from mock import patch, call # noqa
|
||||
|
||||
from openstack_dashboard.test.test_data import utils
|
||||
from tuskar_ui import api as api
|
||||
from tuskar_ui.test import helpers as test
|
||||
from tuskar_ui.test.test_data import tuskar_data
|
||||
|
||||
|
||||
INDEX_URL = urlresolvers.reverse(
|
||||
'horizon:infrastructure:nodes.overview:index')
|
||||
'horizon:infrastructure:nodes:index')
|
||||
REGISTER_URL = urlresolvers.reverse(
|
||||
'horizon:infrastructure:nodes.overview:register')
|
||||
'horizon:infrastructure:nodes:register')
|
||||
TEST_DATA = utils.TestDataContainer()
|
||||
tuskar_data.data(TEST_DATA)
|
||||
|
||||
|
||||
class RegisterNodesTests(test.BaseAdminViewTests):
|
||||
class NodesTests(test.BaseAdminViewTests):
|
||||
def test_index_get(self):
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertTemplateUsed(
|
||||
res, 'infrastructure/nodes.overview/index.html')
|
||||
res, 'infrastructure/nodes/index.html')
|
||||
self.assertTemplateUsed(res, 'infrastructure/nodes/_overview.html')
|
||||
|
||||
def test_free_nodes(self):
|
||||
free_nodes = [api.Node(node)
|
||||
for node in self.ironicclient_nodes.list()]
|
||||
|
||||
with patch('tuskar_ui.api.Node', **{
|
||||
'spec_set': ['list'], # Only allow these attributes
|
||||
'list.return_value': free_nodes,
|
||||
}) as mock:
|
||||
res = self.client.get(INDEX_URL + '?tab=nodes__free')
|
||||
self.assertEqual(mock.list.call_count, 4)
|
||||
|
||||
self.maxDiff = None
|
||||
self.assertTemplateUsed(res,
|
||||
'infrastructure/nodes/index.html')
|
||||
self.assertTemplateUsed(res, 'horizon/common/_detail_table.html')
|
||||
self.assertItemsEqual(res.context['free_nodes_table'].data,
|
||||
free_nodes)
|
||||
|
||||
def test_free_nodes_list_exception(self):
|
||||
with patch('tuskar_ui.api.Node', **{
|
||||
'spec_set': ['list'],
|
||||
'list.side_effect': self.exceptions.tuskar,
|
||||
}) as mock:
|
||||
res = self.client.get(INDEX_URL + '?tab=nodes__free')
|
||||
self.assertEqual(mock.list.call_count, 3)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_resource_nodes(self):
|
||||
resource_nodes = [api.Node(node)
|
||||
for node in self.ironicclient_nodes.list()]
|
||||
|
||||
with patch('tuskar_ui.api.Node', **{
|
||||
'spec_set': ['list'], # Only allow these attributes
|
||||
'list.return_value': resource_nodes,
|
||||
}) as mock:
|
||||
res = self.client.get(INDEX_URL + '?tab=nodes__resource')
|
||||
self.assertEqual(mock.list.call_count, 4)
|
||||
|
||||
self.maxDiff = None
|
||||
self.assertTemplateUsed(
|
||||
res, 'infrastructure/nodes/index.html')
|
||||
self.assertTemplateUsed(res, 'horizon/common/_detail_table.html')
|
||||
self.assertItemsEqual(res.context['resource_nodes_table'].data,
|
||||
resource_nodes)
|
||||
|
||||
def test_resource_nodes_list_exception(self):
|
||||
with patch('tuskar_ui.api.Node', **{
|
||||
'spec_set': ['list'],
|
||||
'list.side_effect': self.exceptions.tuskar,
|
||||
}) as mock:
|
||||
res = self.client.get(INDEX_URL + '?tab=nodes__resource')
|
||||
self.assertEqual(mock.list.call_count, 3)
|
||||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def test_register_get(self):
|
||||
res = self.client.get(REGISTER_URL)
|
||||
self.assertTemplateUsed(
|
||||
res, 'infrastructure/nodes.overview/register.html')
|
||||
res, 'infrastructure/nodes/register.html')
|
||||
|
||||
def test_register_post(self):
|
||||
node = TEST_DATA.ironicclient_nodes.first
|
||||
@ -104,4 +162,4 @@ class RegisterNodesTests(test.BaseAdminViewTests):
|
||||
['DE:AD:BE:EF:CA:FF'], None, u''),
|
||||
])
|
||||
self.assertTemplateUsed(
|
||||
res, 'infrastructure/nodes.overview/register.html')
|
||||
res, 'infrastructure/nodes/register.html')
|
@ -14,7 +14,7 @@
|
||||
|
||||
from django.conf import urls
|
||||
|
||||
from tuskar_ui.infrastructure.nodes.overview import views
|
||||
from tuskar_ui.infrastructure.nodes import views
|
||||
|
||||
|
||||
urlpatterns = urls.patterns(
|
42
tuskar_ui/infrastructure/nodes/views.py
Normal file
42
tuskar_ui/infrastructure/nodes/views.py
Normal file
@ -0,0 +1,42 @@
|
||||
# -*- 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.urlresolvers import reverse_lazy
|
||||
|
||||
import horizon.forms
|
||||
from horizon import tabs as horizon_tabs
|
||||
|
||||
from tuskar_ui.infrastructure.nodes import forms
|
||||
from tuskar_ui.infrastructure.nodes import tabs
|
||||
|
||||
|
||||
class IndexView(horizon_tabs.TabbedTableView):
|
||||
tab_group_class = tabs.NodeTabs
|
||||
template_name = 'infrastructure/nodes/index.html'
|
||||
|
||||
|
||||
class RegisterView(horizon.forms.ModalFormView):
|
||||
form_class = forms.NodeFormset
|
||||
form_prefix = 'register_nodes'
|
||||
template_name = 'infrastructure/nodes/register.html'
|
||||
success_url = reverse_lazy(
|
||||
'horizon:infrastructure:nodes:index')
|
||||
|
||||
def get_data(self):
|
||||
return []
|
||||
|
||||
def get_form(self, form_class):
|
||||
return form_class(self.request.POST or None,
|
||||
initial=self.get_data(),
|
||||
prefix=self.form_prefix)
|
@ -19,9 +19,9 @@ import horizon
|
||||
from tuskar_ui.infrastructure import dashboard
|
||||
|
||||
|
||||
class Compute(horizon.Panel):
|
||||
name = _("Compute")
|
||||
slug = "deployment.compute"
|
||||
class Overcloud(horizon.Panel):
|
||||
name = _("Overcloud")
|
||||
slug = "overcloud"
|
||||
|
||||
|
||||
dashboard.Infrastructure.register(Compute)
|
||||
dashboard.Infrastructure.register(Overcloud)
|
@ -14,7 +14,7 @@
|
||||
|
||||
from django.conf.urls import defaults
|
||||
|
||||
from tuskar_ui.infrastructure.deployment.compute import views
|
||||
from tuskar_ui.infrastructure.overcloud import views
|
||||
|
||||
|
||||
urlpatterns = defaults.patterns(
|
@ -1,17 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
|
||||
"""
|
@ -1,27 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# 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 Overview(horizon.Panel):
|
||||
name = _("Overview")
|
||||
slug = "overview"
|
||||
|
||||
|
||||
dashboard.Infrastructure.register(Overview)
|
@ -1,12 +0,0 @@
|
||||
{% extends 'infrastructure/base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Overview" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Overview") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block infrastructure_main %}
|
||||
{% endblock %}
|
||||
|
||||
|
@ -1,21 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# 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 openstack_dashboard.test import helpers as test
|
||||
|
||||
|
||||
class OverviewTests(test.TestCase):
|
||||
# Unit tests for overview.
|
||||
def test_me(self):
|
||||
self.assertTrue(1 + 1 == 2)
|
@ -1,23 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# 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.urls import defaults
|
||||
|
||||
from tuskar_ui.infrastructure.overview import views
|
||||
|
||||
|
||||
urlpatterns = defaults.patterns(
|
||||
'',
|
||||
defaults.url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
)
|
@ -1,24 +0,0 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# 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 views
|
||||
|
||||
|
||||
class IndexView(views.APIView):
|
||||
# A very simple class-based view...
|
||||
template_name = 'infrastructure/overview/index.html'
|
||||
|
||||
def get_data(self, request, context, *args, **kwargs):
|
||||
# Add data to the context here...
|
||||
return context
|
@ -5,9 +5,7 @@
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="breadcrumbs">
|
||||
<a href="{% url 'horizon:infrastructure:overview:index' %}">{% trans "Infrastructure" %}</a>
|
||||
<span class="separator"></span>
|
||||
<a href="{% url 'horizon:infrastructure:nodes.overview:index' %}">{% trans "Nodes" %}</a>
|
||||
<a href="{% url 'horizon:infrastructure:nodes:index' %}">{% trans "Nodes" %}</a>
|
||||
<span class="separator"></span>
|
||||
</div>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user