As an Operator, I want to define a resource class through the UI
Tab and Table with resource classes added(index view) Create Workflow for Resource Class, info is editable. Deleting is now working. Thanks to jprovaznik Basic unit tests written. Change-Id: I9f50a0dac26759f8c3fecbccbc4a822024939155
This commit is contained in:
committed by
Tomas Sedovic
parent
949779e62a
commit
4eaa37ef0b
@@ -1,15 +1,20 @@
|
||||
[
|
||||
{"pk": 1, "model": "infrastructure.flavor", "fields": {"name": "flavor1"}},
|
||||
{"pk": 1, "model": "infrastructure.flavor", "fields": {"name": "flavor1"}},
|
||||
{"pk": 2, "model": "infrastructure.flavor", "fields": {"name": "flavor2"}},
|
||||
{"pk": 3, "model": "infrastructure.flavor", "fields": {"name": "flavor3"}},
|
||||
{"pk": 4, "model": "infrastructure.flavor", "fields": {"name": "flavor4"}},
|
||||
{"pk": 5, "model": "infrastructure.flavor", "fields": {"name": "flavor5"}},
|
||||
{"pk": 6, "model": "infrastructure.flavor", "fields": {"name": "flavor6"}},
|
||||
|
||||
{"pk": 1, "model": "infrastructure.host", "fields": {"name": "host1", "rack": 1}},
|
||||
{"pk": 2, "model": "infrastructure.host", "fields": {"name": "host2", "rack": 1}},
|
||||
{"pk": 3, "model": "infrastructure.host", "fields": {"name": "host3", "rack": 2}},
|
||||
{"pk": 4, "model": "infrastructure.host", "fields": {"name": "host4", "rack": 2}},
|
||||
{"pk": 1, "model": "infrastructure.host", "fields": {"name": "host1", "rack": 1}},
|
||||
{"pk": 2, "model": "infrastructure.host", "fields": {"name": "host2", "rack": 1}},
|
||||
{"pk": 3, "model": "infrastructure.host", "fields": {"name": "host3", "rack": 2}},
|
||||
{"pk": 4, "model": "infrastructure.host", "fields": {"name": "host4", "rack": 2}},
|
||||
|
||||
{"pk": 1, "model": "infrastructure.rack", "fields": {"name": "rack1", "resource_class": 1}},
|
||||
{"pk": 2, "model": "infrastructure.rack", "fields": {"name": "rack2", "resource_class": 1}},
|
||||
{"pk": 1, "model": "infrastructure.rack", "fields": {"name": "rack1", "resource_class": 1}},
|
||||
{"pk": 2, "model": "infrastructure.rack", "fields": {"name": "rack2", "resource_class": 1}},
|
||||
|
||||
{"pk": 1, "model": "infrastructure.resourceclass", "fields": {"service_type": "compute", "flavors": [1], "name": "rclass1"}},
|
||||
{"pk": 2, "model": "infrastructure.resourceclass", "fields": {"service_type": "compute", "flavors": [], "name": "rclass2"}},
|
||||
{"pk": 3, "model": "infrastructure.resourceclass", "fields": {"service_type": "storage", "flavors": [], "name": "rclass3"}}
|
||||
{"pk": 1, "model": "infrastructure.resourceclass", "fields": {"service_type": "compute", "flavors": [1], "name": "rclass1"}},
|
||||
{"pk": 2, "model": "infrastructure.resourceclass", "fields": {"service_type": "compute", "flavors": [], "name": "rclass2"}},
|
||||
{"pk": 3, "model": "infrastructure.resourceclass", "fields": {"service_type": "storage", "flavors": [], "name": "rclass3"}}
|
||||
]
|
||||
|
||||
@@ -24,7 +24,7 @@ class CreateRack(forms.SelfHandlingForm):
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(CreateRack, self).__init__(request, *args, **kwargs)
|
||||
resource_class_id_choices = [('', _("Select a Resource Class"))]
|
||||
for rc in api.management.resource_class_list(request):
|
||||
for rc in api.management.ResourceClass.list(request):
|
||||
resource_class_id_choices.append((rc.id, rc.name))
|
||||
self.fields['resource_class_id'].choices = resource_class_id_choices
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django import shortcuts
|
||||
from django.core import urlresolvers
|
||||
from django.utils.http import urlencode
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import messages
|
||||
from horizon import tables
|
||||
from horizon import forms
|
||||
|
||||
from openstack_dashboard import api
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateResourceClass(tables.LinkAction):
|
||||
name = "create_class"
|
||||
verbose_name = _("Create Class")
|
||||
url = "horizon:infrastructure:resource_management:resource_classes:create"
|
||||
classes = ("ajax-modal", "btn-create")
|
||||
|
||||
|
||||
class UpdateResourceClass(tables.LinkAction):
|
||||
name = "edit_class"
|
||||
verbose_name = _("Edit Class")
|
||||
url = "horizon:infrastructure:resource_management:resource_classes:update"
|
||||
classes = ("ajax-modal", "btn-edit")
|
||||
|
||||
|
||||
class DeleteResourceClass(tables.DeleteAction):
|
||||
data_type_singular = _("Resource Class")
|
||||
data_type_plural = _("Resource Classes")
|
||||
|
||||
def delete(self, request, obj_id):
|
||||
try:
|
||||
api.management.ResourceClass.get(request, obj_id).delete(request)
|
||||
except:
|
||||
msg = _('Failed to delete resource class %s') % obj_id
|
||||
LOG.info(msg)
|
||||
redirect = urlresolvers.reverse(
|
||||
"horizon:infrastructure:resource_management:index")
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
|
||||
|
||||
class ResourcesClassFilterAction(tables.FilterAction):
|
||||
def filter(self, table, instances, filter_string):
|
||||
pass
|
||||
|
||||
|
||||
class ResourceClassesTable(tables.DataTable):
|
||||
name = tables.Column("name",
|
||||
link=('horizon:infrastructure:'
|
||||
'resource_management:resource_classes:detail'),
|
||||
verbose_name=_("Class Name"))
|
||||
service_type = tables.Column("service_type",
|
||||
verbose_name=_("Class Type"))
|
||||
racks_count = tables.Column("racks_count",
|
||||
verbose_name=_("Racks"),
|
||||
empty_value="0")
|
||||
hosts_count = tables.Column("hosts_count",
|
||||
verbose_name=_("Hosts"),
|
||||
empty_value="0")
|
||||
|
||||
class Meta:
|
||||
name = "resource_classes"
|
||||
verbose_name = ("Classes")
|
||||
table_actions = (ResourcesClassFilterAction, CreateResourceClass,
|
||||
DeleteResourceClass)
|
||||
row_actions = (UpdateResourceClass, DeleteResourceClass)
|
||||
@@ -1,3 +1,17 @@
|
||||
# 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
|
||||
|
||||
@@ -1,15 +1,83 @@
|
||||
# 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 collections import namedtuple
|
||||
|
||||
from django import http
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from mox import IsA
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard.test import helpers as test
|
||||
|
||||
|
||||
class ResourceClassesTests(test.BaseAdminViewTests):
|
||||
def test_create_resource_class(self):
|
||||
ResourceClass = namedtuple('ResourceClass', 'id, name, service_type')
|
||||
resource_class = ResourceClass(1, 'test', 'compute')
|
||||
|
||||
self.mox.ReplayAll()
|
||||
url = reverse(
|
||||
'horizon:infrastructure:resource_management:'
|
||||
'resource_classes:create')
|
||||
resp = self.client.get(url)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
data = {'name': resource_class.name,
|
||||
'service_type': resource_class.service_type}
|
||||
resp = self.client.post(url, data)
|
||||
self.assertRedirectsNoFollow(
|
||||
resp, reverse('horizon:infrastructure:resource_management:index'))
|
||||
|
||||
def test_edit_resource_class(self):
|
||||
ResourceClass = namedtuple('ResourceClass', 'id, name, service_type')
|
||||
resource_class = ResourceClass(1, 'test', 'compute')
|
||||
self.mox.ReplayAll()
|
||||
# get_test
|
||||
url = reverse(
|
||||
'horizon:infrastructure:resource_management:'
|
||||
'resource_classes:update',
|
||||
args=[resource_class.id])
|
||||
resp = self.client.get(url)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
# post test
|
||||
data = {'resource_class_id': resource_class.id,
|
||||
'name': resource_class.name,
|
||||
'service_type': resource_class.service_type}
|
||||
resp = self.client.post(url, data)
|
||||
self.assertNoFormErrors(resp)
|
||||
self.assertMessageCount(success=1)
|
||||
self.assertRedirectsNoFollow(
|
||||
resp, reverse('horizon:infrastructure:resource_management:index'))
|
||||
|
||||
""" #I don't have update yet, it's not suported by API """
|
||||
|
||||
def test_delete_resource_class(self):
|
||||
ResourceClass = namedtuple('ResourceClass', 'id, name, service_type')
|
||||
resource_class = ResourceClass(1, 'test', 'compute')
|
||||
self.mox.ReplayAll()
|
||||
form_data = {'action':
|
||||
'resource_classes__delete__%s' % resource_class.id}
|
||||
res = self.client.post(
|
||||
reverse('horizon:infrastructure:resource_management:index'),
|
||||
form_data)
|
||||
self.assertRedirectsNoFollow(
|
||||
res, reverse('horizon:infrastructure:resource_management:index'))
|
||||
|
||||
|
||||
class ResourceClassViewTests(test.BaseAdminViewTests):
|
||||
|
||||
def test_detail_get(self):
|
||||
ResourceClass = namedtuple('ResourceClass', 'id, name')
|
||||
resource_class = ResourceClass('1', 'test')
|
||||
ResourceClass = namedtuple('ResourceClass', 'id, name, service_type')
|
||||
resource_class = ResourceClass('1', 'test', 'compute')
|
||||
|
||||
url = reverse('horizon:infrastructure:resource_management:'
|
||||
'resource_classes:detail', args=[resource_class.id])
|
||||
|
||||
@@ -1,9 +1,26 @@
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
# 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 .views import DetailView
|
||||
from django.conf.urls.defaults import patterns, url, include
|
||||
|
||||
from .views import CreateView, UpdateView, DetailView
|
||||
|
||||
urlpatterns = patterns('',
|
||||
RESOURCE_CLASS = r'^(?P<resource_class_id>[^/]+)/%s$'
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
url(r'^create$', CreateView.as_view(), name='create'),
|
||||
url(r'^(?P<resource_class_id>[^/]+)/$',
|
||||
DetailView.as_view(), name='detail'),
|
||||
)
|
||||
url(RESOURCE_CLASS % 'update', UpdateView.as_view(), name='update'))
|
||||
|
||||
@@ -1,13 +1,79 @@
|
||||
from django.core.urlresolvers import reverse
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2012 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Views for managing resource classes
|
||||
"""
|
||||
import logging
|
||||
|
||||
from django.core.urlresolvers import reverse_lazy, reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import tabs
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import workflows
|
||||
|
||||
from openstack_dashboard import api
|
||||
|
||||
from .workflows import CreateResourceClass, UpdateResourceClass
|
||||
from .tables import ResourceClassesTable
|
||||
from .tabs import ResourceClassDetailTabs
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateView(workflows.WorkflowView):
|
||||
workflow_class = CreateResourceClass
|
||||
|
||||
def get_initial(self):
|
||||
pass
|
||||
|
||||
|
||||
class UpdateView(workflows.WorkflowView):
|
||||
workflow_class = UpdateResourceClass
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UpdateView, self).get_context_data(**kwargs)
|
||||
context["resource_class_id"] = self.kwargs['resource_class_id']
|
||||
return context
|
||||
|
||||
def _get_object(self, *args, **kwargs):
|
||||
if not hasattr(self, "_object"):
|
||||
resource_class_id = self.kwargs['resource_class_id']
|
||||
try:
|
||||
self._object = \
|
||||
api.management.ResourceClass.get(self.request,
|
||||
resource_class_id)
|
||||
except:
|
||||
redirect = self.success_url
|
||||
msg = _('Unable to retrieve resource class details.')
|
||||
exceptions.handle(self.request, msg, redirect=redirect)
|
||||
|
||||
return self._object
|
||||
|
||||
def get_initial(self):
|
||||
resource_class = self._get_object()
|
||||
|
||||
return {'resource_class_id': resource_class.id,
|
||||
'name': resource_class.name,
|
||||
'service_type': resource_class.service_type}
|
||||
|
||||
|
||||
class DetailView(tabs.TabView):
|
||||
tab_group_class = ResourceClassDetailTabs
|
||||
@@ -24,12 +90,11 @@ class DetailView(tabs.TabView):
|
||||
try:
|
||||
resource_class_id = self.kwargs['resource_class_id']
|
||||
resource_class = api.management.\
|
||||
resource_class_get(self.request,
|
||||
resource_class_id)
|
||||
ResourceClass.get(self.request,
|
||||
resource_class_id)
|
||||
except:
|
||||
redirect = reverse('horizon:infrastructure:'
|
||||
'resource_management:resource_classes:'
|
||||
'index')
|
||||
'resource_management:index')
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve details for '
|
||||
'resource class "%s".')
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
|
||||
# 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 workflows
|
||||
from horizon import forms
|
||||
|
||||
from openstack_dashboard import api
|
||||
|
||||
INDEX_URL = "horizon:infrastructure:resource_management:index"
|
||||
|
||||
|
||||
class ResourceClassInfoAndFlavorsAction(workflows.Action):
|
||||
name = forms.CharField(max_length=255,
|
||||
label=_("Class Name"),
|
||||
help_text="",
|
||||
required=True)
|
||||
service_type = forms.ChoiceField(label=_('Class Type'),
|
||||
required=True,
|
||||
choices=[('', ''),
|
||||
('compute',
|
||||
('Compute')),
|
||||
('storage',
|
||||
('Storage')),
|
||||
],
|
||||
widget=forms.Select(
|
||||
attrs={'class': 'switchable'})
|
||||
)
|
||||
|
||||
class Meta:
|
||||
name = _("Class Settings")
|
||||
help_text = _("From here you can fill the class "
|
||||
"settings and add flavors to class.")
|
||||
|
||||
|
||||
class CreateResourceClassInfoAndFlavors(workflows.Step):
|
||||
action_class = ResourceClassInfoAndFlavorsAction
|
||||
template_name = 'infrastructure/resource_management/resource_classes/'\
|
||||
'_resource_class_info_and_flavors_step.html'
|
||||
contributes = ("name", "service_type", "flavors_object_ids",
|
||||
'flavors_object_ids_max_vms')
|
||||
|
||||
|
||||
class ResourcesAction(workflows.Action):
|
||||
|
||||
class Meta:
|
||||
name = _("Resources")
|
||||
|
||||
|
||||
class CreateResources(workflows.Step):
|
||||
action_class = ResourcesAction
|
||||
contributes = ("resources_object_ids")
|
||||
template_name = 'infrastructure/resource_management/'\
|
||||
'resource_classes/_resources_step.html'
|
||||
|
||||
|
||||
class ResourceClassWorkflowMixin:
|
||||
def get_success_url(self):
|
||||
return reverse(INDEX_URL)
|
||||
|
||||
def get_failure_url(self):
|
||||
return reverse(INDEX_URL)
|
||||
|
||||
def format_status_message(self, message):
|
||||
name = self.context.get('name')
|
||||
return message % name
|
||||
|
||||
def _add_flavors(self, request, data, resource_class):
|
||||
pass
|
||||
|
||||
def _add_resources(self, request, data, resource_class):
|
||||
pass
|
||||
|
||||
|
||||
class CreateResourceClass(ResourceClassWorkflowMixin, workflows.Workflow):
|
||||
default_steps = (CreateResourceClassInfoAndFlavors,
|
||||
CreateResources)
|
||||
|
||||
slug = "create_resource_class"
|
||||
name = _("Create Class")
|
||||
finalize_button_name = _("Create Class")
|
||||
success_message = _('Created class "%s".')
|
||||
failure_message = _('Unable to create class "%s".')
|
||||
|
||||
def _create_resource_class_info(self, request, data):
|
||||
try:
|
||||
return api.management.ResourceClass.create(
|
||||
request,
|
||||
name=data['name'],
|
||||
service_type=data['service_type'])
|
||||
except:
|
||||
redirect = reverse(INDEX_URL)
|
||||
exceptions.handle(request,
|
||||
_('Unable to create resource class.'),
|
||||
redirect=redirect)
|
||||
return None
|
||||
|
||||
def handle(self, request, data):
|
||||
resource_class = self._create_resource_class_info(request, data)
|
||||
self._add_resources(request, data, resource_class)
|
||||
self._add_flavors(request, data, resource_class)
|
||||
return True
|
||||
|
||||
|
||||
class UpdateResourceClassInfoAndFlavors(CreateResourceClassInfoAndFlavors):
|
||||
depends_on = ("resource_class_id",)
|
||||
|
||||
|
||||
class UpdateResources(CreateResources):
|
||||
depends_on = ("resource_class_id",)
|
||||
|
||||
|
||||
class UpdateResourceClass(ResourceClassWorkflowMixin, workflows.Workflow):
|
||||
default_steps = (UpdateResourceClassInfoAndFlavors,
|
||||
UpdateResources)
|
||||
|
||||
slug = "update_resource_class"
|
||||
name = _("Update Class")
|
||||
finalize_button_name = _("Update Class")
|
||||
success_message = _('Updated class "%s".')
|
||||
failure_message = _('Unable to update class "%s".')
|
||||
|
||||
def _update_resource_class_info(self, request, data):
|
||||
try:
|
||||
resource_class = api.management.ResourceClass.get(
|
||||
request,
|
||||
data['resource_class_id'])
|
||||
resource_class.update_attributes(
|
||||
request,
|
||||
name=data['name'],
|
||||
service_type=data['service_type'])
|
||||
return resource_class
|
||||
except:
|
||||
redirect = reverse(INDEX_URL)
|
||||
exceptions.handle(request,
|
||||
_('Unable to create resource class.'),
|
||||
redirect=redirect)
|
||||
return None
|
||||
|
||||
def handle(self, request, data):
|
||||
resource_class = self._update_resource_class_info(request, data)
|
||||
self._add_resources(request, data, resource_class)
|
||||
self._add_flavors(request, data, resource_class)
|
||||
return True
|
||||
@@ -26,6 +26,7 @@ from openstack_dashboard.api import management
|
||||
|
||||
from .flavors.tables import FlavorsTable
|
||||
from .racks.tables import RacksTable
|
||||
from .resource_classes.tables import ResourceClassesTable
|
||||
|
||||
|
||||
class RacksTab(tabs.TableTab):
|
||||
@@ -64,7 +65,24 @@ class FlavorsTab(tabs.TableTab):
|
||||
return flavors
|
||||
|
||||
|
||||
class ResourceClassesTab(tabs.TableTab):
|
||||
table_classes = (ResourceClassesTable,)
|
||||
name = _("Classes")
|
||||
slug = "resource_classes_tab"
|
||||
template_name = "horizon/common/_detail_table.html"
|
||||
#preload = False buggy, checkboxes doesn't work wit table actions
|
||||
|
||||
def get_resource_classes_data(self):
|
||||
try:
|
||||
resource_classes = management.ResourceClass.list(self.request)
|
||||
except:
|
||||
resource_classes = []
|
||||
exceptions.handle(self.request,
|
||||
_('Unable to retrieve resource classes list.'))
|
||||
return resource_classes
|
||||
|
||||
|
||||
class ResourceManagementTabs(tabs.TabGroup):
|
||||
slug = "resource_management_tabs"
|
||||
tabs = (FlavorsTab, RacksTab,)
|
||||
tabs = (FlavorsTab, RacksTab, ResourceClassesTab, )
|
||||
sticky = True
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{% include "horizon/common/_page_header.html" with title=_("Resource Management") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block infrastructure_main %}
|
||||
{% block main %}
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
{{ tab_group.render }}
|
||||
@@ -14,4 +14,3 @@
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<noscript><h3>{{ step }}</h3></noscript>
|
||||
<table class="table-fixed">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="actions">
|
||||
{% include "horizon/common/_form_fields.html" %}
|
||||
</td>
|
||||
<td class="help_text">
|
||||
{{ step.get_help_text }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
TODO: flavors_table.render
|
||||
@@ -0,0 +1,3 @@
|
||||
<noscript><h3>{{ step }}</h3></noscript>
|
||||
|
||||
TODO: resources_table.render
|
||||
@@ -19,13 +19,13 @@ from django.conf.urls.defaults import patterns, url, include
|
||||
from .flavors import urls as flavor_urls
|
||||
from .resource_classes import urls as resource_classes_urls
|
||||
from .racks import urls as rack_urls
|
||||
from .views import IndexView
|
||||
|
||||
from .views import IndexView
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', IndexView.as_view(), name='index'),
|
||||
url(r'flavors/', include(flavor_urls, namespace='flavors')),
|
||||
url(r'resource_classes/', include(resource_classes_urls,
|
||||
namespace='resource_classes')),
|
||||
url(r'racks/', include(rack_urls, namespace='racks')),
|
||||
url(r'resource_classes/',
|
||||
include(resource_classes_urls, namespace='resource_classes')),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user