Microversion 2.28 changes cpu_info string to JSON object

After this microversion Nova API the GET request to
/v2.1/os-hypervisors/{hypervisor_id} responses cpu_info
as regular JSON object instead of string.

Implements blueprint nova-api-hypervsor-cpu-info

Change-Id: I14db9017f69e70e759cc80d031f76af8be179e45
This commit is contained in:
Pavel Kholkin 2016-05-31 20:38:49 +03:00
parent 028091d623
commit 228e916cdd
26 changed files with 404 additions and 30 deletions

View File

@ -0,0 +1,43 @@
{
"hypervisors": [
{
"cpu_info": {
"arch": "x86_64",
"model": "Nehalem",
"vendor": "Intel",
"features": [
"pge",
"clflush"
],
"topology": {
"cores": 1,
"threads": 1,
"sockets": 4
}
},
"current_workload": 0,
"status": "enabled",
"state": "up",
"disk_available_least": 0,
"host_ip": "1.1.1.1",
"free_disk_gb": 1028,
"free_ram_mb": 7680,
"hypervisor_hostname": "fake-mini",
"hypervisor_type": "fake",
"hypervisor_version": 1000,
"id": 1,
"local_gb": 1028,
"local_gb_used": 0,
"memory_mb": 8192,
"memory_mb_used": 512,
"running_vms": 0,
"service": {
"host": "e6a37ee802d74863ab8b91ade8f12a67",
"id": 2,
"disabled_reason": null
},
"vcpus": 1,
"vcpus_used": 0
}
]
}

View File

@ -0,0 +1,10 @@
{
"hypervisors": [
{
"hypervisor_hostname": "fake-mini",
"id": 1,
"state": "up",
"status": "enabled"
}
]
}

View File

@ -0,0 +1,10 @@
{
"hypervisors": [
{
"hypervisor_hostname": "fake-mini",
"id": 1,
"state": "up",
"status": "enabled"
}
]
}

View File

@ -0,0 +1,41 @@
{
"hypervisor": {
"cpu_info": {
"arch": "x86_64",
"model": "Nehalem",
"vendor": "Intel",
"features": [
"pge",
"clflush"
],
"topology": {
"cores": 1,
"threads": 1,
"sockets": 4
}
},
"state": "up",
"status": "enabled",
"current_workload": 0,
"disk_available_least": 0,
"host_ip": "1.1.1.1",
"free_disk_gb": 1028,
"free_ram_mb": 7680,
"hypervisor_hostname": "fake-mini",
"hypervisor_type": "fake",
"hypervisor_version": 1000,
"id": 1,
"local_gb": 1028,
"local_gb_used": 0,
"memory_mb": 8192,
"memory_mb_used": 512,
"running_vms": 0,
"service": {
"host": "043b3cacf6f34c90a7245151fc8ebcda",
"id": 2,
"disabled_reason": null
},
"vcpus": 1,
"vcpus_used": 0
}
}

View File

@ -0,0 +1,16 @@
{
"hypervisor_statistics": {
"count": 1,
"current_workload": 0,
"disk_available_least": 0,
"free_disk_gb": 1028,
"free_ram_mb": 7680,
"local_gb": 1028,
"local_gb_used": 0,
"memory_mb": 8192,
"memory_mb_used": 512,
"running_vms": 0,
"vcpus": 1,
"vcpus_used": 0
}
}

View File

@ -0,0 +1,9 @@
{
"hypervisor": {
"hypervisor_hostname": "fake-mini",
"id": 1,
"state": "up",
"status": "enabled",
"uptime": " 08:32:11 up 93 days, 18:25, 12 users, load average: 0.20, 0.12, 0.14"
}
}

View File

@ -0,0 +1,20 @@
{
"hypervisors": [
{
"hypervisor_hostname": "fake-mini",
"id": 1,
"state": "up",
"status": "enabled",
"servers": [
{
"name": "test_server1",
"uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
},
{
"name": "test_server2",
"uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
}
]
}
]
}

View File

@ -0,0 +1,10 @@
{
"hypervisors": [
{
"hypervisor_hostname": "fake-mini",
"id": 1,
"state": "up",
"status": "enabled"
}
]
}

View File

@ -19,7 +19,7 @@
}
],
"status": "CURRENT",
"version": "2.27",
"version": "2.28",
"min_version": "2.1",
"updated": "2013-07-23T11:33:21Z"
}

View File

