Add a Hosts panel to the admin dashboard
This patch adds a new 'Hosts' panel to the admin dashboard. This panel is grouped in the 'Reservation' group. Only a list view of hosts is currently supported. Partially Implements: blueprint host-operation-with-dashboard Change-Id: I691fa53de4de1e3fbf367eba2f997cd6cafba875
This commit is contained in:
parent
0d6c547552
commit
6afd13a148
@ -39,6 +39,16 @@ class Lease(base.APIDictWrapper):
|
||||
super(Lease, self).__init__(apiresource)
|
||||
|
||||
|
||||
class Host(base.APIDictWrapper):
|
||||
"""Represents one Blazar host."""
|
||||
|
||||
_attrs = ['id', 'hypervisor_hostname', 'hypervisor_type', 'vcpus',
|
||||
'cpu_info', 'memory_mb', 'local_gb']
|
||||
|
||||
def __init__(self, apiresource):
|
||||
super(Host, self).__init__(apiresource)
|
||||
|
||||
|
||||
@memoized
|
||||
def blazarclient(request):
|
||||
try:
|
||||
@ -82,3 +92,9 @@ def lease_update(request, lease_id, **kwargs):
|
||||
def lease_delete(request, lease_id):
|
||||
"""Delete a lease."""
|
||||
blazarclient(request).lease.delete(lease_id)
|
||||
|
||||
|
||||
def host_list(request):
|
||||
"""List hosts."""
|
||||
hosts = blazarclient(request).host.list()
|
||||
return [Host(h) for h in hosts]
|
||||
|
0
blazar_dashboard/content/hosts/__init__.py
Normal file
0
blazar_dashboard/content/hosts/__init__.py
Normal file
19
blazar_dashboard/content/hosts/panel.py
Normal file
19
blazar_dashboard/content/hosts/panel.py
Normal file
@ -0,0 +1,19 @@
|
||||
# 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
|
||||
|
||||
|
||||
class Hosts(horizon.Panel):
|
||||
name = _("Hosts")
|
||||
slug = "hosts"
|
29
blazar_dashboard/content/hosts/tables.py
Normal file
29
blazar_dashboard/content/hosts/tables.py
Normal file
@ -0,0 +1,29 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from horizon import tables
|
||||
from horizon.templatetags import sizeformat
|
||||
|
||||
|
||||
class HostsTable(tables.DataTable):
|
||||
name = tables.Column("hypervisor_hostname", verbose_name=_("Host name"))
|
||||
vcpus = tables.Column("vcpus", verbose_name=_("VCPUs"))
|
||||
memory_mb = tables.Column("memory_mb", verbose_name=_("RAM"),
|
||||
filters=(sizeformat.mb_float_format,))
|
||||
local_gb = tables.Column("local_gb", verbose_name=_("Local Storage"),
|
||||
filters=(sizeformat.diskgbformat,))
|
||||
type = tables.Column("hypervisor_type", verbose_name=_("Hypervisor type"))
|
||||
|
||||
class Meta(object):
|
||||
name = "hosts"
|
||||
verbose_name = _("Hosts")
|
11
blazar_dashboard/content/hosts/templates/hosts/index.html
Normal file
11
blazar_dashboard/content/hosts/templates/hosts/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Hosts" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Hosts") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{{ table.render }}
|
||||
{% endblock %}
|
59
blazar_dashboard/content/hosts/tests.py
Normal file
59
blazar_dashboard/content/hosts/tests.py
Normal file
@ -0,0 +1,59 @@
|
||||
# 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 mox3.mox import IsA
|
||||
|
||||
from blazar_dashboard import api
|
||||
from blazar_dashboard.test import helpers as test
|
||||
|
||||
import logging
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
INDEX_TEMPLATE = 'admin/hosts/index.html'
|
||||
INDEX_URL = reverse('horizon:admin:hosts:index')
|
||||
|
||||
|
||||
class HostsTests(test.BaseAdminViewTests):
|
||||
@test.create_stubs({api.client: ('host_list',)})
|
||||
def test_index(self):
|
||||
hosts = self.hosts.list()
|
||||
api.client.host_list(IsA(http.HttpRequest)).AndReturn(hosts)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertTemplateUsed(res, INDEX_TEMPLATE)
|
||||
self.assertNoMessages(res)
|
||||
self.assertContains(res, 'compute-1')
|
||||
self.assertContains(res, 'compute-2')
|
||||
|
||||
@test.create_stubs({api.client: ('host_list',)})
|
||||
def test_index_no_hosts(self):
|
||||
api.client.host_list(IsA(http.HttpRequest)).AndReturn(())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertTemplateUsed(res, INDEX_TEMPLATE)
|
||||
self.assertNoMessages(res)
|
||||
self.assertContains(res, 'No items to display')
|
||||
|
||||
@test.create_stubs({api.client: ('host_list',)})
|
||||
def test_index_error(self):
|
||||
api.client.host_list(
|
||||
IsA(http.HttpRequest)
|
||||
).AndRaise(self.exceptions.blazar)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(INDEX_URL)
|
||||
self.assertTemplateUsed(res, INDEX_TEMPLATE)
|
||||
self.assertMessageCount(res, error=1)
|
20
blazar_dashboard/content/hosts/urls.py
Normal file
20
blazar_dashboard/content/hosts/urls.py
Normal file
@ -0,0 +1,20 @@
|
||||
# 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 url
|
||||
|
||||
from blazar_dashboard.content.hosts import views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
]
|
32
blazar_dashboard/content/hosts/views.py
Normal file
32
blazar_dashboard/content/hosts/views.py
Normal file
@ -0,0 +1,32 @@
|
||||
# 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 tables
|
||||
|
||||
from blazar_dashboard import api
|
||||
from blazar_dashboard.content.hosts import tables as project_tables
|
||||
|
||||
|
||||
class IndexView(tables.DataTableView):
|
||||
table_class = project_tables.HostsTable
|
||||
template_name = 'admin/hosts/index.html'
|
||||
|
||||
def get_data(self):
|
||||
try:
|
||||
hosts = api.client.host_list(self.request)
|
||||
except Exception:
|
||||
hosts = []
|
||||
msg = _('Unable to retrieve host information.')
|
||||
exceptions.handle(self.request, msg)
|
||||
return hosts
|
20
blazar_dashboard/enabled/_90_admin_reservation_panelgroup.py
Normal file
20
blazar_dashboard/enabled/_90_admin_reservation_panelgroup.py
Normal file
@ -0,0 +1,20 @@
|
||||
# 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 _
|
||||
|
||||
# The slug of the panel group to be added to HORIZON_CONFIG. Required.
|
||||
PANEL_GROUP = 'reservation'
|
||||
# The display name of the PANEL_GROUP. Required.
|
||||
PANEL_GROUP_NAME = _('Reservation')
|
||||
# The slug of the dashboard the PANEL_GROUP associated with. Required.
|
||||
PANEL_GROUP_DASHBOARD = 'admin'
|
@ -0,0 +1,21 @@
|
||||
# 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.
|
||||
|
||||
# The slug of the panel to be added to HORIZON_CONFIG. Required.
|
||||
PANEL = 'hosts'
|
||||
# The slug of the panel group the PANEL is associated with.
|
||||
PANEL_GROUP = 'reservation'
|
||||
# The slug of the dashboard the PANEL associated with. Required.
|
||||
PANEL_DASHBOARD = 'admin'
|
||||
|
||||
# Python panel class of the PANEL to be added.
|
||||
ADD_PANEL = 'blazar_dashboard.content.hosts.panel.Hosts'
|
@ -23,3 +23,9 @@ class TestCase(helpers.TestCase):
|
||||
def _setup_test_data(self):
|
||||
super(TestCase, self)._setup_test_data()
|
||||
utils.load_test_data(self)
|
||||
|
||||
|
||||
class BaseAdminViewTests(helpers.BaseAdminViewTests):
|
||||
def _setup_test_data(self):
|
||||
super(BaseAdminViewTests, self)._setup_test_data()
|
||||
utils.load_test_data(self)
|
||||
|
@ -133,9 +133,46 @@ lease_sample2 = {
|
||||
'trust_id': 'b442a580b9504ababf305bf2b4c49512'
|
||||
}
|
||||
|
||||
host_sample1 = {
|
||||
"status": None,
|
||||
"hypervisor_type": "QEMU",
|
||||
"created_at": "2017-10-01 12:00:00",
|
||||
"updated_at": None,
|
||||
"hypervisor_hostname": "compute-1",
|
||||
"memory_mb": 4096,
|
||||
"cpu_info": "{'dummy': 'true'}",
|
||||
"vcpus": 1,
|
||||
"service_name": "blazar",
|
||||
"hypervisor_version": 2005000,
|
||||
"local_gb": 128,
|
||||
"id": "1",
|
||||
"trust_id": "dummy"
|
||||
}
|
||||
|
||||
host_sample2 = {
|
||||
"status": None,
|
||||
"hypervisor_type": "QEMU",
|
||||
"created_at": "2017-10-01 12:00:00",
|
||||
"updated_at": None,
|
||||
"hypervisor_hostname": "compute-2",
|
||||
"memory_mb": 4096,
|
||||
"cpu_info": "{'dummy': 'true'}",
|
||||
"vcpus": 1,
|
||||
"service_name": "blazar",
|
||||
"hypervisor_version": 2005000,
|
||||
"local_gb": 128,
|
||||
"id": "2",
|
||||
"trust_id": "dummy"
|
||||
}
|
||||
|
||||
|
||||
def data(TEST):
|
||||
TEST.leases = utils.TestDataContainer()
|
||||
|
||||
TEST.leases.add(api.client.Lease(lease_sample1))
|
||||
TEST.leases.add(api.client.Lease(lease_sample2))
|
||||
|
||||
TEST.hosts = utils.TestDataContainer()
|
||||
|
||||
TEST.hosts.add(api.client.Host(host_sample1))
|
||||
TEST.hosts.add(api.client.Host(host_sample2))
|
||||
|
@ -40,7 +40,9 @@ Install Blazar dashboard with all dependencies in your virtual environment::
|
||||
And enable it in Horizon::
|
||||
|
||||
ln -s /path/to/blazar-dashboard/blazar_dashboard/enabled/_90_project_reservations_panelgroup.py openstack_dashboard/local/enabled
|
||||
ln -s /path/to/blazar-dashboard/blazar_dashboard/enabled/_90_admin_reservation_panelgroup.py openstack_dashboard/local/enabled
|
||||
ln -s /path/to/blazar-dashboard/blazar_dashboard/enabled/_91_project_reservations_leases_panel.py openstack_dashboard/local/enabled
|
||||
ln -s /path/to/blazar-dashboard/blazar_dashboard/enabled/_91_admin_reservation_hosts_panel.py openstack_dashboard/local/enabled
|
||||
|
||||
Start horizon and it runs with the newly enabled Blazar dashboard.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user