Retrun 400 if invalid query parameters are specified

The following APIs return 500 error currently
if an invalid sort key or an invalid sort direction
query parameter is specified.

- GET /flavors
- GET /flavors/detail

Make the APIs return 400 error in that case.

Change-Id: I1d6d2c1f734b28dbea5c67cf88717149dd4911d7
Closes-Bug: #1835925
(cherry picked from commit ae7ebdf45e)
This commit is contained in:
Takashi NATSUME 2019-07-12 12:29:49 +09:00
parent 11fde850e6
commit d7e4e47d57
3 changed files with 76 additions and 3 deletions

View File

@ -1231,7 +1231,23 @@ sort_key_flavor:
Sorts by a flavor attribute. Default attribute is ``flavorid``. You can specify Sorts by a flavor attribute. Default attribute is ``flavorid``. You can specify
multiple pairs of sort key and sort direction query parameters. If you omit the multiple pairs of sort key and sort direction query parameters. If you omit the
sort direction in a pair, the API uses the natural sorting direction of the flavor sort direction in a pair, the API uses the natural sorting direction of the flavor
``sort_key`` attribute. ``sort_key`` attribute. The sort keys are limited to:
- ``created_at``
- ``description``
- ``disabled``
- ``ephemeral_gb``
- ``flavorid``
- ``id``
- ``is_public``
- ``memory_mb``
- ``name``
- ``root_gb``
- ``rxtx_factor``
- ``swap``
- ``updated_at``
- ``vcpu_weight``
- ``vcpus``
in: query in: query
required: false required: false
type: string type: string

View File

@ -13,6 +13,16 @@
# under the License. # under the License.
from nova.api.validation import parameter_types from nova.api.validation import parameter_types
# NOTE(takashin): The following sort keys are defined for backward
# compatibility. If they are changed, the API microversion should be bumped.
VALID_SORT_KEYS = [
'created_at', 'description', 'disabled', 'ephemeral_gb', 'flavorid', 'id',
'is_public', 'memory_mb', 'name', 'root_gb', 'rxtx_factor', 'swap',
'updated_at', 'vcpu_weight', 'vcpus'
]
VALID_SORT_DIR = ['asc', 'desc']
index_query = { index_query = {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
@ -22,8 +32,10 @@ index_query = {
'is_public': parameter_types.multi_params({'type': 'string'}), 'is_public': parameter_types.multi_params({'type': 'string'}),
'minRam': parameter_types.multi_params({'type': 'string'}), 'minRam': parameter_types.multi_params({'type': 'string'}),
'minDisk': parameter_types.multi_params({'type': 'string'}), 'minDisk': parameter_types.multi_params({'type': 'string'}),
'sort_key': parameter_types.multi_params({'type': 'string'}), 'sort_key': parameter_types.multi_params({'type': 'string',
'sort_dir': parameter_types.multi_params({'type': 'string'}) 'enum': VALID_SORT_KEYS}),
'sort_dir': parameter_types.multi_params({'type': 'string',
'enum': VALID_SORT_DIR})
}, },
# NOTE(gmann): This is kept True to keep backward compatibility. # NOTE(gmann): This is kept True to keep backward compatibility.
# As of now Schema validation stripped out the additional parameters and # As of now Schema validation stripped out the additional parameters and

View File

@ -22,6 +22,11 @@ class FlavorsSampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
sample_dir = 'flavors' sample_dir = 'flavors'
flavor_show_id = '1' flavor_show_id = '1'
subs = {} subs = {}
sort_keys = ['created_at', 'description', 'disabled', 'ephemeral_gb',
'flavorid', 'id', 'is_public', 'memory_mb', 'name',
'root_gb', 'rxtx_factor', 'swap', 'updated_at',
'vcpu_weight', 'vcpus']
sort_dirs = ['asc', 'desc']
def test_flavors_get(self): def test_flavors_get(self):
response = self._do_get('flavors/%s' % self.flavor_show_id) response = self._do_get('flavors/%s' % self.flavor_show_id)
@ -31,11 +36,51 @@ class FlavorsSampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
response = self._do_get('flavors') response = self._do_get('flavors')
self._verify_response('flavors-list-resp', self.subs, response, 200) self._verify_response('flavors-list-resp', self.subs, response, 200)
def test_flavors_list_with_sort_key(self):
for sort_key in self.sort_keys:
response = self._do_get('flavors?sort_key=%s' % sort_key)
self._verify_response('flavors-list-resp', self.subs, response,
200)
def test_flavors_list_with_invalid_sort_key(self):
response = self._do_get('flavors?sort_key=invalid')
self.assertEqual(400, response.status_code)
def test_flavors_list_with_sort_dir(self):
for sort_dir in self.sort_dirs:
response = self._do_get('flavors?sort_dir=%s' % sort_dir)
self._verify_response('flavors-list-resp', self.subs, response,
200)
def test_flavors_list_with_invalid_sort_dir(self):
response = self._do_get('flavors?sort_dir=invalid')
self.assertEqual(400, response.status_code)
def test_flavors_detail(self): def test_flavors_detail(self):
response = self._do_get('flavors/detail') response = self._do_get('flavors/detail')
self._verify_response('flavors-detail-resp', self.subs, response, self._verify_response('flavors-detail-resp', self.subs, response,
200) 200)
def test_flavors_detail_with_sort_key(self):
for sort_key in self.sort_keys:
response = self._do_get('flavors/detail?sort_key=%s' % sort_key)
self._verify_response('flavors-detail-resp', self.subs, response,
200)
def test_flavors_detail_with_invalid_sort_key(self):
response = self._do_get('flavors/detail?sort_key=invalid')
self.assertEqual(400, response.status_code)
def test_flavors_detail_with_sort_dir(self):
for sort_dir in self.sort_dirs:
response = self._do_get('flavors/detail?sort_dir=%s' % sort_dir)
self._verify_response('flavors-detail-resp', self.subs, response,
200)
def test_flavors_detail_with_invalid_sort_dir(self):
response = self._do_get('flavors/detail?sort_dir=invalid')
self.assertEqual(400, response.status_code)
class FlavorsSampleJsonTest2_55(FlavorsSampleJsonTest): class FlavorsSampleJsonTest2_55(FlavorsSampleJsonTest):
microversion = '2.55' microversion = '2.55'