Reworks quotas and services panels into System Info panel.
This is a step towards combining all the "read only" data about an OpenStack cloud into one place for admin inspection. Implements blueprint system-info-panel. Change-Id: I2dc52a855c1c8a488fb9c66b82e0faca765b3812
This commit is contained in:
parent
0e328995ec
commit
2f98befe3f
@ -183,7 +183,8 @@ def novaclient(request):
|
||||
request.user.token.id,
|
||||
project_id=request.user.tenant_id,
|
||||
auth_url=url_for(request, 'compute'),
|
||||
insecure=insecure)
|
||||
insecure=insecure,
|
||||
http_log_debug=settings.DEBUG)
|
||||
c.client.auth_token = request.user.token.id
|
||||
c.client.management_url = url_for(request, 'compute')
|
||||
return c
|
||||
|
@ -22,8 +22,8 @@ import horizon
|
||||
class SystemPanels(horizon.PanelGroup):
|
||||
slug = "admin"
|
||||
name = _("System Panel")
|
||||
panels = ('overview', 'instances', 'volumes', 'services', 'flavors',
|
||||
'images', 'projects', 'users', 'quotas', 'networks',)
|
||||
panels = ('overview', 'instances', 'volumes', 'flavors',
|
||||
'images', 'projects', 'users', 'networks', 'info')
|
||||
|
||||
|
||||
class Admin(horizon.Dashboard):
|
||||
|
@ -26,8 +26,8 @@ from openstack_dashboard.dashboards.admin import dashboard
|
||||
|
||||
|
||||
class Quotas(horizon.Panel):
|
||||
name = _("Quotas")
|
||||
slug = 'quotas'
|
||||
name = _("System Info")
|
||||
slug = 'info'
|
||||
|
||||
|
||||
dashboard.Admin.register(Quotas)
|
@ -1,6 +1,5 @@
|
||||
import logging
|
||||
|
||||
from django import template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import tables
|
||||
@ -9,6 +8,36 @@ from horizon import tables
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class QuotaFilterAction(tables.FilterAction):
|
||||
def filter(self, table, tenants, filter_string):
|
||||
q = filter_string.lower()
|
||||
|
||||
def comp(tenant):
|
||||
if q in tenant.name.lower():
|
||||
return True
|
||||
return False
|
||||
|
||||
return filter(comp, tenants)
|
||||
|
||||
|
||||
def get_quota_name(quota):
|
||||
return quota.name.replace("_", " ").title()
|
||||
|
||||
|
||||
class QuotasTable(tables.DataTable):
|
||||
name = tables.Column(get_quota_name, verbose_name=_('Quota Name'))
|
||||
limit = tables.Column("limit", verbose_name=_('Limit'))
|
||||
|
||||
def get_object_id(self, obj):
|
||||
return obj.name
|
||||
|
||||
class Meta:
|
||||
name = "quotas"
|
||||
verbose_name = _("Quotas")
|
||||
table_actions = (QuotaFilterAction,)
|
||||
multi_select = False
|
||||
|
||||
|
||||
class ServiceFilterAction(tables.FilterAction):
|
||||
def filter(self, table, services, filter_string):
|
||||
q = filter_string.lower()
|
62
openstack_dashboard/dashboards/admin/info/tabs.py
Normal file
62
openstack_dashboard/dashboards/admin/info/tabs.py
Normal file
@ -0,0 +1,62 @@
|
||||
# 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.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import tabs
|
||||
|
||||
from openstack_dashboard.api import keystone
|
||||
from openstack_dashboard.usage import quotas
|
||||
from .tables import QuotasTable, ServicesTable
|
||||
|
||||
|
||||
class DefaultQuotasTab(tabs.TableTab):
|
||||
table_classes = (QuotasTable,)
|
||||
name = _("Default Quotas")
|
||||
slug = "quotas"
|
||||
template_name = ("horizon/common/_detail_table.html")
|
||||
|
||||
def get_quotas_data(self):
|
||||
request = self.tab_group.request
|
||||
try:
|
||||
quota_set = quotas.get_default_quota_data(request)
|
||||
data = quota_set.items
|
||||
except:
|
||||
data = []
|
||||
exceptions.handle(self.request, _('Unable to get quota info.'))
|
||||
return data
|
||||
|
||||
|
||||
class ServicesTab(tabs.TableTab):
|
||||
table_classes = (ServicesTable,)
|
||||
name = _("Services")
|
||||
slug = "services"
|
||||
template_name = ("horizon/common/_detail_table.html")
|
||||
|
||||
def get_services_data(self):
|
||||
request = self.tab_group.request
|
||||
services = []
|
||||
for i, service in enumerate(request.user.service_catalog):
|
||||
service['id'] = i
|
||||
services.append(keystone.Service(service))
|
||||
return services
|
||||
|
||||
|
||||
class SystemInfoTabs(tabs.TabGroup):
|
||||
slug = "system_info"
|
||||
tabs = (ServicesTab, DefaultQuotasTab,)
|
||||
sticky = True
|
@ -0,0 +1,15 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "System Info" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("System Info")%}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
{{ tab_group.render }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
71
openstack_dashboard/dashboards/admin/info/tests.py
Normal file
71
openstack_dashboard/dashboards/admin/info/tests.py
Normal file
@ -0,0 +1,71 @@
|
||||
# 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 import http
|
||||
from django.core.urlresolvers import reverse
|
||||
from mox import IsA
|
||||
|
||||
from openstack_dashboard.test import helpers as test
|
||||
from openstack_dashboard import api
|
||||
|
||||
INDEX_URL = reverse('horizon:admin:info:index')
|
||||
|
||||
|
||||
class ServicessViewTests(test.BaseAdminViewTests):
|
||||
def test_index(self):
|
||||
self.mox.StubOutWithMock(api.nova, 'default_quota_get')
|
||||
self.mox.StubOutWithMock(api.cinder, 'default_quota_get')
|
||||
api.nova.default_quota_get(IsA(http.HttpRequest),
|
||||
self.tenant.id).AndReturn(self.quotas.nova)
|
||||
api.cinder.default_quota_get(IsA(http.HttpRequest), self.tenant.id) \
|
||||
.AndReturn(self.quotas.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
|
||||
self.assertTemplateUsed(res, 'admin/info/index.html')
|
||||
|
||||
services_tab = res.context['tab_group'].get_tab('services')
|
||||
self.assertQuerysetEqual(services_tab._tables['services'].data,
|
||||
['<Service: compute>',
|
||||
'<Service: volume>',
|
||||
'<Service: image>',
|
||||
'<Service: identity (native backend)>',
|
||||
'<Service: object-store>',
|
||||
'<Service: network>',
|
||||
'<Service: ec2>'])
|
||||
|
||||
quotas_tab = res.context['tab_group'].get_tab('quotas')
|
||||
self.assertQuerysetEqual(quotas_tab._tables['quotas'].data,
|
||||
['<Quota: (injected_file_content_bytes, 1)>',
|
||||
'<Quota: (metadata_items, 1)>',
|
||||
'<Quota: (injected_files, 1)>',
|
||||
'<Quota: (gigabytes, 1000)>',
|
||||
'<Quota: (ram, 10000)>',
|
||||
'<Quota: (floating_ips, 1)>',
|
||||
'<Quota: (instances, 10)>',
|
||||
'<Quota: (volumes, 1)>',
|
||||
'<Quota: (cores, 10)>',
|
||||
'<Quota: (injected_file_content_bytes, 1)>',
|
||||
'<Quota: (metadata_items, 1)>',
|
||||
'<Quota: (injected_files, 1)>',
|
||||
'<Quota: (gigabytes, 1000)>',
|
||||
'<Quota: (ram, 10000)>',
|
||||
'<Quota: (floating_ips, 1)>',
|
||||
'<Quota: (instances, 10)>',
|
||||
'<Quota: (volumes, 1)>',
|
||||
'<Quota: (cores, 10)>'])
|
@ -23,5 +23,5 @@ from django.conf.urls.defaults import patterns, url
|
||||
from .views import IndexView
|
||||
|
||||
|
||||
urlpatterns = patterns('openstack_dashboard.dashboards.admin.quotas.views',
|
||||
urlpatterns = patterns('openstack_dashboard.dashboards.admin.info.views',
|
||||
url(r'^$', IndexView.as_view(), name='index'))
|
@ -18,10 +18,16 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
import logging
|
||||
|
||||
from .views import IndexView
|
||||
from horizon import tabs
|
||||
|
||||
from .tabs import SystemInfoTabs
|
||||
|
||||
|
||||
urlpatterns = patterns('openstack_dashboard.dashboards.admin.services.views',
|
||||
url(r'^$', IndexView.as_view(), name='index'))
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IndexView(tabs.TabbedTableView):
|
||||
tab_group_class = SystemInfoTabs
|
||||
template_name = 'admin/info/index.html'
|
@ -1,38 +0,0 @@
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import tables
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class QuotaFilterAction(tables.FilterAction):
|
||||
def filter(self, table, tenants, filter_string):
|
||||
q = filter_string.lower()
|
||||
|
||||
def comp(tenant):
|
||||
if q in tenant.name.lower():
|
||||
return True
|
||||
return False
|
||||
|
||||
return filter(comp, tenants)
|
||||
|
||||
|
||||
def get_quota_name(quota):
|
||||
return quota.name.replace("_", " ").title()
|
||||
|
||||
|
||||
class QuotasTable(tables.DataTable):
|
||||
name = tables.Column(get_quota_name, verbose_name=_('Quota Name'))
|
||||
limit = tables.Column("limit", verbose_name=_('Limit'))
|
||||
|
||||
def get_object_id(self, obj):
|
||||
return obj.name
|
||||
|
||||
class Meta:
|
||||
name = "quotas"
|
||||
verbose_name = _("Quotas")
|
||||
table_actions = (QuotaFilterAction,)
|
||||
multi_select = False
|
@ -1,13 +0,0 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}Quotas{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% url horizon:admin:quotas:index as refresh_link %}
|
||||
{# to make searchable false, just remove it from the include statement #}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Default Quotas") refresh_link=refresh_link searchable="true" %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{{ table.render }}
|
||||
{% endblock %}
|
@ -1 +0,0 @@
|
||||
#FIXME(gabriel): Needs tests!
|
@ -1,47 +0,0 @@
|
||||
# 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.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import tables
|
||||
|
||||
from openstack_dashboard import api
|
||||
from .tables import QuotasTable
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IndexView(tables.DataTableView):
|
||||
table_class = QuotasTable
|
||||
template_name = 'admin/quotas/index.html'
|
||||
|
||||
def get_data(self):
|
||||
try:
|
||||
quota_set = api.default_quota_get(self.request,
|
||||
self.request.user.tenant_id)
|
||||
data = quota_set.items
|
||||
except:
|
||||
data = []
|
||||
exceptions.handle(self.request, _('Unable to get quota info.'))
|
||||
return data
|
@ -1,33 +0,0 @@
|
||||
# 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.
|
||||
#
|
||||
# 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.utils.translation import ugettext_lazy as _
|
||||
|
||||
import horizon
|
||||
|
||||
from openstack_dashboard.dashboards.admin import dashboard
|
||||
|
||||
|
||||
class Services(horizon.Panel):
|
||||
name = _("Services")
|
||||
slug = 'services'
|
||||
|
||||
|
||||
dashboard.Admin.register(Services)
|
@ -1,14 +0,0 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}Services{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% url horizon:admin:services:index as refresh_link %}
|
||||
{# to make searchable false, just remove it from the include statement #}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Services") refresh_link=refresh_link searchable="true" %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{{ table.render }}
|
||||
{% endblock %}
|
||||
|
@ -1,36 +0,0 @@
|
||||
# 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.urlresolvers import reverse
|
||||
|
||||
from openstack_dashboard.test import helpers as test
|
||||
|
||||
|
||||
INDEX_URL = reverse('horizon:admin:services:index')
|
||||
|
||||
|
||||
class ServicessViewTests(test.BaseAdminViewTests):
|
||||
def test_index(self):
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertTemplateUsed(res, 'admin/services/index.html')
|
||||
self.assertQuerysetEqual(res.context['table'].data,
|
||||
['<Service: compute>',
|
||||
'<Service: volume>',
|
||||
'<Service: image>',
|
||||
'<Service: identity (native backend)>',
|
||||
'<Service: object-store>',
|
||||
'<Service: network>',
|
||||
'<Service: ec2>'])
|
@ -1,41 +0,0 @@
|
||||
# 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.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from horizon import tables
|
||||
|
||||
from openstack_dashboard import api
|
||||
from .tables import ServicesTable
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IndexView(tables.DataTableView):
|
||||
table_class = ServicesTable
|
||||
template_name = 'admin/services/index.html'
|
||||
|
||||
def get_data(self):
|
||||
services = []
|
||||
for i, service in enumerate(self.request.user.service_catalog):
|
||||
service['id'] = i
|
||||
services.append(api.keystone.Service(service))
|
||||
return services
|
@ -280,6 +280,7 @@ def data(TEST):
|
||||
injected_files='1',
|
||||
cores='10')
|
||||
quota = quotas.QuotaSet(quotas.QuotaSetManager(None), quota_data)
|
||||
TEST.quotas.nova = QuotaSetWrapper(quota)
|
||||
TEST.quotas.add(QuotaSetWrapper(quota))
|
||||
|
||||
# Quota Usages
|
||||
|
Loading…
Reference in New Issue
Block a user