From 7d8a78a29128debe7ed49bea394f952f37cee498 Mon Sep 17 00:00:00 2001 From: Yunhong Jiang Date: Thu, 13 Mar 2014 15:09:34 -0700 Subject: [PATCH] Return status for compute node Currently when return compute node information, there is no status returned. When the corresponding service is disabled or down and users try to do 'hypervisor-list' or 'hypervisor-show', they will have no idea of it. Implements: blueprint return-status-for-hypervisor-node Closes-Bug: #1285259 DocImpact Change-Id: I17c53b454ccef023f298f1b8875daef965d2325d --- .../all_extensions/extensions-get-resp.json | 8 ++ .../all_extensions/extensions-get-resp.xml | 3 + .../hypervisors-show-with-status-resp.json | 27 +++++++ .../hypervisors-show-with-status-resp.xml | 4 + .../hypervisors-detail-resp.json | 5 +- .../os-hypervisors/hypervisors-list-resp.json | 6 +- .../hypervisors-search-resp.json | 6 +- .../hypervisors-servers-resp.json | 4 +- .../os-hypervisors/hypervisors-show-resp.json | 5 +- .../hypervisors-uptime-resp.json | 4 +- .../os-pci/hypervisors-pci-detail-resp.json | 5 +- .../os-pci/hypervisors-pci-show-resp.json | 5 +- .../compute/contrib/hypervisor_status.py | 25 ++++++ .../openstack/compute/contrib/hypervisors.py | 15 ++++ .../compute/plugins/v3/hypervisors.py | 7 ++ .../compute/contrib/test_hypervisor_status.py | 80 +++++++++++++++++++ .../compute/plugins/v3/test_hypervisors.py | 69 +++++++++++++--- .../extensions-get-resp.json.tpl | 8 ++ .../extensions-get-resp.xml.tpl | 3 + ...hypervisors-show-with-status-resp.json.tpl | 27 +++++++ .../hypervisors-show-with-status-resp.xml.tpl | 4 + nova/tests/integrated/test_api_samples.py | 38 ++++++++- .../hypervisors-detail-resp.json.tpl | 5 +- .../hypervisors-list-resp.json.tpl | 4 +- .../hypervisors-search-resp.json.tpl | 6 +- .../hypervisors-servers-resp.json.tpl | 4 +- .../hypervisors-show-resp.json.tpl | 5 +- .../hypervisors-uptime-resp.json.tpl | 2 + .../hypervisors-pci-detail-resp.json.tpl | 5 +- .../os-pci/hypervisors-pci-show-resp.json.tpl | 5 +- nova/tests/integrated/v3/test_pci.py | 35 ++++---- 31 files changed, 383 insertions(+), 46 deletions(-) create mode 100644 doc/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.json create mode 100644 doc/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.xml create mode 100644 nova/api/openstack/compute/contrib/hypervisor_status.py create mode 100644 nova/tests/api/openstack/compute/contrib/test_hypervisor_status.py create mode 100644 nova/tests/integrated/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.json.tpl create mode 100644 nova/tests/integrated/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.xml.tpl diff --git a/doc/api_samples/all_extensions/extensions-get-resp.json b/doc/api_samples/all_extensions/extensions-get-resp.json index 4d4967accf7b..0359faf0c41a 100644 --- a/doc/api_samples/all_extensions/extensions-get-resp.json +++ b/doc/api_samples/all_extensions/extensions-get-resp.json @@ -312,6 +312,14 @@ "namespace": "http://docs.openstack.org/compute/ext/extended_rescue_with_image/api/v2", "updated": "2014-01-04T00:00:00Z" }, + { + "alias": "os-hypervisor-status", + "description": "Show hypervisor status.", + "links": [], + "name": "HypervisorStatus", + "namespace": "http://docs.openstack.org/compute/ext/hypervisor_status/api/v1.1", + "updated": "2014-04-17T00:00:00Z" + }, { "alias": "os-extended-services", "description": "Extended services support.", diff --git a/doc/api_samples/all_extensions/extensions-get-resp.xml b/doc/api_samples/all_extensions/extensions-get-resp.xml index d69e8ab40ace..ff47a36b951f 100644 --- a/doc/api_samples/all_extensions/extensions-get-resp.xml +++ b/doc/api_samples/all_extensions/extensions-get-resp.xml @@ -143,6 +143,9 @@ Extended services deletion support. + + Show hypervisor status. + Extended Volumes support. diff --git a/doc/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.json b/doc/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.json new file mode 100644 index 000000000000..44af92c433a5 --- /dev/null +++ b/doc/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.json @@ -0,0 +1,27 @@ +{ + "hypervisor": { + "cpu_info": "?", + "current_workload": 0, + "disk_available_least": 0, + "free_disk_gb": 1028, + "free_ram_mb": 7680, + "hypervisor_hostname": "fake-mini", + "hypervisor_type": "fake", + "hypervisor_version": 1000, + "id": 1, + "status": "enabled", + "state": "up", + "local_gb": 1028, + "local_gb_used": 0, + "memory_mb": 8192, + "memory_mb_used": 512, + "running_vms": 0, + "service": { + "host": "5641188ab2964f88a21042b493585ff8", + "id": 2, + "disabled_reason": null + }, + "vcpus": 1, + "vcpus_used": 0 + } +} diff --git a/doc/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.xml b/doc/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.xml new file mode 100644 index 000000000000..dbfec700ce61 --- /dev/null +++ b/doc/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.xml @@ -0,0 +1,4 @@ + + + + diff --git a/doc/v3/api_samples/os-hypervisors/hypervisors-detail-resp.json b/doc/v3/api_samples/os-hypervisors/hypervisors-detail-resp.json index e800c777ae0c..8694c135a0c8 100644 --- a/doc/v3/api_samples/os-hypervisors/hypervisors-detail-resp.json +++ b/doc/v3/api_samples/os-hypervisors/hypervisors-detail-resp.json @@ -3,6 +3,8 @@ { "cpu_info": "?", "current_workload": 0, + "status": "enabled", + "state": "up", "disk_available_least": 0, "host_ip": "1.1.1.1", "free_disk_gb": 1028, @@ -18,7 +20,8 @@ "running_vms": 0, "service": { "host": "e6a37ee802d74863ab8b91ade8f12a67", - "id": 2 + "id": 2, + "disabled_reason": null }, "vcpus": 1, "vcpus_used": 0 diff --git a/doc/v3/api_samples/os-hypervisors/hypervisors-list-resp.json b/doc/v3/api_samples/os-hypervisors/hypervisors-list-resp.json index 8d94021274fb..375627499df6 100644 --- a/doc/v3/api_samples/os-hypervisors/hypervisors-list-resp.json +++ b/doc/v3/api_samples/os-hypervisors/hypervisors-list-resp.json @@ -2,7 +2,9 @@ "hypervisors": [ { "hypervisor_hostname": "fake-mini", - "id": 1 + "id": 1, + "state": "up", + "status": "enabled" } ] -} \ No newline at end of file +} diff --git a/doc/v3/api_samples/os-hypervisors/hypervisors-search-resp.json b/doc/v3/api_samples/os-hypervisors/hypervisors-search-resp.json index 8d94021274fb..375627499df6 100644 --- a/doc/v3/api_samples/os-hypervisors/hypervisors-search-resp.json +++ b/doc/v3/api_samples/os-hypervisors/hypervisors-search-resp.json @@ -2,7 +2,9 @@ "hypervisors": [ { "hypervisor_hostname": "fake-mini", - "id": 1 + "id": 1, + "state": "up", + "status": "enabled" } ] -} \ No newline at end of file +} diff --git a/doc/v3/api_samples/os-hypervisors/hypervisors-servers-resp.json b/doc/v3/api_samples/os-hypervisors/hypervisors-servers-resp.json index 934ef0c02db7..710b05b9309a 100644 --- a/doc/v3/api_samples/os-hypervisors/hypervisors-servers-resp.json +++ b/doc/v3/api_samples/os-hypervisors/hypervisors-servers-resp.json @@ -2,6 +2,8 @@ "hypervisor": { "hypervisor_hostname": "fake-mini", "id": 1, + "state": "up", + "status": "enabled", "servers": [] } -} \ No newline at end of file +} diff --git a/doc/v3/api_samples/os-hypervisors/hypervisors-show-resp.json b/doc/v3/api_samples/os-hypervisors/hypervisors-show-resp.json index 0c4957bdae09..3d2c972ce3cf 100644 --- a/doc/v3/api_samples/os-hypervisors/hypervisors-show-resp.json +++ b/doc/v3/api_samples/os-hypervisors/hypervisors-show-resp.json @@ -1,6 +1,8 @@ { "hypervisor": { "cpu_info": "?", + "state": "up", + "status": "enabled", "current_workload": 0, "disk_available_least": 0, "host_ip": "1.1.1.1", @@ -17,7 +19,8 @@ "running_vms": 0, "service": { "host": "043b3cacf6f34c90a7245151fc8ebcda", - "id": 2 + "id": 2, + "disabled_reason": null }, "vcpus": 1, "vcpus_used": 0 diff --git a/doc/v3/api_samples/os-hypervisors/hypervisors-uptime-resp.json b/doc/v3/api_samples/os-hypervisors/hypervisors-uptime-resp.json index f5f9d19e7ccd..78521b373112 100644 --- a/doc/v3/api_samples/os-hypervisors/hypervisors-uptime-resp.json +++ b/doc/v3/api_samples/os-hypervisors/hypervisors-uptime-resp.json @@ -2,6 +2,8 @@ "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" } -} \ No newline at end of file +} diff --git a/doc/v3/api_samples/os-pci/hypervisors-pci-detail-resp.json b/doc/v3/api_samples/os-pci/hypervisors-pci-detail-resp.json index 1ca293225e4e..f6f7363ef43c 100644 --- a/doc/v3/api_samples/os-pci/hypervisors-pci-detail-resp.json +++ b/doc/v3/api_samples/os-pci/hypervisors-pci-detail-resp.json @@ -2,6 +2,8 @@ "hypervisors": [ { "cpu_info": "?", + "state": "up", + "status": "enabled", "current_workload": 0, "disk_available_least": 0, "host_ip": "1.1.1.1", @@ -30,7 +32,8 @@ "running_vms": 0, "service": { "host": "043b3cacf6f34c90a7245151fc8ebcda", - "id": 2 + "id": 2, + "disabled_reason": null }, "vcpus": 1, "vcpus_used": 0 diff --git a/doc/v3/api_samples/os-pci/hypervisors-pci-show-resp.json b/doc/v3/api_samples/os-pci/hypervisors-pci-show-resp.json index 2a6e41bf4dbd..f2fa988f83c9 100644 --- a/doc/v3/api_samples/os-pci/hypervisors-pci-show-resp.json +++ b/doc/v3/api_samples/os-pci/hypervisors-pci-show-resp.json @@ -4,6 +4,8 @@ "current_workload": 0, "disk_available_least": 0, "host_ip": "1.1.1.1", + "state": "up", + "status": "enabled", "free_disk_gb": 1028, "free_ram_mb": 7680, "hypervisor_hostname": "fake-mini", @@ -29,7 +31,8 @@ "running_vms": 0, "service": { "host": "043b3cacf6f34c90a7245151fc8ebcda", - "id": 2 + "id": 2, + "disabled_reason": null }, "vcpus": 1, "vcpus_used": 0 diff --git a/nova/api/openstack/compute/contrib/hypervisor_status.py b/nova/api/openstack/compute/contrib/hypervisor_status.py new file mode 100644 index 000000000000..94bcabca48e5 --- /dev/null +++ b/nova/api/openstack/compute/contrib/hypervisor_status.py @@ -0,0 +1,25 @@ +# Copyright 2014 Intel Corp. +# +# 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 nova.api.openstack import extensions + + +class Hypervisor_status(extensions.ExtensionDescriptor): + """Show hypervisor status.""" + + name = "HypervisorStatus" + alias = "os-hypervisor-status" + namespace = ("http://docs.openstack.org/compute/ext/" + "hypervisor_status/api/v1.1") + updated = "2014-04-17T00:00:00Z" diff --git a/nova/api/openstack/compute/contrib/hypervisors.py b/nova/api/openstack/compute/contrib/hypervisors.py index 22b51fce740e..d2df93fa8293 100644 --- a/nova/api/openstack/compute/contrib/hypervisors.py +++ b/nova/api/openstack/compute/contrib/hypervisors.py @@ -23,6 +23,7 @@ from nova.api.openstack import xmlutil from nova import compute from nova import exception from nova.i18n import _ +from nova import servicegroup authorize = extensions.extension_authorizer('compute', 'hypervisors') @@ -31,6 +32,8 @@ authorize = extensions.extension_authorizer('compute', 'hypervisors') def make_hypervisor(elem, detail): elem.set('hypervisor_hostname') elem.set('id') + elem.set('state') + elem.set('status') if detail: elem.set('vcpus') elem.set('memory_mb') @@ -52,6 +55,7 @@ def make_hypervisor(elem, detail): selector='service') service.set('id') service.set('host') + service.set('disabled_reason') class HypervisorIndexTemplate(xmlutil.TemplateBuilder): @@ -128,6 +132,7 @@ class HypervisorsController(object): def __init__(self, ext_mgr): self.host_api = compute.HostAPI() + self.servicegroup_api = servicegroup.API() super(HypervisorsController, self).__init__() self.ext_mgr = ext_mgr @@ -137,6 +142,13 @@ class HypervisorsController(object): 'hypervisor_hostname': hypervisor['hypervisor_hostname'], } + ext_status_loaded = self.ext_mgr.is_loaded('os-hypervisor-status') + if ext_status_loaded: + alive = self.servicegroup_api.service_is_up(hypervisor['service']) + hyp_dict['state'] = 'up' if alive else "down" + hyp_dict['status'] = ( + 'disabled' if hypervisor['service']['disabled'] else 'enabled') + if detail and not servers: fields = ('vcpus', 'memory_mb', 'local_gb', 'vcpus_used', 'memory_mb_used', 'local_gb_used', @@ -153,6 +165,9 @@ class HypervisorsController(object): 'id': hypervisor['service_id'], 'host': hypervisor['service']['host'], } + if ext_status_loaded: + hyp_dict['service'].update( + disabled_reason=hypervisor['service']['disabled_reason']) if servers: hyp_dict['servers'] = [dict(name=serv['name'], uuid=serv['uuid']) diff --git a/nova/api/openstack/compute/plugins/v3/hypervisors.py b/nova/api/openstack/compute/plugins/v3/hypervisors.py index cf145e6283a1..c38ed4af18a6 100644 --- a/nova/api/openstack/compute/plugins/v3/hypervisors.py +++ b/nova/api/openstack/compute/plugins/v3/hypervisors.py @@ -21,6 +21,7 @@ from nova.api.openstack import extensions from nova import compute from nova import exception from nova.i18n import _ +from nova import servicegroup ALIAS = "os-hypervisors" @@ -32,12 +33,17 @@ class HypervisorsController(object): def __init__(self): self.host_api = compute.HostAPI() + self.servicegroup_api = servicegroup.API() super(HypervisorsController, self).__init__() def _view_hypervisor(self, hypervisor, detail, servers=None, **kwargs): + alive = self.servicegroup_api.service_is_up(hypervisor['service']) hyp_dict = { 'id': hypervisor['id'], 'hypervisor_hostname': hypervisor['hypervisor_hostname'], + 'state': 'up' if alive else 'down', + 'status': ('disabled' if hypervisor['service']['disabled'] + else 'enabled'), } if detail and not servers: @@ -52,6 +58,7 @@ class HypervisorsController(object): hyp_dict['service'] = { 'id': hypervisor['service_id'], 'host': hypervisor['service']['host'], + 'disabled_reason': hypervisor['service']['disabled_reason'], } if servers is not None: diff --git a/nova/tests/api/openstack/compute/contrib/test_hypervisor_status.py b/nova/tests/api/openstack/compute/contrib/test_hypervisor_status.py new file mode 100644 index 000000000000..1d8cd95358c6 --- /dev/null +++ b/nova/tests/api/openstack/compute/contrib/test_hypervisor_status.py @@ -0,0 +1,80 @@ +# Copyright 2014 Intel Corp. +# +# 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 copy + +import mock + +from nova.api.openstack.compute.contrib import hypervisors +from nova.tests.api.openstack.compute.contrib import test_hypervisors + + +TEST_HYPER = dict(test_hypervisors.TEST_HYPERS[0], + service=dict(id=1, + host="compute1", + binary="nova-compute", + topic="compute_topic", + report_count=5, + disabled=False, + disabled_reason=None, + availability_zone="nova"), + ) + + +class HypervisorStatusTest(test_hypervisors.HypervisorsTest): + def _prepare_extension(self): + self.ext_mgr.extensions['os-hypervisor-status'] = True + self.controller = hypervisors.HypervisorsController(self.ext_mgr) + self.controller.servicegroup_api.service_is_up = mock.MagicMock( + return_value=True) + + def test_view_hypervisor_service_status(self): + self._prepare_extension() + result = self.controller._view_hypervisor( + TEST_HYPER, False) + 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, False) + self.assertEqual('down', result['state']) + + hyper = copy.deepcopy(TEST_HYPER) + hyper['service']['disabled'] = True + result = self.controller._view_hypervisor(hyper, False) + self.assertEqual('disabled', result['status']) + + def test_view_hypervisor_detail_status(self): + self._prepare_extension() + + result = self.controller._view_hypervisor( + TEST_HYPER, True) + + self.assertEqual('enabled', result['status']) + self.assertEqual('up', result['state']) + self.assertIsNone(result['service']['disabled_reason']) + + self.controller.servicegroup_api.service_is_up.return_value = False + result = self.controller._view_hypervisor( + TEST_HYPER, True) + self.assertEqual('down', result['state']) + + hyper = copy.deepcopy(TEST_HYPER) + hyper['service']['disabled'] = True + hyper['service']['disabled_reason'] = "fake" + result = self.controller._view_hypervisor(hyper, True) + self.assertEqual('disabled', result['status'],) + self.assertEqual('fake', result['service']['disabled_reason']) diff --git a/nova/tests/api/openstack/compute/plugins/v3/test_hypervisors.py b/nova/tests/api/openstack/compute/plugins/v3/test_hypervisors.py index 7d746c8148d8..039dae759c97 100644 --- a/nova/tests/api/openstack/compute/plugins/v3/test_hypervisors.py +++ b/nova/tests/api/openstack/compute/plugins/v3/test_hypervisors.py @@ -13,6 +13,9 @@ # License for the specific language governing permissions and limitations # under the License. +import copy + +import mock from webob import exc from nova.api.openstack.compute.plugins.v3 import hypervisors @@ -32,6 +35,7 @@ TEST_HYPERS = [ topic="compute_topic", report_count=5, disabled=False, + disabled_reason=None, availability_zone="nova"), vcpus=4, memory_mb=10 * 1024, @@ -57,6 +61,7 @@ TEST_HYPERS = [ topic="compute_topic", report_count=5, disabled=False, + disabled_reason=None, availability_zone="nova"), vcpus=4, memory_mb=10 * 1024, @@ -134,6 +139,8 @@ class HypervisorsTest(test.NoDBTestCase): def setUp(self): super(HypervisorsTest, self).setUp() self.controller = hypervisors.HypervisorsController() + self.controller.servicegroup_api.service_is_up = mock.MagicMock( + return_value=True) self.stubs.Set(db, 'compute_node_get_all', fake_compute_node_get_all) self.stubs.Set(db, 'compute_node_search_by_hypervisor', @@ -148,7 +155,9 @@ class HypervisorsTest(test.NoDBTestCase): def test_view_hypervisor_nodetail_noservers(self): result = self.controller._view_hypervisor(TEST_HYPERS[0], False) - self.assertEqual(result, dict(id=1, hypervisor_hostname="hyper1")) + self.assertEqual(dict(id=1, hypervisor_hostname="hyper1", + state='up', status='enabled'), + result) def test_view_hypervisor_detail_noservers(self): result = self.controller._view_hypervisor(TEST_HYPERS[0], True) @@ -156,6 +165,8 @@ class HypervisorsTest(test.NoDBTestCase): self.assertEqual(result, dict( id=1, hypervisor_hostname="hyper1", + state='up', + status='enabled', vcpus=4, memory_mb=10 * 1024, local_gb=250, @@ -171,7 +182,7 @@ class HypervisorsTest(test.NoDBTestCase): cpu_info='cpu_info', disk_available_least=100, host_ip='1.1.1.1', - service=dict(id=1, host='compute1'))) + service=dict(id=1, host='compute1', disabled_reason=None))) def test_view_hypervisor_servers(self): result = self.controller._view_hypervisor(TEST_HYPERS[0], False, @@ -180,20 +191,44 @@ class HypervisorsTest(test.NoDBTestCase): self.assertEqual(result, dict( id=1, hypervisor_hostname="hyper1", + state='up', + status='enabled', servers=[ dict(name="inst1", id="uuid1"), dict(name="inst2", id="uuid2"), dict(name="inst3", id="uuid3"), dict(name="inst4", id="uuid4")])) + def test_view_hypervisor_service_status(self): + result = self.controller._view_hypervisor(TEST_HYPERS[0], False) + 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_HYPERS[0], False) + self.assertEqual('down', result['state']) + self.assertEqual('enabled', result['status']) + + hyper = copy.deepcopy(TEST_HYPERS[0]) + hyper['service']['disabled'] = True + result = self.controller._view_hypervisor(hyper, False) + self.assertEqual('down', result['state']) + self.assertEqual('disabled', result['status']) + def test_index(self): req = fakes.HTTPRequestV3.blank('/os-hypervisors', use_admin_context=True) result = self.controller.index(req) self.assertEqual(result, dict(hypervisors=[ - dict(id=1, hypervisor_hostname="hyper1"), - dict(id=2, hypervisor_hostname="hyper2")])) + dict(id=1, + hypervisor_hostname="hyper1", + state='up', + status='enabled'), + dict(id=2, + hypervisor_hostname="hyper2", + state='up', + status='enabled')])) def test_index_non_admin(self): req = fakes.HTTPRequestV3.blank('/os-hypervisors') @@ -207,8 +242,11 @@ class HypervisorsTest(test.NoDBTestCase): self.assertEqual(result, dict(hypervisors=[ dict(id=1, - service=dict(id=1, host="compute1"), + service=dict( + id=1, host="compute1", disabled_reason=None), vcpus=4, + state='up', + status='enabled', memory_mb=10 * 1024, local_gb=250, vcpus_used=2, @@ -225,8 +263,11 @@ class HypervisorsTest(test.NoDBTestCase): disk_available_least=100, host_ip='1.1.1.1'), dict(id=2, - service=dict(id=2, host="compute2"), + service=dict(id=2, host="compute2", + disabled_reason=None), vcpus=4, + state='up', + status='enabled', memory_mb=10 * 1024, local_gb=250, vcpus_used=2, @@ -265,8 +306,10 @@ class HypervisorsTest(test.NoDBTestCase): self.assertEqual(result, dict(hypervisor=dict( id=1, - service=dict(id=1, host="compute1"), + service=dict(id=1, host="compute1", disabled_reason=None), vcpus=4, + state='up', + status='enabled', memory_mb=10 * 1024, local_gb=250, vcpus_used=2, @@ -319,6 +362,8 @@ class HypervisorsTest(test.NoDBTestCase): self.assertEqual(result, dict(hypervisor=dict( id=1, hypervisor_hostname="hyper1", + state='up', + status='enabled', uptime="fake uptime"))) def test_uptime_non_integer_id(self): @@ -336,8 +381,10 @@ class HypervisorsTest(test.NoDBTestCase): use_admin_context=True) result = self.controller.search(req) self.assertEqual(result, dict(hypervisors=[ - dict(id=1, hypervisor_hostname="hyper1"), - dict(id=2, hypervisor_hostname="hyper2")])) + dict(id=1, hypervisor_hostname="hyper1", + state='up', status='enabled'), + dict(id=2, hypervisor_hostname="hyper2", + state='up', status='enabled')])) def test_search_non_exist(self): def fake_compute_node_search_by_hypervisor_return_empty(context, @@ -362,6 +409,8 @@ class HypervisorsTest(test.NoDBTestCase): self.assertEqual(result, dict(hypervisor= dict(id=1, hypervisor_hostname="hyper1", + state='up', + status='enabled', servers=[ dict(name="inst1", id="uuid1"), dict(name="inst3", id="uuid3")]))) @@ -387,6 +436,8 @@ class HypervisorsTest(test.NoDBTestCase): self.assertEqual(result, dict(hypervisor= dict(id=1, hypervisor_hostname="hyper1", + state='up', + status='enabled', servers=[]))) def test_servers_with_non_integer_hypervisor_id(self): diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl index ac203b83d4ea..6a243b5af4fb 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl @@ -416,6 +416,14 @@ "namespace": "http://docs.openstack.org/compute/ext/extended_hypervisors/api/v1.1", "updated": "%(isotime)s" }, + { + "alias": "os-hypervisor-status", + "description": "%(text)s", + "links": [], + "name": "HypervisorStatus", + "namespace": "http://docs.openstack.org/compute/ext/hypervisor_status/api/v1.1", + "updated": "%(isotime)s" + }, { "alias": "os-server-external-events", "description": "%(text)s", diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl index 308d32136bdd..3e5ac8ea27f4 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl @@ -150,6 +150,9 @@ %(text)s + + %(text)s + %(text)s diff --git a/nova/tests/integrated/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.json.tpl b/nova/tests/integrated/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.json.tpl new file mode 100644 index 000000000000..14464ccf4d06 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.json.tpl @@ -0,0 +1,27 @@ +{ + "hypervisor": { + "cpu_info": "?", + "current_workload": 0, + "disk_available_least": 0, + "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, + "state": "up", + "status": "enabled", + "service": { + "host": "%(host_name)s", + "id": 2, + "disabled_reason": null + }, + "vcpus": 1, + "vcpus_used": 0 + } +} diff --git a/nova/tests/integrated/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.xml.tpl b/nova/tests/integrated/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.xml.tpl new file mode 100644 index 000000000000..6cfd860af530 --- /dev/null +++ b/nova/tests/integrated/api_samples/os-hypervisor-status/hypervisors-show-with-status-resp.xml.tpl @@ -0,0 +1,4 @@ + + + + diff --git a/nova/tests/integrated/test_api_samples.py b/nova/tests/integrated/test_api_samples.py index 0d7dc6311183..fedcee8fe081 100644 --- a/nova/tests/integrated/test_api_samples.py +++ b/nova/tests/integrated/test_api_samples.py @@ -1771,7 +1771,7 @@ class ServicesJsonTest(ApiSampleTestBaseV2): 'status': 'disabled', 'state': 'up'} subs.update(self._get_regexes()) - return self._verify_response('services-get-resp', + self._verify_response('services-get-resp', subs, response, 200) def test_service_disable_log_reason(self): @@ -3584,6 +3584,12 @@ class HypervisorsSampleJsonTests(ApiSampleTestBaseV2): extension_name = ("nova.api.openstack.compute.contrib.hypervisors." "Hypervisors") + def setUp(self): + super(HypervisorsSampleJsonTests, self).setUp() + mock.patch("nova.servicegroup.API.service_is_up", + return_value=True).start() + self.addCleanup(mock.patch.stopall) + def test_hypervisors_list(self): response = self._do_get('os-hypervisors') self._verify_response('hypervisors-list-resp', {}, response, 200) @@ -3646,9 +3652,31 @@ class ExtendedHypervisorsJsonTest(ApiSampleTestBaseV2): class ExtendedHypervisorsXmlTest(ExtendedHypervisorsJsonTest): + ctype = "xml" + + +class HypervisorStatusJsonTest(ApiSampleTestBaseV2): + extends_name = ("nova.api.openstack.compute.contrib." + "hypervisors.Hypervisors") + extension_name = ("nova.api.openstack.compute.contrib." + "hypervisor_status.Hypervisor_status") + + def test_hypervisors_show_with_status(self): + hypervisor_id = 1 + subs = { + 'hypervisor_id': hypervisor_id + } + response = self._do_get('os-hypervisors/%s' % hypervisor_id) + subs.update(self._get_regexes()) + self._verify_response('hypervisors-show-with-status-resp', + subs, response, 200) + + +class HypervisorStatusXmlTest(HypervisorStatusJsonTest): ctype = 'xml' +@mock.patch("nova.servicegroup.API.service_is_up", return_value=True) class HypervisorsCellsSampleJsonTests(ApiSampleTestBaseV2): extension_name = ("nova.api.openstack.compute.contrib.hypervisors." "Hypervisors") @@ -3657,9 +3685,11 @@ class HypervisorsCellsSampleJsonTests(ApiSampleTestBaseV2): self.flags(enable=True, cell_type='api', group='cells') super(HypervisorsCellsSampleJsonTests, self).setUp() - def test_hypervisor_uptime(self): - fake_hypervisor = {'service': {'host': 'fake-mini'}, 'id': 1, - 'hypervisor_hostname': 'fake-mini'} + def test_hypervisor_uptime(self, mocks): + fake_hypervisor = {'service': {'host': 'fake-mini', + 'disabled': False, + 'disabled_reason': None}, + 'id': 1, 'hypervisor_hostname': 'fake-mini'} def fake_get_host_uptime(self, context, hyp): return (" 08:32:11 up 93 days, 18:25, 12 users, load average:" diff --git a/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-detail-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-detail-resp.json.tpl index fb473a03bbcb..2777eb488740 100644 --- a/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-detail-resp.json.tpl +++ b/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-detail-resp.json.tpl @@ -3,6 +3,8 @@ { "cpu_info": "?", "current_workload": 0, + "state": "up", + "status": "enabled", "disk_available_least": 0, "host_ip": "%(ip)s", "free_disk_gb": 1028, @@ -18,7 +20,8 @@ "running_vms": 0, "service": { "host": "%(host_name)s", - "id": 2 + "id": 2, + "disabled_reason": null }, "vcpus": 1, "vcpus_used": 0 diff --git a/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-list-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-list-resp.json.tpl index 8d94021274fb..710cdfcf9cb0 100644 --- a/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-list-resp.json.tpl +++ b/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-list-resp.json.tpl @@ -2,7 +2,9 @@ "hypervisors": [ { "hypervisor_hostname": "fake-mini", + "state": "up", + "status": "enabled", "id": 1 } ] -} \ No newline at end of file +} diff --git a/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-search-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-search-resp.json.tpl index 8d94021274fb..375627499df6 100644 --- a/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-search-resp.json.tpl +++ b/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-search-resp.json.tpl @@ -2,7 +2,9 @@ "hypervisors": [ { "hypervisor_hostname": "fake-mini", - "id": 1 + "id": 1, + "state": "up", + "status": "enabled" } ] -} \ No newline at end of file +} diff --git a/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-servers-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-servers-resp.json.tpl index 934ef0c02db7..710b05b9309a 100644 --- a/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-servers-resp.json.tpl +++ b/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-servers-resp.json.tpl @@ -2,6 +2,8 @@ "hypervisor": { "hypervisor_hostname": "fake-mini", "id": 1, + "state": "up", + "status": "enabled", "servers": [] } -} \ No newline at end of file +} diff --git a/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-show-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-show-resp.json.tpl index a1e5f2080b45..f125da01af9f 100644 --- a/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-show-resp.json.tpl +++ b/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-show-resp.json.tpl @@ -3,6 +3,8 @@ "cpu_info": "?", "current_workload": 0, "disk_available_least": 0, + "state": "up", + "status": "enabled", "host_ip": "%(ip)s", "free_disk_gb": 1028, "free_ram_mb": 7680, @@ -17,7 +19,8 @@ "running_vms": 0, "service": { "host": "%(host_name)s", - "id": 2 + "id": 2, + "disabled_reason": null }, "vcpus": 1, "vcpus_used": 0 diff --git a/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-uptime-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-uptime-resp.json.tpl index 8a36c65f232a..e2f6d2e47e74 100644 --- a/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-uptime-resp.json.tpl +++ b/nova/tests/integrated/v3/api_samples/os-hypervisors/hypervisors-uptime-resp.json.tpl @@ -2,6 +2,8 @@ "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" } } diff --git a/nova/tests/integrated/v3/api_samples/os-pci/hypervisors-pci-detail-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-pci/hypervisors-pci-detail-resp.json.tpl index 69c5df943fa2..f2bf2bc02c84 100644 --- a/nova/tests/integrated/v3/api_samples/os-pci/hypervisors-pci-detail-resp.json.tpl +++ b/nova/tests/integrated/v3/api_samples/os-pci/hypervisors-pci-detail-resp.json.tpl @@ -2,6 +2,8 @@ "hypervisors": [ { "cpu_info": "?", + "state": "up", + "status": "enabled", "current_workload": 0, "disk_available_least": 0, "host_ip": "%(ip)s", @@ -30,7 +32,8 @@ "running_vms": 0, "service": { "host": "043b3cacf6f34c90a7245151fc8ebcda", - "id": 2 + "id": 2, + "disabled_reason": null }, "vcpus": 1, "vcpus_used": 0 diff --git a/nova/tests/integrated/v3/api_samples/os-pci/hypervisors-pci-show-resp.json.tpl b/nova/tests/integrated/v3/api_samples/os-pci/hypervisors-pci-show-resp.json.tpl index 6a6fbe3d3b47..3c0fc0abcd78 100644 --- a/nova/tests/integrated/v3/api_samples/os-pci/hypervisors-pci-show-resp.json.tpl +++ b/nova/tests/integrated/v3/api_samples/os-pci/hypervisors-pci-show-resp.json.tpl @@ -2,6 +2,8 @@ "hypervisor": { "cpu_info": "?", "current_workload": 0, + "state": "up", + "status": "enabled", "disk_available_least": 0, "host_ip": "%(ip)s", "free_disk_gb": 1028, @@ -29,7 +31,8 @@ "running_vms": 0, "service": { "host": "043b3cacf6f34c90a7245151fc8ebcda", - "id": 2 + "id": 2, + "disabled_reason": null }, "vcpus": 1, "vcpus_used": 0 diff --git a/nova/tests/integrated/v3/test_pci.py b/nova/tests/integrated/v3/test_pci.py index 30c664dbf2fd..91aba3f9c7df 100644 --- a/nova/tests/integrated/v3/test_pci.py +++ b/nova/tests/integrated/v3/test_pci.py @@ -12,6 +12,8 @@ # License for the specific language governing permissions and limitations # under the License. +import mock + from nova import db from nova.openstack.common import jsonutils from nova.tests.integrated.v3 import api_sample_base @@ -83,6 +85,8 @@ class ExtendedHyervisorPciSampleJsonTest(api_sample_base.ApiSampleTestBaseV3): "current_workload": 0, "disk_available_least": 0, "host_ip": "1.1.1.1", + "state": "up", + "status": "enabled", "free_disk_gb": 1028, "free_ram_mb": 7680, "hypervisor_hostname": "fake-mini", @@ -94,8 +98,10 @@ class ExtendedHyervisorPciSampleJsonTest(api_sample_base.ApiSampleTestBaseV3): "memory_mb": 8192, "memory_mb_used": 512, "running_vms": 0, - "service": {"host": '043b3cacf6f34c90a724' - '5151fc8ebcda'}, + "service": {"host": '043b3cacf6f34c90a' + '7245151fc8ebcda', + "disabled": False, + "disabled_reason": None}, "vcpus": 1, "vcpus_used": 0, "service_id": 2, @@ -110,13 +116,12 @@ class ExtendedHyervisorPciSampleJsonTest(api_sample_base.ApiSampleTestBaseV3): ' "0x1"]]', "key1": "value1"}}]} - def test_pci_show(self): - def fake_compute_node_get(context, id): - self.fake_compute_node['pci_stats'] = jsonutils.dumps( - self.fake_compute_node['pci_stats']) - return self.fake_compute_node - - self.stubs.Set(db, 'compute_node_get', fake_compute_node_get) + @mock.patch("nova.servicegroup.API.service_is_up", return_value=True) + @mock.patch("nova.db.compute_node_get") + def test_pci_show(self, mock_db, mock_service): + self.fake_compute_node['pci_stats'] = jsonutils.dumps( + self.fake_compute_node['pci_stats']) + mock_db.return_value = self.fake_compute_node hypervisor_id = 1 response = self._do_get('os-hypervisors/%s' % hypervisor_id) subs = { @@ -126,13 +131,13 @@ class ExtendedHyervisorPciSampleJsonTest(api_sample_base.ApiSampleTestBaseV3): self._verify_response('hypervisors-pci-show-resp', subs, response, 200) - def test_pci_detail(self): - def fake_compute_node_get_all(context): - self.fake_compute_node['pci_stats'] = jsonutils.dumps( - self.fake_compute_node['pci_stats']) - return [self.fake_compute_node] + @mock.patch("nova.servicegroup.API.service_is_up", return_value=True) + @mock.patch("nova.db.compute_node_get_all") + def test_pci_detail(self, mock_db, mock_service): + self.fake_compute_node['pci_stats'] = jsonutils.dumps( + self.fake_compute_node['pci_stats']) - self.stubs.Set(db, 'compute_node_get_all', fake_compute_node_get_all) + mock_db.return_value = [self.fake_compute_node] hypervisor_id = 1 subs = { 'hypervisor_id': hypervisor_id