From ee000d7a0e6263401b379be4f045c80cf8acda55 Mon Sep 17 00:00:00 2001 From: Hiroaki Kobayashi Date: Tue, 3 Oct 2017 14:45:12 +0900 Subject: [PATCH] Add a detailed view of a Host This patch adds a detailed view of host information. Click a host name in the list view and you can see the detailed view. Partially Implements: blueprint host-operation-with-dashboard Change-Id: I6ee0286f1f79f151b9908d4952d54f5ba748b7ad --- blazar_dashboard/api/client.py | 22 ++++++++- blazar_dashboard/content/hosts/tables.py | 3 +- blazar_dashboard/content/hosts/tabs.py | 43 ++++++++++++++++ .../templates/hosts/_detail_overview.html | 49 +++++++++++++++++++ .../content/hosts/templates/hosts/detail.html | 15 ++++++ blazar_dashboard/content/hosts/tests.py | 25 ++++++++++ blazar_dashboard/content/hosts/urls.py | 1 + blazar_dashboard/content/hosts/views.py | 7 +++ .../test/test_data/blazar_data.py | 6 ++- 9 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 blazar_dashboard/content/hosts/tabs.py create mode 100644 blazar_dashboard/content/hosts/templates/hosts/_detail_overview.html create mode 100644 blazar_dashboard/content/hosts/templates/hosts/detail.html diff --git a/blazar_dashboard/api/client.py b/blazar_dashboard/api/client.py index 1fffba1..44bc417 100644 --- a/blazar_dashboard/api/client.py +++ b/blazar_dashboard/api/client.py @@ -42,12 +42,24 @@ class Lease(base.APIDictWrapper): class Host(base.APIDictWrapper): """Represents one Blazar host.""" - _attrs = ['id', 'hypervisor_hostname', 'hypervisor_type', 'vcpus', - 'cpu_info', 'memory_mb', 'local_gb'] + _attrs = ['id', 'hypervisor_hostname', 'hypervisor_type', + 'hypervisor_version', 'vcpus', 'cpu_info', 'memory_mb', + 'local_gb', 'status', 'created_at', 'updated_at', + 'service_name', 'trust_id'] def __init__(self, apiresource): super(Host, self).__init__(apiresource) + def cpu_info_dict(self): + return eval(getattr(self, 'cpu_info', "")) + + def extra_capabilities(self): + excaps = {} + for k, v in self._apidict.items(): + if k not in self._attrs: + excaps[k] = v + return excaps + @memoized def blazarclient(request): @@ -98,3 +110,9 @@ def host_list(request): """List hosts.""" hosts = blazarclient(request).host.list() return [Host(h) for h in hosts] + + +def host_get(request, host_id): + """Get a host.""" + host = blazarclient(request).host.get(host_id) + return Host(host) diff --git a/blazar_dashboard/content/hosts/tables.py b/blazar_dashboard/content/hosts/tables.py index b4347bf..fb3abdc 100644 --- a/blazar_dashboard/content/hosts/tables.py +++ b/blazar_dashboard/content/hosts/tables.py @@ -16,7 +16,8 @@ from horizon.templatetags import sizeformat class HostsTable(tables.DataTable): - name = tables.Column("hypervisor_hostname", verbose_name=_("Host name")) + name = tables.Column("hypervisor_hostname", verbose_name=_("Host name"), + link="horizon:admin:hosts:detail") vcpus = tables.Column("vcpus", verbose_name=_("VCPUs")) memory_mb = tables.Column("memory_mb", verbose_name=_("RAM"), filters=(sizeformat.mb_float_format,)) diff --git a/blazar_dashboard/content/hosts/tabs.py b/blazar_dashboard/content/hosts/tabs.py new file mode 100644 index 0000000..7babd96 --- /dev/null +++ b/blazar_dashboard/content/hosts/tabs.py @@ -0,0 +1,43 @@ +# Copyright 2014 Intel Corporation +# 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. + +from django.core.urlresolvers import reverse +from django.utils.translation import ugettext_lazy as _ +from horizon import exceptions +from horizon import tabs + +from blazar_dashboard.api import client + + +class OverviewTab(tabs.Tab): + name = _("Overview") + slug = "overview" + template_name = "admin/hosts/_detail_overview.html" + + def get_context_data(self, request): + host_id = self.tab_group.kwargs['host_id'] + try: + host = client.host_get(self.request, host_id) + except Exception: + redirect = reverse('horizon:admin:hosts:index') + msg = _('Unable to retrieve host details.') + exceptions.handle(request, msg, redirect=redirect) + + return {'host': host} + + +class HostDetailTabs(tabs.TabGroup): + slug = "host_details" + tabs = (OverviewTab,) diff --git a/blazar_dashboard/content/hosts/templates/hosts/_detail_overview.html b/blazar_dashboard/content/hosts/templates/hosts/_detail_overview.html new file mode 100644 index 0000000..14f134a --- /dev/null +++ b/blazar_dashboard/content/hosts/templates/hosts/_detail_overview.html @@ -0,0 +1,49 @@ +{% load i18n sizeformat %} + +
+
+
+
{% trans "Host name" %}
+
{{ host.hypervisor_hostname }}
+
{% trans "Id" %}
+
{{ host.id }}
+
{% trans "Status" %}
+
{{ host.status }}
{% trans "Created at" %}
+
{{ host.created_at|parse_isotime|date:"Y-m-d H:i T"|default:"-" }}
+
{% trans "Updated at" %}
+
{{ host.updated_at|parse_isotime|date:"Y-m-d H:i T"|default:"-" }}
+
+
+ +
+

