From ad9f66a7153a5b6358b99351017bda7d5bd50f5d Mon Sep 17 00:00:00 2001 From: Eric Harney Date: Wed, 12 Jul 2023 16:04:59 +0000 Subject: [PATCH] Coerce booleans to integer values in paginate_query (Grabbed from oslo.db's I4b90f1873 which fixes the same issue.) This fixes a failed request when a volume listing is requested with sorting by bootable:asc and with a marker id specified. It looks like we are due to replace our paginate_query() method with the one from oslo.db, as noted in the comments above the method. Closes-Bug: #2027532 Change-Id: Idf75e9cc8be6d9f0be320f8109e45b9b9f93dacf (cherry picked from commit 6d60a6b1ae4c95d4b202746caacd86293ea84620) --- cinder/common/sqlalchemyutils.py | 5 +++- cinder/tests/unit/api/v3/test_volumes.py | 25 ++++++++++++++++--- ...-sort-by-boolean-fix-49972c69007d5ebc.yaml | 6 +++++ 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 releasenotes/notes/bug-2027532-volume-list-sort-by-boolean-fix-49972c69007d5ebc.yaml diff --git a/cinder/common/sqlalchemyutils.py b/cinder/common/sqlalchemyutils.py index da8ab034d8e..c2db6e361a8 100644 --- a/cinder/common/sqlalchemyutils.py +++ b/cinder/common/sqlalchemyutils.py @@ -35,7 +35,8 @@ _TYPE_SCHEMA = { 'datetime': datetime.datetime(1900, 1, 1), 'big_integer': 0, 'integer': 0, - 'string': '' + 'string': '', + 'boolean': False, } @@ -155,6 +156,8 @@ def paginate_query(query, model, limit, sort_keys, marker=None, *[(model_attr.isnot(None), model_attr)], else_=default, ) + if isinstance(model_attr.type, sqlalchemy.Boolean): + marker_values[i] = int(marker_values[i]) if sort_dirs[i] == 'desc': crit_attrs.append((attr < marker_values[i])) elif sort_dirs[i] == 'asc': diff --git a/cinder/tests/unit/api/v3/test_volumes.py b/cinder/tests/unit/api/v3/test_volumes.py index 52d5f3fc9f0..72045da7c11 100644 --- a/cinder/tests/unit/api/v3/test_volumes.py +++ b/cinder/tests/unit/api/v3/test_volumes.py @@ -192,14 +192,17 @@ class VolumeApiTest(test.TestCase): # Create volumes in project 1 db.volume_create(self.ctxt, {'display_name': 'test1', 'project_id': fake.PROJECT_ID, - 'volume_type_id': fake.VOLUME_TYPE_ID}) + 'volume_type_id': fake.VOLUME_TYPE_ID, + 'id': fake.VOLUME_ID}) db.volume_create(self.ctxt, {'display_name': 'test2', 'project_id': fake.PROJECT_ID, - 'volume_type_id': fake.VOLUME_TYPE_ID}) + 'volume_type_id': fake.VOLUME_TYPE_ID, + 'id': fake.VOLUME2_ID}) # Create volume in project 2 db.volume_create(self.ctxt, {'display_name': 'test3', 'project_id': fake.PROJECT2_ID, - 'volume_type_id': fake.VOLUME_TYPE_ID}) + 'volume_type_id': fake.VOLUME_TYPE_ID, + 'id': fake.VOLUME3_ID}) def test_volume_index_filter_by_glance_metadata(self): vols = self._create_volume_with_glance_metadata() @@ -332,6 +335,22 @@ class VolumeApiTest(test.TestCase): self.assertEqual(1, len(res_dict['volumes'])) self.assertEqual(metadata, res_dict['volumes'][0]['metadata']) + def test_list_volume_with_filter_and_paginate(self): + self._create_multiple_volumes_with_different_project() + test_utils.create_volume(self.ctxt) + + self.mock_object(ViewBuilder, '_get_volume_type', + v2_fakes.fake_volume_type_name_get) + + req = fakes.HTTPRequest.blank( + "/v3/volumes/detail?all_tenants=1" + "&sort=bootable:asc&with_count=True&limit=5" + "&marker=" + fake.VOLUME_ID) + ctxt = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, False) + req.environ['cinder.context'] = ctxt + res_dict = self.controller._get_volumes(req, is_detail=True) + self.assertEqual(2, len(res_dict['volumes'])) + def test_volume_index_filter_by_group_id_in_unsupport_version(self): self._create_volume_with_group() req = fakes.HTTPRequest.blank(("/v3/volumes?group_id=%s") % diff --git a/releasenotes/notes/bug-2027532-volume-list-sort-by-boolean-fix-49972c69007d5ebc.yaml b/releasenotes/notes/bug-2027532-volume-list-sort-by-boolean-fix-49972c69007d5ebc.yaml new file mode 100644 index 00000000000..a5cba19abfc --- /dev/null +++ b/releasenotes/notes/bug-2027532-volume-list-sort-by-boolean-fix-49972c69007d5ebc.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + `Bug #2027532 `_: + Fixed Cinder API HTTP 500 when issuing a volume list and sorting by a + boolean field (i.e. "bootable").