Flavors table and Flavor detail page
Flavors as nested resource to resource_class, the specific content of flavor detail and flavor template detail pages are to be decided. Implements: blueprint flavor-and-flavor-template-details Change-Id: Ib2b967a1cc7129ec06a97a0bd1a4de6625186504
This commit is contained in:
parent
433eb2d4d9
commit
9ff082e5a7
@ -641,7 +641,7 @@ class ResourceClass(StringIdAPIResourceWrapper):
|
||||
added_flavors = tuskarclient(self.request).flavors.list(self.id)
|
||||
self._flavors = []
|
||||
for f in added_flavors:
|
||||
flavor_obj = Flavor(f)
|
||||
flavor_obj = Flavor(f, self.request)
|
||||
#flavor_obj.max_vms = f.max_vms
|
||||
|
||||
# FIXME just a mock of used instances, add real values
|
||||
@ -899,6 +899,13 @@ class Flavor(StringIdAPIResourceWrapper):
|
||||
"""
|
||||
_attrs = ['id', 'name', 'max_vms']
|
||||
|
||||
@classmethod
|
||||
def get(cls, request, resource_class_id, flavor_id):
|
||||
flavor = cls(tuskarclient(request).flavors.get(resource_class_id,
|
||||
flavor_id))
|
||||
flavor.request = request
|
||||
return flavor
|
||||
|
||||
@classmethod
|
||||
def create(cls, request, **kwargs):
|
||||
return cls(tuskarclient(request).flavors.create(
|
||||
|
35
tuskar_ui/infrastructure/resource_management/flavors/tabs.py
Normal file
35
tuskar_ui/infrastructure/resource_management/flavors/tabs.py
Normal file
@ -0,0 +1,35 @@
|
||||
# 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 _
|
||||
|
||||
from horizon import tabs
|
||||
|
||||
|
||||
class OverviewTab(tabs.Tab):
|
||||
name = _("Overview")
|
||||
slug = "flavor_overview_tab"
|
||||
template_name = ("infrastructure/resource_management/flavors/"
|
||||
"_detail_overview.html")
|
||||
preload = False
|
||||
|
||||
def get_context_data(self, request):
|
||||
return {"flavor": self.tab_group.kwargs['flavor'],
|
||||
'resource_class': self.tab_group.kwargs['resource_class']}
|
||||
|
||||
|
||||
class FlavorDetailTabs(tabs.TabGroup):
|
||||
slug = "flavor_detail_tabs"
|
||||
tabs = (OverviewTab,)
|
||||
sticky = True
|
@ -0,0 +1,64 @@
|
||||
# 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.core.urlresolvers import reverse
|
||||
from django import http
|
||||
from mox import IsA
|
||||
|
||||
from tuskar_ui import api as tuskar
|
||||
from tuskar_ui.test import helpers as test
|
||||
|
||||
|
||||
class FlavorsTests(test.BaseAdminViewTests):
|
||||
|
||||
@test.create_stubs({tuskar.Flavor: ('get',),
|
||||
tuskar.ResourceClass: ('get',)})
|
||||
def test_detail_flavor(self):
|
||||
flavor = self.tuskar_flavors.first()
|
||||
resource_class = self.tuskar_resource_classes.first()
|
||||
|
||||
tuskar.ResourceClass.get(IsA(http.HttpRequest),
|
||||
resource_class.id).AndReturn(resource_class)
|
||||
|
||||
tuskar.Flavor.get(IsA(http.HttpRequest),
|
||||
resource_class.id,
|
||||
flavor.id).AndReturn(flavor)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:infrastructure:resource_management'
|
||||
':resource_classes:flavors:detail',
|
||||
args=[resource_class.id, flavor.id])
|
||||
res = self.client.get(url)
|
||||
self.assertTemplateUsed(res, "infrastructure/resource_management/"
|
||||
"flavors/detail.html")
|
||||
|
||||
@test.create_stubs({tuskar.Flavor: ('get',)})
|
||||
def test_detail_flavor_exception(self):
|
||||
flavor = self.tuskar_flavors.first()
|
||||
resource_class = self.tuskar_resource_classes.first()
|
||||
|
||||
tuskar.Flavor.get(IsA(http.HttpRequest),
|
||||
resource_class.id,
|
||||
flavor.id).AndRaise(self.exceptions.tuskar)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:infrastructure:resource_management:'
|
||||
'resource_classes:flavors:detail',
|
||||
args=[resource_class.id, flavor.id])
|
||||
res = self.client.get(url)
|
||||
|
||||
self.assertRedirectsNoFollow(
|
||||
res, reverse('horizon:infrastructure:resource_management:index'))
|
28
tuskar_ui/infrastructure/resource_management/flavors/urls.py
Normal file
28
tuskar_ui/infrastructure/resource_management/flavors/urls.py
Normal file
@ -0,0 +1,28 @@
|
||||
# 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.defaults import patterns
|
||||
from django.conf.urls.defaults import url
|
||||
|
||||
from tuskar_ui.infrastructure.resource_management.flavors.views \
|
||||
import DetailView
|
||||
|
||||
|
||||
VIEW_MOD = 'tuskar_ui.infrastructure.' \
|
||||
'resource_management.flavors.views'
|
||||
|
||||
urlpatterns = patterns(VIEW_MOD,
|
||||
url(r'^(?P<flavor_id>[^/]+)/$', DetailView.as_view(), name='detail')
|
||||
)
|
@ -0,0 +1,77 @@
|
||||
# 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.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import tabs
|
||||
|
||||
from tuskar_ui import api as tuskar
|
||||
from tuskar_ui.infrastructure. \
|
||||
resource_management.flavors.tabs import FlavorDetailTabs
|
||||
|
||||
|
||||
class DetailView(tabs.TabView):
|
||||
tab_group_class = FlavorDetailTabs
|
||||
template_name = ('infrastructure/resource_management/flavors/detail.html')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(DetailView, self).get_context_data(**kwargs)
|
||||
context["flavor"] = self.get_flavor_data()
|
||||
context["resource_class"] = self.get_resource_class_data()
|
||||
return context
|
||||
|
||||
def get_flavor_data(self):
|
||||
if not hasattr(self, "_flavor"):
|
||||
try:
|
||||
flavor_id = self.kwargs['flavor_id']
|
||||
resource_class_id = self.kwargs['resource_class_id']
|
||||
flavor = tuskar.Flavor.get(self.request,
|
||||
flavor_id,
|
||||
resource_class_id)
|
||||
except Exception:
|
||||
redirect = reverse('horizon:infrastructure:'
|
||||
'resource_management:index')
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve details for '
|
||||
'flavor "%s".') % flavor_id,
|
||||
redirect=redirect)
|
||||
self._flavor = flavor
|
||||
return self._flavor
|
||||
|
||||
def get_resource_class_data(self):
|
||||
if not hasattr(self, "_resource_class"):
|
||||
try:
|
||||
resource_class_id = self.kwargs['resource_class_id']
|
||||
resource_class = tuskar.ResourceClass.get(self.request,
|
||||
resource_class_id)
|
||||
except Exception:
|
||||
redirect = reverse('horizon:infrastructure:'
|
||||
'resource_management:index')
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve details for resource '
|
||||
'class "%s".') % resource_class_id,
|
||||
redirect=redirect)
|
||||
self._resource_class = resource_class
|
||||
return self._resource_class
|
||||
|
||||
def get_tabs(self, request, *args, **kwargs):
|
||||
flavor = self.get_flavor_data()
|
||||
resource_class = self.get_resource_class_data()
|
||||
return self.tab_group_class(request,
|
||||
flavor=flavor,
|
||||
resource_class=resource_class,
|
||||
**kwargs)
|
@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
from django.core import urlresolvers
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
@ -159,9 +160,17 @@ class UpdateFlavorsClass(tables.LinkAction):
|
||||
|
||||
|
||||
class FlavorsTable(flavor_templates_tables.FlavorTemplatesTable):
|
||||
def get_flavor_detail_link(datum):
|
||||
# FIXME - horizon Column.get_link_url does not allow to access GET
|
||||
# params
|
||||
resource_class_id = re.findall("[0-9]+", datum.request.path)[-1]
|
||||
return urlresolvers.reverse("horizon:infrastructure:"
|
||||
"resource_management:resource_classes:"
|
||||
"flavors:detail",
|
||||
args=(resource_class_id, datum.id))
|
||||
|
||||
name = tuskar_ui.tables.Column('name',
|
||||
link=("horizon:infrastructure:"
|
||||
"resource_management:flavor_templates:detail"),
|
||||
link=get_flavor_detail_link,
|
||||
verbose_name=_('Flavor Name'))
|
||||
max_vms = tuskar_ui.tables.Column("max_vms",
|
||||
verbose_name=_("Max. VMs"))
|
||||
|
@ -12,6 +12,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django.conf.urls.defaults import include
|
||||
from django.conf.urls.defaults import patterns
|
||||
from django.conf.urls.defaults import url
|
||||
|
||||
@ -29,6 +30,8 @@ from tuskar_ui.infrastructure. \
|
||||
resource_management.resource_classes.views import UpdateRacksView
|
||||
from tuskar_ui.infrastructure. \
|
||||
resource_management.resource_classes.views import UpdateView
|
||||
from tuskar_ui.infrastructure. \
|
||||
resource_management.flavors import urls as flavor_urls
|
||||
|
||||
|
||||
RESOURCE_CLASS = r'^(?P<resource_class_id>[^/]+)/%s$'
|
||||
@ -51,4 +54,6 @@ urlpatterns = patterns(
|
||||
name='update_flavors'),
|
||||
url(RESOURCE_CLASS % 'rack_health.json', 'rack_health',
|
||||
name='rack_health'),
|
||||
url(r'^(?P<resource_class_id>[^/]+)/flavors/',
|
||||
include(flavor_urls, namespace='flavors')),
|
||||
)
|
||||
|
@ -0,0 +1,31 @@
|
||||
{% load i18n sizeformat %}
|
||||
{% load url from future %}
|
||||
|
||||
<div class="info row-fluid detail">
|
||||
<div class="span4">
|
||||
<h4>{% trans "About" %}</h4>
|
||||
<hr class="header_rule">
|
||||
<dl>
|
||||
<dt>{% trans "Name" %}</dt>
|
||||
<dd>{{ flavor.name|default:_("None") }}</dd>
|
||||
<dt>{% trans "Resource Class" %}</dt>
|
||||
<dd>{{ resource_class.name|default:_("None") }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="span4">
|
||||
<h4>{% trans "Specification" %}</h4>
|
||||
<hr class="header_rule">
|
||||
<dl>
|
||||
<dt>{% trans "VCPU" %}</dt>
|
||||
<dd>{{ flavor.cpu.value }}</dd>
|
||||
<dt>{% trans "RAM" %}</dt>
|
||||
<dd>{{ flavor.memory.value }} {{ flavor.memory.unit }}</dd>
|
||||
<dt>{% trans "Root Disk" %}</dt>
|
||||
<dd>{{ flavor.storage.value }} {{ flavor.storage.unit }}</dd>
|
||||
<dt>{% trans "Ephemeral Disk" %}</dt>
|
||||
<dd>{{ flavor.ephemeral_disk.value }} {{ flavor.ephemeral_disk.unit }}</dd>
|
||||
<dt>{% trans "Swap Disk" %}</dt>
|
||||
<dd>{{ flavor.swap_disk.value }} {{ flavor.swap_disk.unit }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,23 @@
|
||||
{% extends 'infrastructure/base_detail.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Flavor Detail"%}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Flavor Detail") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block actions %}
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
<a href="{% url 'horizon:infrastructure:resource_management:index' %}?tab=resource_management_tabs__resource_classes_tab" >{% trans 'Home' %}</a>
|
||||
<span class="separator"></span>
|
||||
<a href="{% url 'horizon:infrastructure:resource_management:index' %}?tab=resource_management_tabs__resource_classes_tab" >{% trans 'Classes'%}</a>
|
||||
<span class="separator"></span>
|
||||
<a href="{% url 'horizon:infrastructure:resource_management:resource_classes:detail' resource_class.id %}" >{{ resource_class.name }}</a>
|
||||
<span class="separator"></span>
|
||||
</div>
|
||||
{% endblock breadcrumbs %}
|
||||
|
||||
{% block name %}{{ flavor.name }}{% endblock %}
|
Loading…
x
Reference in New Issue
Block a user