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:
parent
8bca5a4705
commit
f678336cd7
@ -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 = {}
|
||||||
|
@ -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')
|
||||||
|
|
||||||
|
29
openstack_dashboard/dashboards/admin/hypervisors/panel.py
Normal file
29
openstack_dashboard/dashboards/admin/hypervisors/panel.py
Normal 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)
|
75
openstack_dashboard/dashboards/admin/hypervisors/tables.py
Normal file
75
openstack_dashboard/dashboards/admin/hypervisors/tables.py
Normal 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")
|
@ -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 %}
|
34
openstack_dashboard/dashboards/admin/hypervisors/tests.py
Normal file
34
openstack_dashboard/dashboards/admin/hypervisors/tests.py
Normal 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)
|
26
openstack_dashboard/dashboards/admin/hypervisors/urls.py
Normal file
26
openstack_dashboard/dashboards/admin/hypervisors/urls.py
Normal 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')
|
||||||
|
)
|
42
openstack_dashboard/dashboards/admin/hypervisors/views.py
Normal file
42
openstack_dashboard/dashboards/admin/hypervisors/views.py
Normal 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
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user