Add hypervisor information extension.
Adds support for a new nova extension for getting information about hypervisors (as opposed to compute hosts), including a list of hypervisors matching a regular expression (database regular expression, i.e., %'s) and a list of hypervisors with the list of instances living on those hypervisors. Change-Id: I7353991ffbf484da175a0912ee46e80f623e230f
This commit is contained in:
parent
08cf0bf95e
commit
a11788515e
|
@ -7,6 +7,7 @@ from novaclient.v1_1 import floating_ip_dns
|
||||||
from novaclient.v1_1 import floating_ips
|
from novaclient.v1_1 import floating_ips
|
||||||
from novaclient.v1_1 import floating_ip_pools
|
from novaclient.v1_1 import floating_ip_pools
|
||||||
from novaclient.v1_1 import hosts
|
from novaclient.v1_1 import hosts
|
||||||
|
from novaclient.v1_1 import hypervisors
|
||||||
from novaclient.v1_1 import images
|
from novaclient.v1_1 import images
|
||||||
from novaclient.v1_1 import keypairs
|
from novaclient.v1_1 import keypairs
|
||||||
from novaclient.v1_1 import limits
|
from novaclient.v1_1 import limits
|
||||||
|
@ -76,6 +77,7 @@ class Client(object):
|
||||||
virtual_interfaces.VirtualInterfaceManager(self)
|
virtual_interfaces.VirtualInterfaceManager(self)
|
||||||
self.aggregates = aggregates.AggregateManager(self)
|
self.aggregates = aggregates.AggregateManager(self)
|
||||||
self.hosts = hosts.HostManager(self)
|
self.hosts = hosts.HostManager(self)
|
||||||
|
self.hypervisors = hypervisors.HypervisorManager(self)
|
||||||
|
|
||||||
# Add in any extensions...
|
# Add in any extensions...
|
||||||
if extensions:
|
if extensions:
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
# Copyright 2012 OpenStack LLC.
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Hypervisors interface (1.1 extension).
|
||||||
|
"""
|
||||||
|
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
from novaclient import base
|
||||||
|
|
||||||
|
|
||||||
|
class Hypervisor(base.Resource):
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Hypervisor: %s>" % self.id
|
||||||
|
|
||||||
|
|
||||||
|
class HypervisorManager(base.Manager):
|
||||||
|
resource_class = Hypervisor
|
||||||
|
|
||||||
|
def list(self, detailed=True):
|
||||||
|
"""
|
||||||
|
Get a list of hypervisors.
|
||||||
|
"""
|
||||||
|
detail = ""
|
||||||
|
if detailed:
|
||||||
|
detail = "/detail"
|
||||||
|
return self._list('/os-hypervisors%s' % detail, 'hypervisors')
|
||||||
|
|
||||||
|
def search(self, hypervisor_match, servers=False):
|
||||||
|
"""
|
||||||
|
Get a list of matching hypervisors.
|
||||||
|
|
||||||
|
:param servers: If True, server information is also retrieved.
|
||||||
|
"""
|
||||||
|
target = 'servers' if servers else 'search'
|
||||||
|
url = ('/os-hypervisors/%s/%s' %
|
||||||
|
(urllib.quote(hypervisor_match, safe=''), target))
|
||||||
|
return self._list(url, 'hypervisors')
|
||||||
|
|
||||||
|
def get(self, hypervisor):
|
||||||
|
"""
|
||||||
|
Get a specific hypervisor.
|
||||||
|
"""
|
||||||
|
return self._get("/os-hypervisors/%s" % base.getid(hypervisor),
|
||||||
|
"hypervisor")
|
|
@ -1649,6 +1649,60 @@ def do_host_action(cs, args):
|
||||||
utils.print_list([result], ['HOST', 'power_action'])
|
utils.print_list([result], ['HOST', 'power_action'])
|
||||||
|
|
||||||
|
|
||||||
|
@utils.arg('--matching', metavar='<hostname>', default=None,
|
||||||
|
help='List hypervisors matching the given <hostname>.')
|
||||||
|
def do_hypervisor_list(cs, args):
|
||||||
|
"""List hypervisors."""
|
||||||
|
columns = ['ID', 'Hypervisor hostname']
|
||||||
|
if args.matching:
|
||||||
|
utils.print_list(cs.hypervisors.search(args.matching), columns)
|
||||||
|
else:
|
||||||
|
# Since we're not outputting detail data, choose
|
||||||
|
# detailed=False for server-side efficiency
|
||||||
|
utils.print_list(cs.hypervisors.list(False), columns)
|
||||||
|
|
||||||
|
|
||||||
|
@utils.arg('hostname', metavar='<hostname>',
|
||||||
|
help='The hypervisor hostname (or pattern) to search for.')
|
||||||
|
def do_hypervisor_servers(cs, args):
|
||||||
|
"""List instances belonging to specific hypervisors."""
|
||||||
|
hypers = cs.hypervisors.search(args.hostname, servers=True)
|
||||||
|
|
||||||
|
class InstanceOnHyper(object):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.__dict__.update(kwargs)
|
||||||
|
|
||||||
|
# Massage the result into a list to be displayed
|
||||||
|
instances = []
|
||||||
|
for hyper in hypers:
|
||||||
|
hyper_host = hyper.hypervisor_hostname
|
||||||
|
hyper_id = hyper.id
|
||||||
|
instances.extend([InstanceOnHyper(id=serv['uuid'],
|
||||||
|
name=serv['name'],
|
||||||
|
hypervisor_hostname=hyper_host,
|
||||||
|
hypervisor_id=hyper_id)
|
||||||
|
for serv in hyper.servers])
|
||||||
|
|
||||||
|
# Output the data
|
||||||
|
utils.print_list(instances, ['ID', 'Name', 'Hypervisor ID',
|
||||||
|
'Hypervisor Hostname'])
|
||||||
|
|
||||||
|
|
||||||
|
@utils.arg('hypervisor_id', metavar='<hypervisor_id>',
|
||||||
|
help='The ID of the hypervisor to show the details of.')
|
||||||
|
def do_hypervisor_show(cs, args):
|
||||||
|
"""Display the details of the specified hypervisor."""
|
||||||
|
hyper = utils.find_resource(cs.hypervisors, args.hypervisor_id)
|
||||||
|
|
||||||
|
# Build up the dict
|
||||||
|
info = hyper._info.copy()
|
||||||
|
info['service_id'] = info['service']['id']
|
||||||
|
info['service_host'] = info['service']['host']
|
||||||
|
del info['service']
|
||||||
|
|
||||||
|
utils.print_dict(info)
|
||||||
|
|
||||||
|
|
||||||
def do_endpoints(cs, _args):
|
def do_endpoints(cs, _args):
|
||||||
"""Discover endpoints that get returned from the authenticate services"""
|
"""Discover endpoints that get returned from the authenticate services"""
|
||||||
catalog = cs.client.service_catalog.catalog
|
catalog = cs.client.service_catalog.catalog
|
||||||
|
|
|
@ -822,3 +822,89 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||||
result = {'host': 'dummy'}
|
result = {'host': 'dummy'}
|
||||||
result.update(body)
|
result.update(body)
|
||||||
return (200, result)
|
return (200, result)
|
||||||
|
|
||||||
|
def get_os_hypervisors(self, **kw):
|
||||||
|
return (200, {"hypervisors": [
|
||||||
|
{'id': 1234, 'hypervisor_hostname': 'hyper1'},
|
||||||
|
{'id': 5678, 'hypervisor_hostname': 'hyper2'},
|
||||||
|
]})
|
||||||
|
|
||||||
|
def get_os_hypervisors_detail(self, **kw):
|
||||||
|
return (200, {"hypervisors": [
|
||||||
|
{'id': 1234,
|
||||||
|
'service': {'id': 1, 'host': 'compute1'},
|
||||||
|
'vcpus': 4,
|
||||||
|
'memory_mb': 10 * 1024,
|
||||||
|
'local_gb': 250,
|
||||||
|
'vcpus_used': 2,
|
||||||
|
'memory_mb_used': 5 * 1024,
|
||||||
|
'local_gb_used': 125,
|
||||||
|
'hypervisor_type': "xen",
|
||||||
|
'hypervisor_version': 3,
|
||||||
|
'hypervisor_hostname': "hyper1",
|
||||||
|
'free_ram_mb': 5 * 1024,
|
||||||
|
'free_disk_gb': 125,
|
||||||
|
'current_workload': 2,
|
||||||
|
'running_vms': 2,
|
||||||
|
'cpu_info': 'cpu_info',
|
||||||
|
'disk_available_least': 100},
|
||||||
|
{'id': 2,
|
||||||
|
'service': {'id': 2, 'host': "compute2"},
|
||||||
|
'vcpus': 4,
|
||||||
|
'memory_mb': 10 * 1024,
|
||||||
|
'local_gb': 250,
|
||||||
|
'vcpus_used': 2,
|
||||||
|
'memory_mb_used': 5 * 1024,
|
||||||
|
'local_gb_used': 125,
|
||||||
|
'hypervisor_type': "xen",
|
||||||
|
'hypervisor_version': 3,
|
||||||
|
'hypervisor_hostname': "hyper2",
|
||||||
|
'free_ram_mb': 5 * 1024,
|
||||||
|
'free_disk_gb': 125,
|
||||||
|
'current_workload': 2,
|
||||||
|
'running_vms': 2,
|
||||||
|
'cpu_info': 'cpu_info',
|
||||||
|
'disk_available_least': 100}
|
||||||
|
]})
|
||||||
|
|
||||||
|
def get_os_hypervisors_hyper_search(self, **kw):
|
||||||
|
return (200, {'hypervisors': [
|
||||||
|
{'id': 1234, 'hypervisor_hostname': 'hyper1'},
|
||||||
|
{'id': 5678, 'hypervisor_hostname': 'hyper2'}
|
||||||
|
]})
|
||||||
|
|
||||||
|
def get_os_hypervisors_hyper_servers(self, **kw):
|
||||||
|
return (200, {'hypervisors': [
|
||||||
|
{'id': 1234,
|
||||||
|
'hypervisor_hostname': 'hyper1',
|
||||||
|
'servers': [
|
||||||
|
{'name': 'inst1', 'uuid': 'uuid1'},
|
||||||
|
{'name': 'inst2', 'uuid': 'uuid2'}
|
||||||
|
]},
|
||||||
|
{'id': 5678,
|
||||||
|
'hypervisor_hostname': 'hyper2',
|
||||||
|
'servers': [
|
||||||
|
{'name': 'inst3', 'uuid': 'uuid3'},
|
||||||
|
{'name': 'inst4', 'uuid': 'uuid4'}
|
||||||
|
]}
|
||||||
|
]})
|
||||||
|
|
||||||
|
def get_os_hypervisors_1234(self, **kw):
|
||||||
|
return (200, {'hypervisor':
|
||||||
|
{'id': 1234,
|
||||||
|
'service': {'id': 1, 'host': 'compute1'},
|
||||||
|
'vcpus': 4,
|
||||||
|
'memory_mb': 10 * 1024,
|
||||||
|
'local_gb': 250,
|
||||||
|
'vcpus_used': 2,
|
||||||
|
'memory_mb_used': 5 * 1024,
|
||||||
|
'local_gb_used': 125,
|
||||||
|
'hypervisor_type': "xen",
|
||||||
|
'hypervisor_version': 3,
|
||||||
|
'hypervisor_hostname': "hyper1",
|
||||||
|
'free_ram_mb': 5 * 1024,
|
||||||
|
'free_disk_gb': 125,
|
||||||
|
'current_workload': 2,
|
||||||
|
'running_vms': 2,
|
||||||
|
'cpu_info': 'cpu_info',
|
||||||
|
'disk_available_least': 100}})
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
# Copyright 2012 OpenStack LLC.
|
||||||
|
# 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 tests import utils
|
||||||
|
from tests.v1_1 import fakes
|
||||||
|
|
||||||
|
|
||||||
|
cs = fakes.FakeClient()
|
||||||
|
|
||||||
|
|
||||||
|
class HypervisorsTest(utils.TestCase):
|
||||||
|
def compare_to_expected(self, expected, hyper):
|
||||||
|
for key, value in expected.items():
|
||||||
|
self.assertEqual(getattr(hyper, key), value)
|
||||||
|
|
||||||
|
def test_hypervisor_index(self):
|
||||||
|
expected = [
|
||||||
|
dict(id=1234, hypervisor_hostname='hyper1'),
|
||||||
|
dict(id=5678, hypervisor_hostname='hyper2'),
|
||||||
|
]
|
||||||
|
|
||||||
|
result = cs.hypervisors.list(False)
|
||||||
|
cs.assert_called('GET', '/os-hypervisors')
|
||||||
|
|
||||||
|
for idx, hyper in enumerate(result):
|
||||||
|
self.compare_to_expected(expected[idx], hyper)
|
||||||
|
|
||||||
|
def test_hypervisor_detail(self):
|
||||||
|
expected = [
|
||||||
|
dict(id=1234,
|
||||||
|
service=dict(id=1, host='compute1'),
|
||||||
|
vcpus=4,
|
||||||
|
memory_mb=10 * 1024,
|
||||||
|
local_gb=250,
|
||||||
|
vcpus_used=2,
|
||||||
|
memory_mb_used=5 * 1024,
|
||||||
|
local_gb_used=125,
|
||||||
|
hypervisor_type="xen",
|
||||||
|
hypervisor_version=3,
|
||||||
|
hypervisor_hostname="hyper1",
|
||||||
|
free_ram_mb=5 * 1024,
|
||||||
|
free_disk_gb=125,
|
||||||
|
current_workload=2,
|
||||||
|
running_vms=2,
|
||||||
|
cpu_info='cpu_info',
|
||||||
|
disk_available_least=100),
|
||||||
|
dict(id=2,
|
||||||
|
service=dict(id=2, host="compute2"),
|
||||||
|
vcpus=4,
|
||||||
|
memory_mb=10 * 1024,
|
||||||
|
local_gb=250,
|
||||||
|
vcpus_used=2,
|
||||||
|
memory_mb_used=5 * 1024,
|
||||||
|
local_gb_used=125,
|
||||||
|
hypervisor_type="xen",
|
||||||
|
hypervisor_version=3,
|
||||||
|
hypervisor_hostname="hyper2",
|
||||||
|
free_ram_mb=5 * 1024,
|
||||||
|
free_disk_gb=125,
|
||||||
|
current_workload=2,
|
||||||
|
running_vms=2,
|
||||||
|
cpu_info='cpu_info',
|
||||||
|
disk_available_least=100)]
|
||||||
|
|
||||||
|
result = cs.hypervisors.list()
|
||||||
|
cs.assert_called('GET', '/os-hypervisors/detail')
|
||||||
|
|
||||||
|
for idx, hyper in enumerate(result):
|
||||||
|
self.compare_to_expected(expected[idx], hyper)
|
||||||
|
|
||||||
|
def test_hypervisor_search(self):
|
||||||
|
expected = [
|
||||||
|
dict(id=1234, hypervisor_hostname='hyper1'),
|
||||||
|
dict(id=5678, hypervisor_hostname='hyper2'),
|
||||||
|
]
|
||||||
|
|
||||||
|
result = cs.hypervisors.search('hyper')
|
||||||
|
cs.assert_called('GET', '/os-hypervisors/hyper/search')
|
||||||
|
|
||||||
|
for idx, hyper in enumerate(result):
|
||||||
|
self.compare_to_expected(expected[idx], hyper)
|
||||||
|
|
||||||
|
def test_hypervisor_servers(self):
|
||||||
|
expected = [
|
||||||
|
dict(id=1234,
|
||||||
|
hypervisor_hostname='hyper1',
|
||||||
|
servers=[
|
||||||
|
dict(name='inst1', uuid='uuid1'),
|
||||||
|
dict(name='inst2', uuid='uuid2')]),
|
||||||
|
dict(id=5678,
|
||||||
|
hypervisor_hostname='hyper2',
|
||||||
|
servers=[
|
||||||
|
dict(name='inst3', uuid='uuid3'),
|
||||||
|
dict(name='inst4', uuid='uuid4')]),
|
||||||
|
]
|
||||||
|
|
||||||
|
result = cs.hypervisors.search('hyper', True)
|
||||||
|
cs.assert_called('GET', '/os-hypervisors/hyper/servers')
|
||||||
|
|
||||||
|
for idx, hyper in enumerate(result):
|
||||||
|
self.compare_to_expected(expected[idx], hyper)
|
||||||
|
|
||||||
|
def test_hypervisor_get(self):
|
||||||
|
expected = dict(
|
||||||
|
id=1234,
|
||||||
|
service=dict(id=1, host='compute1'),
|
||||||
|
vcpus=4,
|
||||||
|
memory_mb=10 * 1024,
|
||||||
|
local_gb=250,
|
||||||
|
vcpus_used=2,
|
||||||
|
memory_mb_used=5 * 1024,
|
||||||
|
local_gb_used=125,
|
||||||
|
hypervisor_type="xen",
|
||||||
|
hypervisor_version=3,
|
||||||
|
hypervisor_hostname="hyper1",
|
||||||
|
free_ram_mb=5 * 1024,
|
||||||
|
free_disk_gb=125,
|
||||||
|
current_workload=2,
|
||||||
|
running_vms=2,
|
||||||
|
cpu_info='cpu_info',
|
||||||
|
disk_available_least=100)
|
||||||
|
|
||||||
|
result = cs.hypervisors.get(1234)
|
||||||
|
cs.assert_called('GET', '/os-hypervisors/1234')
|
||||||
|
|
||||||
|
self.compare_to_expected(expected, result)
|
|
@ -476,6 +476,22 @@ class ShellTest(utils.TestCase):
|
||||||
self.run_command('host-action sample-host --action reboot')
|
self.run_command('host-action sample-host --action reboot')
|
||||||
self.assert_called('GET', '/os-hosts/sample-host/reboot')
|
self.assert_called('GET', '/os-hosts/sample-host/reboot')
|
||||||
|
|
||||||
|
def test_hypervisor_list(self):
|
||||||
|
self.run_command('hypervisor-list')
|
||||||
|
self.assert_called('GET', '/os-hypervisors')
|
||||||
|
|
||||||
|
def test_hypervisor_list_matching(self):
|
||||||
|
self.run_command('hypervisor-list --matching hyper')
|
||||||
|
self.assert_called('GET', '/os-hypervisors/hyper/search')
|
||||||
|
|
||||||
|
def test_hypervisor_servers(self):
|
||||||
|
self.run_command('hypervisor-servers hyper')
|
||||||
|
self.assert_called('GET', '/os-hypervisors/hyper/servers')
|
||||||
|
|
||||||
|
def test_hypervisor_show(self):
|
||||||
|
self.run_command('hypervisor-show 1234')
|
||||||
|
self.assert_called('GET', '/os-hypervisors/1234')
|
||||||
|
|
||||||
def test_quota_show(self):
|
def test_quota_show(self):
|
||||||
self.run_command('quota-show test')
|
self.run_command('quota-show test')
|
||||||
self.assert_called('GET', '/os-quota-sets/test')
|
self.assert_called('GET', '/os-quota-sets/test')
|
||||||
|
|
Loading…
Reference in New Issue