Adds hypervisor support for Nova V3 API

Adds support and tests for the os-hypervisors extension
for the Nova V3 API.

Note that compared to the V2 API it separates the search
function into search by hypervisor name and a new list
servers by hypervisor as this better first the changes
in the V3 API. The listing of servers by hypervisor command
is preserved, though reworked to use the new interfaces.

Partially implements blueprint v3-api

Change-Id: I472f9acad895dcf842e93d2de27530652f73867e
This commit is contained in:
Chris Yeoh 2013-12-13 21:23:27 +10:30
parent 94b40dd2f8
commit 3c46b26666
6 changed files with 152 additions and 24 deletions

View File

@ -17,10 +17,14 @@ from novaclient.tests import utils
from novaclient.tests.v1_1 import fakes
cs = fakes.FakeClient()
class HypervisorsTest(utils.TestCase):
def setUp(self):
super(HypervisorsTest, self).setUp()
self.cs = self._get_fake_client()
def _get_fake_client(self):
return fakes.FakeClient()
def compare_to_expected(self, expected, hyper):
for key, value in expected.items():
self.assertEqual(getattr(hyper, key), value)
@ -31,8 +35,8 @@ class HypervisorsTest(utils.TestCase):
dict(id=5678, hypervisor_hostname='hyper2'),
]
result = cs.hypervisors.list(False)
cs.assert_called('GET', '/os-hypervisors')
result = self.cs.hypervisors.list(False)
self.cs.assert_called('GET', '/os-hypervisors')
for idx, hyper in enumerate(result):
self.compare_to_expected(expected[idx], hyper)
@ -74,8 +78,8 @@ class HypervisorsTest(utils.TestCase):
cpu_info='cpu_info',
disk_available_least=100)]
result = cs.hypervisors.list()
cs.assert_called('GET', '/os-hypervisors/detail')
result = self.cs.hypervisors.list()
self.cs.assert_called('GET', '/os-hypervisors/detail')
for idx, hyper in enumerate(result):
self.compare_to_expected(expected[idx], hyper)
@ -86,8 +90,8 @@ class HypervisorsTest(utils.TestCase):
dict(id=5678, hypervisor_hostname='hyper2'),
]
result = cs.hypervisors.search('hyper')
cs.assert_called('GET', '/os-hypervisors/hyper/search')
result = self.cs.hypervisors.search('hyper')
self.cs.assert_called('GET', '/os-hypervisors/hyper/search')
for idx, hyper in enumerate(result):
self.compare_to_expected(expected[idx], hyper)
@ -106,8 +110,8 @@ class HypervisorsTest(utils.TestCase):
dict(name='inst4', uuid='uuid4')]),
]
result = cs.hypervisors.search('hyper', True)
cs.assert_called('GET', '/os-hypervisors/hyper/servers')
result = self.cs.hypervisors.search('hyper', True)
self.cs.assert_called('GET', '/os-hypervisors/hyper/servers')
for idx, hyper in enumerate(result):
self.compare_to_expected(expected[idx], hyper)
@ -132,8 +136,8 @@ class HypervisorsTest(utils.TestCase):
cpu_info='cpu_info',
disk_available_least=100)
result = cs.hypervisors.get(1234)
cs.assert_called('GET', '/os-hypervisors/1234')
result = self.cs.hypervisors.get(1234)
self.cs.assert_called('GET', '/os-hypervisors/1234')
self.compare_to_expected(expected, result)
@ -143,8 +147,8 @@ class HypervisorsTest(utils.TestCase):
hypervisor_hostname="hyper1",
uptime="fake uptime")
result = cs.hypervisors.uptime(1234)
cs.assert_called('GET', '/os-hypervisors/1234/uptime')
result = self.cs.hypervisors.uptime(1234)
self.cs.assert_called('GET', '/os-hypervisors/1234/uptime')
self.compare_to_expected(expected, result)
@ -164,7 +168,7 @@ class HypervisorsTest(utils.TestCase):
disk_available_least=200,
)
result = cs.hypervisors.statistics()
cs.assert_called('GET', '/os-hypervisors/statistics')
result = self.cs.hypervisors.statistics()
self.cs.assert_called('GET', '/os-hypervisors/statistics')
self.compare_to_expected(expected, result)

View File

