summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin L. Mitchell <kevin.mitchell@rackspace.com>2012-06-27 18:45:28 -0500
committerKevin L. Mitchell <kevin.mitchell@rackspace.com>2012-06-29 12:21:19 -0500
commita11788515e800a95d5b83448c2a9403eed509bdf (patch)
treee4b1d211815f36284c155d14b1aee30842a77fc5
parent08cf0bf95ef99a0e39122ef99eb559e2d739716d (diff)
downloadpython-novaclient-2.6.10.tar.gz
Add hypervisor information extension.2.6.10
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
-rw-r--r--novaclient/v1_1/client.py2
-rw-r--r--novaclient/v1_1/hypervisors.py58
-rw-r--r--novaclient/v1_1/shell.py54
-rw-r--r--tests/v1_1/fakes.py86
-rw-r--r--tests/v1_1/test_hypervisors.py138
-rw-r--r--tests/v1_1/test_shell.py16
6 files changed, 354 insertions, 0 deletions
diff --git a/novaclient/v1_1/client.py b/novaclient/v1_1/client.py
index 15364089..ba3bf7ae 100644
--- a/novaclient/v1_1/client.py
+++ b/novaclient/v1_1/client.py
@@ -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_ip_pools
from novaclient.v1_1 import hosts
+from novaclient.v1_1 import hypervisors
from novaclient.v1_1 import images
from novaclient.v1_1 import keypairs
from novaclient.v1_1 import limits
@@ -76,6 +77,7 @@ class Client(object):
virtual_interfaces.VirtualInterfaceManager(self)
self.aggregates = aggregates.AggregateManager(self)
self.hosts = hosts.HostManager(self)
+ self.hypervisors = hypervisors.HypervisorManager(self)
# Add in any extensions...
if extensions:
diff --git a/novaclient/v1_1/hypervisors.py b/novaclient/v1_1/hypervisors.py
new file mode 100644
index 00000000..9f56ae05
--- /dev/null
+++ b/novaclient/v1_1/hypervisors.py
@@ -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")
diff --git a/novaclient/v1_1/shell.py b/novaclient/v1_1/shell.py
index 8d92e249..faf9d655 100644
--- a/novaclient/v1_1/shell.py
+++ b/novaclient/v1_1/shell.py
@@ -1649,6 +1649,60 @@ def do_host_action(cs, args):
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):
"""Discover endpoints that get returned from the authenticate services"""
catalog = cs.client.service_catalog.catalog
diff --git a/tests/v1_1/fakes.py b/tests/v1_1/fakes.py
index f2112f23..4a7c3aa1 100644
--- a/tests/v1_1/fakes.py
+++ b/tests/v1_1/fakes.py
@@ -822,3 +822,89 @@ class FakeHTTPClient(base_client.HTTPClient):
result = {'host': 'dummy'}
result.update(body)
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}})
diff --git a/tests/v1_1/test_hypervisors.py b/tests/v1_1/test_hypervisors.py
new file mode 100644
index 00000000..2febadae
--- /dev/null
+++ b/tests/v1_1/test_hypervisors.py
@@ -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)
diff --git a/tests/v1_1/test_shell.py b/tests/v1_1/test_shell.py
index e790cc9e..b31070fb 100644
--- a/tests/v1_1/test_shell.py
+++ b/tests/v1_1/test_shell.py
@@ -476,6 +476,22 @@ class ShellTest(utils.TestCase):
self.run_command('host-action sample-host --action 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):
self.run_command('quota-show test')
self.assert_called('GET', '/os-quota-sets/test')