@ -22,7 +22,7 @@
}
],
"status": "CURRENT",
"version": "2.27",
"version": "2.28",
"min_version": "2.1",
"updated": "2013-07-23T11:33:21Z"
}

View File

@ -74,6 +74,7 @@ REST_API_VERSION_HISTORY = """REST API Version History:
* 2.26 - Adds support of server tags
* 2.27 - Adds support for new-style microversion headers while
keeping support for the original style.
* 2.28 - Changes compute_node.cpu_info from string to object
"""
# The minimum and maximum versions of the API supported
@ -82,7 +83,7 @@ REST_API_VERSION_HISTORY = """REST API Version History:
# Note(cyeoh): This only applies for the v2.1 API once microversions
# support is fully merged. It does not affect the V2 API.
_MIN_API_VERSION = "2.1"
_MAX_API_VERSION = "2.27"
_MAX_API_VERSION = "2.28"
DEFAULT_API_VERSION = _MIN_API_VERSION

View File

@ -15,8 +15,10 @@
"""The hypervisors admin extension."""
from oslo_serialization import jsonutils
import webob.exc
from nova.api.openstack import api_version_request
from nova.api.openstack import common
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
@ -38,7 +40,7 @@ class HypervisorsController(wsgi.Controller):
self.servicegroup_api = servicegroup.API()
super(HypervisorsController, self).__init__()
def _view_hypervisor(self, hypervisor, service, detail, servers=None,
def _view_hypervisor(self, hypervisor, service, detail, req, servers=None,
**kwargs):
alive = self.servicegroup_api.service_is_up(service)
hyp_dict = {
@ -54,8 +56,7 @@ class HypervisorsController(wsgi.Controller):
'memory_mb_used', 'local_gb_used',
'hypervisor_type', 'hypervisor_version',
'free_ram_mb', 'free_disk_gb', 'current_workload',
'running_vms', 'cpu_info', 'disk_available_least',
'host_ip'):
'running_vms', 'disk_available_least', 'host_ip'):
hyp_dict[field] = getattr(hypervisor, field)
hyp_dict['service'] = {
@ -64,6 +65,11 @@ class HypervisorsController(wsgi.Controller):
'disabled_reason': service.disabled_reason,
}
if api_version_request.is_supported(req, min_version='2.28'):
hyp_dict['cpu_info'] = jsonutils.loads(hypervisor.cpu_info)
else:
hyp_dict['cpu_info'] = hypervisor.cpu_info
if servers:
hyp_dict['servers'] = [dict(name=serv['name'], uuid=serv['uuid'])
for serv in servers]
@ -84,7 +90,7 @@ class HypervisorsController(wsgi.Controller):
hyp,
self.host_api.service_get_by_compute_host(
context, hyp.host),
False)
False, req)
for hyp in compute_nodes])
@extensions.expected_errors(())
@ -94,11 +100,8 @@ class HypervisorsController(wsgi.Controller):
compute_nodes = self.host_api.compute_node_get_all(context)
req.cache_db_compute_nodes(compute_nodes)
return dict(hypervisors=[self._view_hypervisor(
hyp,
self.host_api.service_get_by_compute_host(
context, hyp.host),
True)
for hyp in compute_nodes])
hyp, self.host_api.service_get_by_compute_host(context, hyp.host),
True, req) for hyp in compute_nodes])
@extensions.expected_errors(404)
def show(self, req, id):
@ -112,7 +115,8 @@ class HypervisorsController(wsgi.Controller):
raise webob.exc.HTTPNotFound(explanation=msg)
service = self.host_api.service_get_by_compute_host(
context, hyp.host)
return dict(hypervisor=self._view_hypervisor(hyp, service, True))
return dict(hypervisor=self._view_hypervisor(
hyp, service, True, req))
@extensions.expected_errors((400, 404, 501))
def uptime(self, req, id):
@ -135,7 +139,7 @@ class HypervisorsController(wsgi.Controller):
raise webob.exc.HTTPBadRequest(explanation=e.format_message())
service = self.host_api.service_get_by_compute_host(context, host)
return dict(hypervisor=self._view_hypervisor(hyp, service, False,
return dict(hypervisor=self._view_hypervisor(hyp, service, False, req,
uptime=uptime))
@extensions.expected_errors(404)
@ -149,7 +153,7 @@ class HypervisorsController(wsgi.Controller):
hyp,
self.host_api.service_get_by_compute_host(
context, hyp.host),
False)
False, req)
for hyp in hypervisors])
else:
msg = _("No hypervisor matching '%s' could be found.") % id
@ -170,7 +174,7 @@ class HypervisorsController(wsgi.Controller):
compute_node.host)
service = self.host_api.service_get_by_compute_host(
context, compute_node.host)
hyp = self._view_hypervisor(compute_node, service, False,
hyp = self._view_hypervisor(compute_node, service, False, req,
instances)
hypervisors.append(hyp)
return dict(hypervisors=hypervisors)

View File

@ -291,3 +291,12 @@ user documentation.
`Microversion Specification
<http://specs.openstack.org/openstack/api-wg/guidelines/microversion_specification.html>`_.
Both the original form of header and the new form is supported.
2.28
----
Nova API hypervisor.cpu_info change from string to JSON object.
From this version of the API the hypervisor's 'cpu_info' field will be
will returned as JSON object (not string) by sending GET request
to the /v2.1/os-hypervisors/{hypervisor_id}.

View File

@ -0,0 +1,43 @@
{
"hypervisors": [
{
"cpu_info": {
"arch": "x86_64",
"model": "Nehalem",
"vendor": "Intel",
"features": [
"pge",
"clflush"
],
"topology": {
"cores": 1,
"threads": 1,
"sockets": 4
}
},
"current_workload": 0,
"state": "up",
"status": "enabled",
"disk_available_least": 0,
"host_ip": "%(ip)s",
"free_disk_gb": 1028,
"free_ram_mb": 7680,
"hypervisor_hostname": "fake-mini",
"hypervisor_type": "fake",
"hypervisor_version": 1000,
"id": %(hypervisor_id)s,
"local_gb": 1028,
"local_gb_used": 0,
"memory_mb": 8192,
"memory_mb_used": 512,
"running_vms": 0,
"service": {
"host": "%(host_name)s",
"id": 2,
"disabled_reason": null
},
"vcpus": 1,
"vcpus_used": 0
}
]
}

View File

@ -0,0 +1,10 @@
{
"hypervisors": [
{
"hypervisor_hostname": "fake-mini",
"state": "up",
"status": "enabled",
"id": 1
}
]
}

View File

@ -0,0 +1,10 @@
{
"hypervisors": [
{
"hypervisor_hostname": "fake-mini",
"id": 1,
"state": "up",
"status": "enabled"
}
]
}

View File

@ -0,0 +1,41 @@
{
"hypervisor": {
"cpu_info": {
"arch": "x86_64",
"model": "Nehalem",
"vendor": "Intel",
"features": [
"pge",
"clflush"
],
"topology": {
"cores": 1,
"threads": 1,
"sockets": 4
}
},
"current_workload": 0,
"disk_available_least": 0,
"state": "up",
"status": "enabled",
"host_ip": "%(ip)s",
"free_disk_gb": 1028,
"free_ram_mb": 7680,
"hypervisor_hostname": "fake-mini",
"hypervisor_type": "fake",
"hypervisor_version": 1000,
"id": %(hypervisor_id)s,
"local_gb": 1028,
"local_gb_used": 0,
"memory_mb": 8192,
"memory_mb_used": 512,
"running_vms": 0,
"service": {
"host": "%(host_name)s",
"id": 2,
"disabled_reason": null
},
"vcpus": 1,
"vcpus_used": 0
}
}

View File

@ -0,0 +1,16 @@
{
"hypervisor_statistics": {
"count": 1,
"current_workload": 0,
"disk_available_least": 0,
"free_disk_gb": 1028,
"free_ram_mb": 7680,
"local_gb": 1028,
"local_gb_used": 0,
"memory_mb": 8192,
"memory_mb_used": 512,
"running_vms": 0,
"vcpus": 1,
"vcpus_used": 0
}
}

View File

@ -0,0 +1,9 @@
{
"hypervisor": {
"hypervisor_hostname": "fake-mini",
"id": %(hypervisor_id)s,
"state": "up",
"status": "enabled",
"uptime": " 08:32:11 up 93 days, 18:25, 12 users, load average: 0.20, 0.12, 0.14"
}
}

View File

@ -0,0 +1,20 @@
{
"hypervisors": [
{
"hypervisor_hostname": "fake-mini",
"id": 1,
"state": "up",
"status": "enabled",
"servers": [
{
"name": "test_server1",
"uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
},
{
"name": "test_server2",
"uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
}
]
}
]
}

View File

@ -0,0 +1,10 @@
{
"hypervisors": [
{
"hypervisor_hostname": "fake-mini",
"id": 1,
"state": "up",
"status": "enabled"
}
]
}

View File

@ -157,3 +157,12 @@ class HypervisorsCellsSampleJsonTests(api_sample_base.ApiSampleTestBaseV21):
response = self._do_get('os-hypervisors/%s/uptime' % hypervisor_id)
subs = {'hypervisor_id': str(hypervisor_id)}
self._verify_response('hypervisors-uptime-resp', subs, response, 200)
class HypervisorsSampleJson228Tests(HypervisorsSampleJsonTests):
microversion = '2.28'
scenarios = [('v2_28', {'api_major_version': 'v2.1'})]
def setUp(self):
super(HypervisorsSampleJson228Tests, self).setUp()
self.api.microversion = self.microversion

View File

@ -79,9 +79,10 @@ class ExtendedHypervisorsTestV21(test.NoDBTestCase):
fake_service_get_by_compute_host)
def test_view_hypervisor_detail_noservers(self):
req = self._get_request()
result = self.controller._view_hypervisor(
test_hypervisors.TEST_HYPERS_OBJ[0],
test_hypervisors.TEST_SERVICES[0], True)
test_hypervisors.TEST_SERVICES[0], True, req)
self.assertEqual(result, self.DETAIL_HYPERS_DICTS[0])

View File

@ -21,6 +21,7 @@ from nova.api.openstack.compute import hypervisors \
from nova import objects
from nova import test
from nova.tests.unit.api.openstack.compute import test_hypervisors
from nova.tests.unit.api.openstack import fakes
TEST_HYPER = test_hypervisors.TEST_HYPERS_OBJ[0].obj_clone()
TEST_SERVICE = objects.Service(id=1,
@ -39,31 +40,37 @@ class HypervisorStatusTestV21(test.NoDBTestCase):
self.controller.servicegroup_api.service_is_up = mock.MagicMock(
return_value=True)
def _get_request(self):
return fakes.HTTPRequest.blank('/v2/fake/os-hypervisors/detail',
use_admin_context=True)
def test_view_hypervisor_service_status(self):
self._prepare_extension()
req = self._get_request()
result = self.controller._view_hypervisor(
TEST_HYPER, TEST_SERVICE, False)
TEST_HYPER, TEST_SERVICE, False, req)
self.assertEqual('enabled', result['status'])
self.assertEqual('up', result['state'])
self.assertEqual('enabled', result['status'])
self.controller.servicegroup_api.service_is_up.return_value = False
result = self.controller._view_hypervisor(
TEST_HYPER, TEST_SERVICE, False)
TEST_HYPER, TEST_SERVICE, False, req)
self.assertEqual('down', result['state'])
hyper = copy.deepcopy(TEST_HYPER)
service = copy.deepcopy(TEST_SERVICE)
service.disabled = True
result = self.controller._view_hypervisor(hyper, service, False)
result = self.controller._view_hypervisor(hyper, service, False, req)
self.assertEqual('disabled', result['status'])
def test_view_hypervisor_detail_status(self):
self._prepare_extension()
req = self._get_request()
result = self.controller._view_hypervisor(
TEST_HYPER, TEST_SERVICE, True)
TEST_HYPER, TEST_SERVICE, True, req)
self.assertEqual('enabled', result['status'])
self.assertEqual('up', result['state'])
@ -71,13 +78,13 @@ class HypervisorStatusTestV21(test.NoDBTestCase):
self.controller.servicegroup_api.service_is_up.return_value = False
result = self.controller._view_hypervisor(
TEST_HYPER, TEST_SERVICE, True)
TEST_HYPER, TEST_SERVICE, True, req)
self.assertEqual('down', result['state'])
hyper = copy.deepcopy(TEST_HYPER)
service = copy.deepcopy(TEST_SERVICE)
service.disabled = True
service.disabled_reason = "fake"
result = self.controller._view_hypervisor(hyper, service, True)
result = self.controller._view_hypervisor(hyper, service, True, req)
self.assertEqual('disabled', result['status'],)
self.assertEqual('fake', result['service']['disabled_reason'])

View File

@ -16,6 +16,7 @@
import copy
import mock
import netaddr
from oslo_serialization import jsonutils
from webob import exc
from nova.api.openstack.compute import hypervisors \
@ -28,6 +29,12 @@ from nova.tests.unit.api.openstack import fakes
from nova.tests.unit import fake_instance
from nova.tests import uuidsentinel as uuids
CPU_INFO = """
{"arch": "x86_64",
"vendor": "fake",
"topology": {"cores": 1, "threads": 1, "sockets": 1},
"features": [],
"model": ""}"""
TEST_HYPERS = [
dict(id=1,
@ -46,7 +53,7 @@ TEST_HYPERS = [
free_disk_gb=125,
current_workload=2,
running_vms=2,
cpu_info='cpu_info',
cpu_info=CPU_INFO,
disk_available_least=100,
host_ip=netaddr.IPAddress('1.1.1.1')),
dict(id=2,
@ -65,7 +72,7 @@ TEST_HYPERS = [
free_disk_gb=125,
current_workload=2,
running_vms=2,
cpu_info='cpu_info',
cpu_info=CPU_INFO,
disk_available_least=100,
host_ip=netaddr.IPAddress('2.2.2.2'))]
@ -158,6 +165,8 @@ def fake_instance_get_all_by_host(context, host):
class HypervisorsTestV21(test.NoDBTestCase):
api_version = '2.1'
# copying the objects locally so the cells testcases can provide their own
TEST_HYPERS_OBJ = copy.deepcopy(TEST_HYPERS_OBJ)
TEST_SERVICES = copy.deepcopy(TEST_SERVICES)
@ -176,7 +185,6 @@ class HypervisorsTestV21(test.NoDBTestCase):
'status': 'enabled',
'service': dict(id=2, host='compute2',
disabled_reason=None)})
INDEX_HYPER_DICTS = [
dict(id=1, hypervisor_hostname="hyper1",
state='up', status='enabled'),
@ -184,7 +192,8 @@ class HypervisorsTestV21(test.NoDBTestCase):
state='up', status='enabled')]
def _get_request(self, use_admin_context):
return fakes.HTTPRequest.blank('', use_admin_context=use_admin_context)
return fakes.HTTPRequest.blank('', use_admin_context=use_admin_context,
version=self.api_version)
def _set_up_controller(self):
self.controller = hypervisors_v21.HypervisorsController()
@ -208,21 +217,25 @@ class HypervisorsTestV21(test.NoDBTestCase):
fake_compute_node_statistics)
def test_view_hypervisor_nodetail_noservers(self):
req = self._get_request(True)
result = self.controller._view_hypervisor(
self.TEST_HYPERS_OBJ[0], self.TEST_SERVICES[0], False)
self.TEST_HYPERS_OBJ[0], self.TEST_SERVICES[0], False, req)
self.assertEqual(result, self.INDEX_HYPER_DICTS[0])
def test_view_hypervisor_detail_noservers(self):
req = self._get_request(True)
result = self.controller._view_hypervisor(
self.TEST_HYPERS_OBJ[0], self.TEST_SERVICES[0], True)
self.TEST_HYPERS_OBJ[0], self.TEST_SERVICES[0], True, req)
self.assertEqual(result, self.DETAIL_HYPERS_DICTS[0])
def test_view_hypervisor_servers(self):
req = self._get_request(True)
result = self.controller._view_hypervisor(self.TEST_HYPERS_OBJ[0],
self.TEST_SERVICES[0],
False, self.TEST_SERVERS)
False, req,
self.TEST_SERVERS)
expected_dict = copy.deepcopy(self.INDEX_HYPER_DICTS[0])
expected_dict.update({'servers': [
dict(name="inst1", uuid=uuids.instance_1),
@ -511,3 +524,11 @@ class CellHypervisorsTestV21(HypervisorsTestV21):
fake_compute_node_statistics)
self.stubs.Set(self.controller.host_api, 'instance_get_all_by_host',
self.fake_instance_get_all_by_host)
class HypervisorsTestV228(HypervisorsTestV21):
api_version = '2.28'
DETAIL_HYPERS_DICTS = copy.deepcopy(HypervisorsTestV21.DETAIL_HYPERS_DICTS)
DETAIL_HYPERS_DICTS[0]['cpu_info'] = jsonutils.loads(CPU_INFO)
DETAIL_HYPERS_DICTS[1]['cpu_info'] = jsonutils.loads(CPU_INFO)

View File

@ -0,0 +1,4 @@
---
features:
- Added microversion v2.28 from which hypervisor's 'cpu_info' field returned
as JSON object by sending GET /v2.1/os-hypervisors/{hypervisor_id} request.