From 38f6ae7c1fd46f94292f55bec50a90e1805d6225 Mon Sep 17 00:00:00 2001 From: ghanshyam Date: Fri, 20 Oct 2017 12:57:36 +0300 Subject: [PATCH] Implement query param schema for host index GET host API accept query param to filter the hosts. This commit adds json schema to validating the valid query parameters. There is no change in API behaviour and additionalProperty is kept True for backward compatibility. Partially implements blueprint json-schema-validation-for-query-param Change-Id: I272a2950090943372f4563d59ea25d6b5b6c1033 --- nova/api/openstack/compute/hosts.py | 1 + nova/api/openstack/compute/schemas/hosts.py | 14 +++++ .../unit/api/openstack/compute/test_hosts.py | 55 ++++++++++++++++--- 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/nova/api/openstack/compute/hosts.py b/nova/api/openstack/compute/hosts.py index ba5fac3db853..a2eac66a9c19 100644 --- a/nova/api/openstack/compute/hosts.py +++ b/nova/api/openstack/compute/hosts.py @@ -40,6 +40,7 @@ class HostController(wsgi.Controller): super(HostController, self).__init__() @wsgi.Controller.api_version("2.1", "2.42") + @validation.query_schema(hosts.index_query) @extensions.expected_errors(()) def index(self, req): """Returns a dict in the format diff --git a/nova/api/openstack/compute/schemas/hosts.py b/nova/api/openstack/compute/schemas/hosts.py index 3905fc63aa2d..e708e8a1ca31 100644 --- a/nova/api/openstack/compute/schemas/hosts.py +++ b/nova/api/openstack/compute/schemas/hosts.py @@ -12,6 +12,8 @@ # License for the specific language governing permissions and limitations # under the License. +from nova.api.validation import parameter_types + update = { 'type': 'object', 'properties': { @@ -34,3 +36,15 @@ update = { }, 'additionalProperties': False } + +index_query = { + 'type': 'object', + 'properties': { + 'zone': parameter_types.multi_params({'type': 'string'}) + }, + # NOTE(gmann): This is kept True to keep backward compatibility. + # As of now Schema validation stripped out the additional parameters and + # does not raise 400. In the future, we may block the additional parameters + # by bump in Microversion. + 'additionalProperties': True +} diff --git a/nova/tests/unit/api/openstack/compute/test_hosts.py b/nova/tests/unit/api/openstack/compute/test_hosts.py index 308202e8b1d9..b7a85d9a3fe0 100644 --- a/nova/tests/unit/api/openstack/compute/test_hosts.py +++ b/nova/tests/unit/api/openstack/compute/test_hosts.py @@ -17,7 +17,6 @@ import mock import testtools import webob.exc -from nova.api.openstack import api_version_request as api_version from nova.api.openstack.compute import hosts as os_hosts_v21 from nova.compute import power_state from nova.compute import vm_states @@ -129,12 +128,6 @@ def _create_instance_dict(**kwargs): return inst -class FakeRequestWithNovaZone(object): - environ = {"nova.context": context_maker.get_admin_context()} - GET = {"zone": "nova"} - api_version_request = api_version.APIVersionRequest('2.1') - - class HostTestCaseV21(test.TestCase): """Test Case for hosts.""" validation_ex = exception.ValidationError @@ -178,6 +171,49 @@ class HostTestCaseV21(test.TestCase): hosts = result['hosts'] self.assertEqual(fake_hosts.HOST_LIST, hosts) + def test_list_host_with_multi_filter(self): + query_string = 'zone=nova1&zone=nova' + req = fakes.HTTPRequest.blank('', use_admin_context=True, + query_string=query_string) + result = self.controller.index(req) + self.assertIn('hosts', result) + hosts = result['hosts'] + self.assertEqual(fake_hosts.HOST_LIST_NOVA_ZONE, hosts) + + def test_list_host_query_allow_negative_int_as_string(self): + req = fakes.HTTPRequest.blank('', use_admin_context=True, + query_string='zone=-1') + result = self.controller.index(req) + self.assertIn('hosts', result) + hosts = result['hosts'] + self.assertEqual([], hosts) + + def test_list_host_query_allow_int_as_string(self): + req = fakes.HTTPRequest.blank('', use_admin_context=True, + query_string='zone=123') + result = self.controller.index(req) + self.assertIn('hosts', result) + hosts = result['hosts'] + self.assertEqual([], hosts) + + def test_list_host_with_unknown_filter(self): + query_string = 'unknown_filter=abc' + req = fakes.HTTPRequest.blank('', use_admin_context=True, + query_string=query_string) + result = self.controller.index(req) + self.assertIn('hosts', result) + hosts = result['hosts'] + self.assertEqual(fake_hosts.HOST_LIST, hosts) + + def test_list_host_with_hypervisor_and_additional_filter(self): + query_string = 'zone=nova&additional_filter=nova2' + req = fakes.HTTPRequest.blank('', use_admin_context=True, + query_string=query_string) + result = self.controller.index(req) + self.assertIn('hosts', result) + hosts = result['hosts'] + self.assertEqual(fake_hosts.HOST_LIST_NOVA_ZONE, hosts) + def test_disable_host(self): self._test_host_update('host_c1', 'status', 'disable', 'disabled') self._test_host_update('host_c2', 'status', 'disable', 'enabled') @@ -383,7 +419,10 @@ class HostTestCaseV21(test.TestCase): self.controller.show, self.req, s_ref['host']) def test_list_hosts_with_zone(self): - result = self.controller.index(FakeRequestWithNovaZone()) + query_string = 'zone=nova' + req = fakes.HTTPRequest.blank('', use_admin_context=True, + query_string=query_string) + result = self.controller.index(req) self.assertIn('hosts', result) hosts = result['hosts'] self.assertEqual(fake_hosts.HOST_LIST_NOVA_ZONE, hosts)