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:
Hiroaki Kobayashi 2017-10-02 17:11:43 +09:00
parent 0d6c547552
commit 6afd13a148
13 changed files with 272 additions and 0 deletions

View File

@ -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]

View 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"

View 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")

View 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 %}

View 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)

View 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'),
]

View 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

View 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'

View File

@ -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'

View File

@ -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)

View File

@ -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))

View File

@ -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.