@ -292,3 +292,22 @@ class FakeHTTPClient(fakes_v1_1.FakeHTTPClient):
'keypairs': 1,
'security_groups': 1,
'security_group_rules': 1}})
#
# Hypervisors
#
def get_os_hypervisors_search(self, **kw):
return (200, {}, {'hypervisors': [
{'id': 1234, 'hypervisor_hostname': 'hyper1'},
{'id': 5678, 'hypervisor_hostname': 'hyper2'}
]})
def get_os_hypervisors_1234_servers(self, **kw):
return (200, {}, {'hypervisor':
{'id': 1234,
'hypervisor_hostname': 'hyper1',
'servers': [
{'name': 'inst1', 'uuid': 'uuid1'},
{'name': 'inst2', 'uuid': 'uuid2'}
]},
})

View File

@ -0,0 +1,50 @@
# Copyright 2012 OpenStack Foundation
# 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 novaclient.tests.v1_1 import test_hypervisors
from novaclient.tests.v3 import fakes
class HypervisorsTest(test_hypervisors.HypervisorsTest):
def setUp(self):
super(HypervisorsTest, self).setUp()
self.cs = self._get_fake_client()
def _get_fake_client(self):
return fakes.FakeClient()
def test_hypervisor_search(self):
expected = [
dict(id=1234, hypervisor_hostname='hyper1'),
dict(id=5678, hypervisor_hostname='hyper2'),
]
result = self.cs.hypervisors.search('hyper')
self.cs.assert_called('GET', '/os-hypervisors/search?query=hyper')
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')])
result = self.cs.hypervisors.servers('1234')
self.cs.assert_called('GET', '/os-hypervisors/1234/servers')
self.compare_to_expected(expected, result)

View File

@ -20,6 +20,7 @@ from novaclient.v3 import availability_zones
from novaclient.v3 import flavor_access
from novaclient.v3 import flavors
from novaclient.v3 import hosts
from novaclient.v3 import hypervisors
from novaclient.v3 import images
from novaclient.v3 import quota_classes
from novaclient.v3 import quotas
@ -65,6 +66,7 @@ class Client(object):
self.hosts = hosts.HostManager(self)
self.flavors = flavors.FlavorManager(self)
self.flavor_access = flavor_access.FlavorAccessManager(self)
self.hypervisors = hypervisors.HypervisorManager(self)
self.images = images.ImageManager(self)
self.quotas = quotas.QuotaSetManager(self)
self.quota_classes = quota_classes.QuotaClassSetManager(self)

View File

@ -0,0 +1,48 @@
# Copyright 2013 IBM Corp
# 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
"""
from novaclient.openstack.common.py3kcompat import urlutils
from novaclient.v1_1 import hypervisors
class Hypervisor(hypervisors.Hypervisor):
pass
class HypervisorManager(hypervisors.HypervisorManager):
resource_class = Hypervisor
def search(self, hypervisor_match):
"""
Get a list of matching hypervisors.
:param servers: If True, server information is also retrieved.
"""
url = ('/os-hypervisors/search?query=%s' %
urlutils.quote(hypervisor_match, safe=''))
return self._list(url, 'hypervisors')
def servers(self, hypervisor):
"""
Get servers for a specific hypervisor
:param hypervisor: ID of hypervisor to get list of servers for.
"""
return self._get('/os-hypervisors/%s/servers' % hypervisor,
'hypervisor')

View File

@ -2684,27 +2684,32 @@ def do_hypervisor_list(cs, args):
help='The hypervisor hostname (or pattern) to search for.')
def do_hypervisor_servers(cs, args):
"""List servers belonging to specific hypervisors."""
hypers = cs.hypervisors.search(args.hostname, servers=True)
# Get a list of hypervisors first
hypers = cs.hypervisors.search(args.hostname)
class InstanceOnHyper(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
# Massage the result into a list to be displayed
instances = []
servers = []
for hyper in hypers:
# Get a list of servers for each hypervisor
hyper_host = hyper.hypervisor_hostname
hyper_id = hyper.id
if hasattr(hyper, 'servers'):
instances.extend([InstanceOnHyper(id=serv['uuid'],
hyper_servers = cs.hypervisors.servers(hyper_id)
if hasattr(hyper_servers, 'servers'):
print(hyper_servers.servers)
servers.extend([InstanceOnHyper(id=serv['id'],
name=serv['name'],
hypervisor_hostname=hyper_host,
hypervisor_id=hyper_id)
for serv in hyper.servers])
for serv in hyper_servers.servers])
# Output the data
utils.print_list(instances, ['ID', 'Name', 'Hypervisor ID',
'Hypervisor Hostname'])
utils.print_list(servers, ['ID', 'Name', 'Hypervisor ID',
'Hypervisor Hostname'])
@utils.arg('hypervisor',