diff --git a/api-ref/source/parameters.yaml b/api-ref/source/parameters.yaml index 12439a51bc9b..6f666c083d06 100644 --- a/api-ref/source/parameters.yaml +++ b/api-ref/source/parameters.yaml @@ -1042,7 +1042,23 @@ sort_key_flavor: 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 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 required: false type: string diff --git a/nova/api/openstack/compute/schemas/flavors.py b/nova/api/openstack/compute/schemas/flavors.py index 91ca03e5d525..96a6f6b4e80a 100644 --- a/nova/api/openstack/compute/schemas/flavors.py +++ b/nova/api/openstack/compute/schemas/flavors.py @@ -13,6 +13,16 @@ # under the License. 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 = { 'type': 'object', 'properties': { @@ -22,8 +32,10 @@ index_query = { 'is_public': parameter_types.multi_params({'type': 'string'}), 'minRam': parameter_types.multi_params({'type': 'string'}), 'minDisk': parameter_types.multi_params({'type': 'string'}), - 'sort_key': parameter_types.multi_params({'type': 'string'}), - 'sort_dir': parameter_types.multi_params({'type': 'string'}) + 'sort_key': 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. # As of now Schema validation stripped out the additional parameters and diff --git a/nova/tests/functional/api_sample_tests/test_flavors.py b/nova/tests/functional/api_sample_tests/test_flavors.py index b2b42975b924..de78d00a52a9 100644 --- a/nova/tests/functional/api_sample_tests/test_flavors.py +++ b/nova/tests/functional/api_sample_tests/test_flavors.py @@ -22,6 +22,11 @@ class FlavorsSampleJsonTest(api_sample_base.ApiSampleTestBaseV21): sample_dir = 'flavors' flavor_show_id = '1' 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): 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') 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): response = self._do_get('flavors/detail') self._verify_response('flavors-detail-resp', self.subs, response, 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): microversion = '2.55'