{% trans "CPU Specs" %}

+
+
+
{% trans "VCPUs" %}
+
{{ host.vcpus|default:_("None") }}
+ {% for key, value in host.cpu_info_dict.items %} +
{{ key }}
+
{{ value }}
+ {% endfor %} +
+
+ +
+

{% trans "Other Specs" %}

+
+
+
{% trans "RAM" %}
+
{{ host.memory_mb|mb_float_format }}
+
{% trans "Local storage" %}
+
{{ host.local_gb|diskgbformat }}
+
{% trans "Hypervisor type" %}
+
{{ host.hypervisor_type }}
+
{% trans "Hypervisor version" %}
+
{{ host.hypervisor_version }}
+ {% for key, value in host.extra_capabilities.items %} +
{{ key }}
+
{{ value }}
+ {% endfor %} +
+
+
diff --git a/blazar_dashboard/content/hosts/templates/hosts/detail.html b/blazar_dashboard/content/hosts/templates/hosts/detail.html new file mode 100644 index 0000000..b388f55 --- /dev/null +++ b/blazar_dashboard/content/hosts/templates/hosts/detail.html @@ -0,0 +1,15 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Host Details"%}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Host Details") %} +{% endblock page_header %} + +{% block main %} +
+
+ {{ tab_group.render }} +
+
+{% endblock %} diff --git a/blazar_dashboard/content/hosts/tests.py b/blazar_dashboard/content/hosts/tests.py index d44351b..64c8c8e 100644 --- a/blazar_dashboard/content/hosts/tests.py +++ b/blazar_dashboard/content/hosts/tests.py @@ -22,6 +22,8 @@ LOG = logging.getLogger(__name__) INDEX_TEMPLATE = 'admin/hosts/index.html' INDEX_URL = reverse('horizon:admin:hosts:index') +DETAIL_TEMPLATE = 'admin/hosts/detail.html' +DETAIL_URL_BASE = 'horizon:admin:hosts:detail' class HostsTests(test.BaseAdminViewTests): @@ -57,3 +59,26 @@ class HostsTests(test.BaseAdminViewTests): res = self.client.get(INDEX_URL) self.assertTemplateUsed(res, INDEX_TEMPLATE) self.assertMessageCount(res, error=1) + + @test.create_stubs({api.client: ('host_get',)}) + def test_host_detail(self): + host = self.hosts.get(hypervisor_hostname='compute-1') + api.client.host_get(IsA(http.HttpRequest), + host['id']).AndReturn(host) + self.mox.ReplayAll() + + res = self.client.get(reverse(DETAIL_URL_BASE, args=[host['id']])) + self.assertTemplateUsed(res, DETAIL_TEMPLATE) + self.assertContains(res, 'compute-1') + self.assertContains(res, 'ex1') + + @test.create_stubs({api.client: ('host_get',)}) + def test_host_detail_error(self): + api.client.host_get(IsA(http.HttpRequest), + 'invalid').AndRaise(self.exceptions.blazar) + self.mox.ReplayAll() + + res = self.client.get(reverse(DETAIL_URL_BASE, args=['invalid'])) + self.assertTemplateNotUsed(res, DETAIL_TEMPLATE) + self.assertMessageCount(error=1) + self.assertRedirectsNoFollow(res, INDEX_URL) diff --git a/blazar_dashboard/content/hosts/urls.py b/blazar_dashboard/content/hosts/urls.py index 69dfc69..f7886cf 100644 --- a/blazar_dashboard/content/hosts/urls.py +++ b/blazar_dashboard/content/hosts/urls.py @@ -17,4 +17,5 @@ from blazar_dashboard.content.hosts import views urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), + url(r'^(?P[^/]+)/$', views.DetailView.as_view(), name='detail') ] diff --git a/blazar_dashboard/content/hosts/views.py b/blazar_dashboard/content/hosts/views.py index 7e57dd2..f8b6989 100644 --- a/blazar_dashboard/content/hosts/views.py +++ b/blazar_dashboard/content/hosts/views.py @@ -13,9 +13,11 @@ from django.utils.translation import ugettext_lazy as _ from horizon import exceptions from horizon import tables +from horizon import tabs from blazar_dashboard import api from blazar_dashboard.content.hosts import tables as project_tables +from blazar_dashboard.content.hosts import tabs as project_tabs class IndexView(tables.DataTableView): @@ -30,3 +32,8 @@ class IndexView(tables.DataTableView): msg = _('Unable to retrieve host information.') exceptions.handle(self.request, msg) return hosts + + +class DetailView(tabs.TabView): + tab_group_class = project_tabs.HostDetailTabs + template_name = 'admin/hosts/detail.html' diff --git a/blazar_dashboard/test/test_data/blazar_data.py b/blazar_dashboard/test/test_data/blazar_data.py index 1b795ef..bc32d82 100644 --- a/blazar_dashboard/test/test_data/blazar_data.py +++ b/blazar_dashboard/test/test_data/blazar_data.py @@ -146,7 +146,8 @@ host_sample1 = { "hypervisor_version": 2005000, "local_gb": 128, "id": "1", - "trust_id": "dummy" + "trust_id": "dummy", + "ex1": "dummy" } host_sample2 = { @@ -162,7 +163,8 @@ host_sample2 = { "hypervisor_version": 2005000, "local_gb": 128, "id": "2", - "trust_id": "dummy" + "trust_id": "dummy", + "ex2": "dummy" }