Implement query param schema for simple_tenant_usage
GET simple_tenant_usage API accept query param to filter the tenant usage. This commit adds json schema to validate the valid query parameters. There is no change in API behaviour and additionalProperties is kept True for backward compatibility. Partially implements blueprint json-schema-validation-for-query-param Change-Id: I24726fd9a82617798a13597ad9883db22a4a9846
This commit is contained in:
parent
2463c962ee
commit
3fc7609931
|
@ -0,0 +1,52 @@
|
|||
# Copyright 2017 NEC Corporation.
|
||||
#
|
||||
# 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
|
||||
|
||||
from nova.api.validation import parameter_types
|
||||
|
||||
|
||||
index_query = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'start': parameter_types.multi_params({'type': 'string'}),
|
||||
'end': parameter_types.multi_params({'type': 'string'}),
|
||||
'detailed': 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
|
||||
}
|
||||
|
||||
show_query = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'start': parameter_types.multi_params({'type': 'string'}),
|
||||
'end': 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
|
||||
}
|
||||
|
||||
index_query_v240 = copy.deepcopy(index_query)
|
||||
index_query_v240['properties'].update(
|
||||
parameter_types.pagination_parameters)
|
||||
|
||||
show_query_v240 = copy.deepcopy(show_query)
|
||||
show_query_v240['properties'].update(
|
||||
parameter_types.pagination_parameters)
|
|
@ -22,9 +22,11 @@ import six.moves.urllib.parse as urlparse
|
|||
from webob import exc
|
||||
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack.compute.schemas import simple_tenant_usage as schema
|
||||
from nova.api.openstack.compute.views import usages as usages_view
|
||||
from nova.api.openstack import extensions
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.api import validation
|
||||
import nova.conf
|
||||
from nova import context as nova_context
|
||||
from nova import exception
|
||||
|
@ -261,24 +263,28 @@ class SimpleTenantUsageController(wsgi.Controller):
|
|||
return (period_start, period_stop, detailed)
|
||||
|
||||
@wsgi.Controller.api_version("2.40")
|
||||
@validation.query_schema(schema.index_query_v240)
|
||||
@extensions.expected_errors(400)
|
||||
def index(self, req):
|
||||
"""Retrieve tenant_usage for all tenants."""
|
||||
return self._index(req, links=True)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.39") # noqa
|
||||
@validation.query_schema(schema.index_query)
|
||||
@extensions.expected_errors(400)
|
||||
def index(self, req):
|
||||
"""Retrieve tenant_usage for all tenants."""
|
||||
return self._index(req)
|
||||
|
||||
@wsgi.Controller.api_version("2.40")
|
||||
@validation.query_schema(schema.show_query_v240)
|
||||
@extensions.expected_errors(400)
|
||||
def show(self, req, id):
|
||||
"""Retrieve tenant_usage for a specified tenant."""
|
||||
return self._show(req, id, links=True)
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.39") # noqa
|
||||
@validation.query_schema(schema.show_query)
|
||||
@extensions.expected_errors(400)
|
||||
def show(self, req, id):
|
||||
"""Retrieve tenant_usage for a specified tenant."""
|
||||
|
|
|
@ -367,6 +367,53 @@ class SimpleTenantUsageTestV21(test.TestCase):
|
|||
self._test_get_tenants_usage_with_one_date(
|
||||
'start=%s' % (NOW - datetime.timedelta(5)).isoformat())
|
||||
|
||||
def test_index_additional_query_parameters(self):
|
||||
req = fakes.HTTPRequest.blank('?start=%s&end=%s&additional=1' %
|
||||
(START.isoformat(), STOP.isoformat()),
|
||||
version=self.version)
|
||||
res = self.controller.index(req)
|
||||
self.assertIn('tenant_usages', res)
|
||||
|
||||
def _test_index_duplicate_query_parameters_validation(self, params):
|
||||
for param, value in params.items():
|
||||
req = fakes.HTTPRequest.blank('?start=%s&%s=%s&%s=%s' %
|
||||
(START.isoformat(), param, value, param, value),
|
||||
version=self.version)
|
||||
|
||||
res = self.controller.index(req)
|
||||
self.assertIn('tenant_usages', res)
|
||||
|
||||
def test_index_duplicate_query_parameters_validation(self):
|
||||
params = {
|
||||
'start': START.isoformat(),
|
||||
'end': STOP.isoformat(),
|
||||
'detailed': 1
|
||||
}
|
||||
self._test_index_duplicate_query_parameters_validation(params)
|
||||
|
||||
def test_show_additional_query_parameters(self):
|
||||
req = fakes.HTTPRequest.blank('?start=%s&end=%s&additional=1' %
|
||||
(START.isoformat(), STOP.isoformat()),
|
||||
version=self.version)
|
||||
res = self.controller.show(req, 1)
|
||||
self.assertIn('tenant_usage', res)
|
||||
|
||||
def _test_show_duplicate_query_parameters_validation(self, params):
|
||||
for param, value in params.items():
|
||||
req = fakes.HTTPRequest.blank('?start=%s&%s=%s&%s=%s' %
|
||||
(START.isoformat(), param, value, param, value),
|
||||
version=self.version)
|
||||
|
||||
res = self.controller.show(req, 1)
|
||||
self.assertIn('tenant_usage', res)
|
||||
|
||||
def test_show_duplicate_query_parameters_validation(self):
|
||||
params = {
|
||||
'start': START.isoformat(),
|
||||
'end': STOP.isoformat()
|
||||
}
|
||||
self._test_show_duplicate_query_parameters_validation(params)
|
||||
|
||||
|
||||
class SimpleTenantUsageTestV40(SimpleTenantUsageTestV21):
|
||||
version = '2.40'
|
||||
|
@ -383,6 +430,29 @@ class SimpleTenantUsageTestV40(SimpleTenantUsageTestV21):
|
|||
self._test_verify_index(START, STOP,
|
||||
limit=SERVERS * TENANTS)
|
||||
|
||||
@mock.patch('nova.objects.InstanceList.get_active_by_window_joined',
|
||||
fake_get_active_by_window_joined)
|
||||
def test_index_duplicate_query_parameters_validation(self):
|
||||
params = {
|
||||
'start': START.isoformat(),
|
||||
'end': STOP.isoformat(),
|
||||
'detailed': 1,
|
||||
'limit': 1,
|
||||
'marker': 1
|
||||
}
|
||||
self._test_index_duplicate_query_parameters_validation(params)
|
||||
|
||||
@mock.patch('nova.objects.InstanceList.get_active_by_window_joined',
|
||||
fake_get_active_by_window_joined)
|
||||
def test_show_duplicate_query_parameters_validation(self):
|
||||
params = {
|
||||
'start': START.isoformat(),
|
||||
'end': STOP.isoformat(),
|
||||
'limit': 1,
|
||||
'marker': 1
|
||||
}
|
||||
self._test_show_duplicate_query_parameters_validation(params)
|
||||
|
||||
|
||||
class SimpleTenantUsageLimitsTestV21(test.TestCase):
|
||||
version = '2.1'
|
||||
|
@ -449,6 +519,36 @@ class SimpleTenantUsageLimitsTestV240(SimpleTenantUsageLimitsTestV21):
|
|||
self.assertRaises(
|
||||
webob.exc.HTTPBadRequest, self.controller.index, req)
|
||||
|
||||
def test_index_with_invalid_non_int_limit(self):
|
||||
req = self._get_request('?start=%s&end=%s&limit=-3')
|
||||
self.assertRaises(exception.ValidationError,
|
||||
self.controller.index, req)
|
||||
|
||||
def test_index_with_invalid_string_limit(self):
|
||||
req = self._get_request('?start=%s&end=%s&limit=abc')
|
||||
self.assertRaises(exception.ValidationError,
|
||||
self.controller.index, req)
|
||||
|
||||
def test_index_duplicate_query_with_invalid_string_limit(self):
|
||||
req = self._get_request('?start=%s&end=%s&limit=3&limit=abc')
|
||||
self.assertRaises(exception.ValidationError,
|
||||
self.controller.index, req)
|
||||
|
||||
def test_show_with_invalid_non_int_limit(self):
|
||||
req = self._get_request('?start=%s&end=%s&limit=-3')
|
||||
self.assertRaises(exception.ValidationError,
|
||||
self.controller.show, req)
|
||||
|
||||
def test_show_with_invalid_string_limit(self):
|
||||
req = self._get_request('?start=%s&end=%s&limit=abc')
|
||||
self.assertRaises(exception.ValidationError,
|
||||
self.controller.show, req)
|
||||
|
||||
def test_show_duplicate_query_with_invalid_string_limit(self):
|
||||
req = self._get_request('?start=%s&end=%s&limit=3&limit=abc')
|
||||
self.assertRaises(exception.ValidationError,
|
||||
self.controller.show, req)
|
||||
|
||||
|
||||
class SimpleTenantUsageControllerTestV21(test.TestCase):
|
||||
controller = simple_tenant_usage_v21.SimpleTenantUsageController()
|
||||
|
|
Loading…
Reference in New Issue