adding hypervisors panel to admin dashboard

This commit adds a new panel "Hypervisors" to the system panel in
the admin dashboard listing all registered hypervisors hosts by
using the os-hypervisors extension of the Nova API.

fixes bug #1197763

Change-Id: I3f9a7858342c3592521b7fa8ecf17e2fb5af6cda
This commit is contained in:
Christian Berendt 2013-07-04 12:28:34 +02:00
parent 8bca5a4705
commit f678336cd7
10 changed files with 251 additions and 1 deletions

View File

@ -575,6 +575,10 @@ def instance_volumes_list(request, instance_id):
return volumes return volumes
def hypervisor_list(request):
return novaclient(request).hypervisors.list()
def tenant_absolute_limits(request, reserved=False): def tenant_absolute_limits(request, reserved=False):
limits = novaclient(request).limits.get(reserved=reserved).absolute limits = novaclient(request).limits.get(reserved=reserved).absolute
limits_dict = {} limits_dict = {}

View File

@ -22,7 +22,7 @@ import horizon
class SystemPanels(horizon.PanelGroup): class SystemPanels(horizon.PanelGroup):
slug = "admin" slug = "admin"
name = _("System Panel") name = _("System Panel")
panels = ('overview', 'instances', 'volumes', 'flavors', panels = ('overview', 'hypervisors', 'instances', 'volumes', 'flavors',
'images', 'domains', 'projects', 'users', 'groups', 'images', 'domains', 'projects', 'users', 'groups',
'roles', 'networks', 'routers', 'info') 'roles', 'networks', 'routers', 'info')

View File

@ -0,0 +1,29 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 B1 Systems GmbH
#
# 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 Hypervisors(horizon.Panel):
name = _("Hypervisors")
slug = 'hypervisors'
permissions = ('openstack.roles.admin',)
dashboard.Admin.register(Hypervisors)

View File

@ -0,0 +1,75 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 B1 Systems GmbH
#
# 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_lazy as _
from horizon import tables
LOG = logging.getLogger(__name__)
def get_memory(hypervisor):
return _("%s MB") % hypervisor.memory_mb
def get_memory_used(hypervisor):
return _("%s MB") % hypervisor.memory_mb_used
def get_local(hypervisor):
return _("%s GB") % hypervisor.local_gb
def get_local_used(hypervisor):
return _("%s GB") % hypervisor.local_gb_used
class AdminHypervisorsTable(tables.DataTable):
hypervisor_hostname = tables.Column("hypervisor_hostname",
verbose_name=_("Hostname"))
hypervisor_type = tables.Column("hypervisor_type",
verbose_name=_("Type"))
vcpus = tables.Column("vcpus",
verbose_name=_("VCPUs (total)"))
vcpus_used = tables.Column("vcpus_used",
verbose_name=_("VCPUs (used)"))
memory = tables.Column(get_memory,
verbose_name=_("RAM (total)"),
attrs={'data-type': 'size'})
memory_used = tables.Column(get_memory_used,
verbose_name=_("RAM (used)"),
attrs={'data-type': 'size'})
local = tables.Column(get_local,
verbose_name=_("Storage (total)"),
attrs={'data-type': 'size'})
local_used = tables.Column(get_local_used,
verbose_name=_("Storage (used)"),
attrs={'data-type': 'size'})
running_vms = tables.Column("running_vms",
verbose_name=_("Instances"))
class Meta:
name = "hypervisors"
verbose_name = _("Hypervisors")

View File

@ -0,0 +1,11 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Hypervisors" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("All Hypervisors") %}
{% endblock page_header %}
{% block main %}
{{ table.render }}
{% endblock %}

View File

@ -0,0 +1,34 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 B1 Systems GmbH
#
# 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 mox import IsA
from openstack_dashboard import api
from openstack_dashboard.test import helpers as test
class HypervisorViewTest(test.BaseAdminViewTests):
@test.create_stubs({api.nova: ('hypervisor_list',)})
def test_index(self):
hypervisors = self.hypervisors.list()
api.nova.hypervisor_list(IsA(http.HttpRequest)).AndReturn(hypervisors)
self.mox.ReplayAll()
res = self.client.get(reverse('horizon:admin:hypervisors:index'))
self.assertTemplateUsed(res, 'admin/hypervisors/index.html')
self.assertItemsEqual(res.context['table'].data, hypervisors)

View File

@ -0,0 +1,26 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 B1 Systems GmbH
#
# 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.defaults import patterns
from django.conf.urls.defaults import url
from .views import AdminIndexView
urlpatterns = patterns(
'openstack_dashboard.dashboards.admin.hypervisors.views',
url(r'^$', AdminIndexView.as_view(), name='index')
)

View File

@ -0,0 +1,42 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 B1 Systems GmbH
#
# 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_lazy as _
from horizon import exceptions
from horizon import tables
from openstack_dashboard import api
from openstack_dashboard.dashboards.admin.hypervisors.tables import \
AdminHypervisorsTable
LOG = logging.getLogger(__name__)
class AdminIndexView(tables.DataTableView):
table_class = AdminHypervisorsTable
template_name = 'admin/hypervisors/index.html'
def get_data(self):
hypervisors = []
try:
hypervisors = api.nova.hypervisor_list(self.request)
except:
exceptions.handle(self.request,
_('Unable to retrieve hypervisor list.'))
return hypervisors

View File

@ -19,6 +19,7 @@ from novaclient.v1_1 import availability_zones
from novaclient.v1_1 import certs from novaclient.v1_1 import certs
from novaclient.v1_1 import flavors from novaclient.v1_1 import flavors
from novaclient.v1_1 import floating_ips from novaclient.v1_1 import floating_ips
from novaclient.v1_1 import hypervisors
from novaclient.v1_1 import keypairs from novaclient.v1_1 import keypairs
from novaclient.v1_1 import quotas from novaclient.v1_1 import quotas
from novaclient.v1_1 import security_group_rules as rules from novaclient.v1_1 import security_group_rules as rules
@ -162,6 +163,7 @@ def data(TEST):
TEST.volume_snapshots = TestDataContainer() TEST.volume_snapshots = TestDataContainer()
TEST.volume_types = TestDataContainer() TEST.volume_types = TestDataContainer()
TEST.availability_zones = TestDataContainer() TEST.availability_zones = TestDataContainer()
TEST.hypervisors = TestDataContainer()
# Data return by novaclient. # Data return by novaclient.
# It is used if API layer does data conversion. # It is used if API layer does data conversion.
@ -483,3 +485,30 @@ def data(TEST):
{'zoneName': 'nova', 'zoneState': {'available': True}} {'zoneName': 'nova', 'zoneState': {'available': True}}
) )
) )
# hypervisors
hypervisor_1 = hypervisors.Hypervisor(hypervisors.HypervisorManager(None),
{
"service": {"host": "devstack001", "id": 3},
"vcpus_used": 1,
"hypervisor_type": "QEMU",
"local_gb_used": 20,
"hypervisor_hostname": "devstack001",
"memory_mb_used": 1500,
"memory_mb": 2000,
"current_workload": 0,
"vcpus": 1,
"cpu_info": '{"vendor": "Intel", "model": "core2duo",'
'"arch": "x86_64", "features": ["lahf_lm"'
', "rdtscp"], "topology": {"cores": 1, "t'
'hreads": 1, "sockets": 1}}',
"running_vms": 1,
"free_disk_gb": 9,
"hypervisor_version": 1002000,
"disk_available_least": 6,
"local_gb": 29,
"free_ram_mb": 500,
"id": 1
}
)
TEST.hypervisors.add(hypervisor_1)