Merge "Do not ignore 'fields' query parameter when building next url" into stable/rocky

This commit is contained in:
Zuul 2019-10-23 23:56:59 +00:00 committed by Gerrit Code Review
commit 02b852d59c
14 changed files with 143 additions and 12 deletions

View File

@ -157,9 +157,10 @@ class ChassisCollection(collection.Collection):
sanitize=False)
for ch in chassis]
url = url or None
collection.next = collection.get_next(limit, url=url, **kwargs)
collection.next = collection.get_next(limit, url=url, fields=fields,
**kwargs)
for item in collection.chassis:
item.sanitize(fields)
item.sanitize(fields)
return collection
@classmethod

View File

@ -39,6 +39,11 @@ class Collection(base.APIBase):
return wtypes.Unset
resource_url = url or self._type
fields = kwargs.pop('fields', None)
# NOTE(saga): If fields argument is present in kwargs and not None. It
# is a list so convert it into a comma seperated string.
if fields:
kwargs['fields'] = ','.join(fields)
q_args = ''.join(['%s=%s&' % (key, kwargs[key]) for key in kwargs])
next_args = '?%(args)slimit=%(limit)d&marker=%(marker)s' % {
'args': q_args, 'limit': limit,

View File

@ -1319,10 +1319,10 @@ class NodeCollection(collection.Collection):
collection.nodes = [Node.convert_with_links(n, fields=fields,
sanitize=False)
for n in nodes]
collection.next = collection.get_next(limit, url=url, **kwargs)
for node in collection.nodes:
node.sanitize(fields)
collection.next = collection.get_next(limit, url=url, fields=fields,
**kwargs)
for item in collection.nodes:
item.sanitize(fields)
return collection

View File

@ -299,8 +299,8 @@ class PortCollection(collection.Collection):
collection.ports.append(port)
collection.next = collection.get_next(limit, url=url, **kwargs)
collection.next = collection.get_next(limit, url=url, fields=fields,
**kwargs)
for item in collection.ports:
item.sanitize(fields=fields)

View File

@ -232,8 +232,9 @@ class PortgroupCollection(collection.Collection):
collection.portgroups = [Portgroup.convert_with_links(p, fields=fields,
sanitize=False)
for p in rpc_portgroups]
collection.next = collection.get_next(limit, url=url, **kwargs)
collection.next = collection.get_next(limit, url=url, fields=fields,
**kwargs)
for item in collection.portgroups:
item.sanitize(fields=fields)

View File

@ -201,7 +201,8 @@ class VolumeConnectorCollection(collection.Collection):
for p in rpc_connectors]
if detail:
kwargs['detail'] = detail
collection.next = collection.get_next(limit, url=url, **kwargs)
collection.next = collection.get_next(limit, url=url, fields=fields,
**kwargs)
for connector in collection.connectors:
connector.sanitize(fields)
return collection

View File

@ -217,9 +217,10 @@ class VolumeTargetCollection(collection.Collection):
for p in rpc_targets]
if detail:
kwargs['detail'] = detail
collection.next = collection.get_next(limit, url=url, **kwargs)
collection.next = collection.get_next(limit, url=url, fields=fields,
**kwargs)
for target in collection.targets:
target.sanitize(fields)
target.sanitize(fields=fields)
return collection
@classmethod

View File

@ -230,6 +230,22 @@ class TestListChassis(test_api_base.BaseApiTest):
next_marker = data['chassis'][-1]['uuid']
self.assertIn(next_marker, data['next'])
def test_collection_links_custom_fields(self):
fields = 'extra,uuid'
cfg.CONF.set_override('max_limit', 3, 'api')
for i in range(5):
obj_utils.create_test_chassis(
self.context, uuid=uuidutils.generate_uuid())
data = self.get_json(
'/chassis?fields=%s' % fields,
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(3, len(data['chassis']))
next_marker = data['chassis'][-1]['uuid']
self.assertIn(next_marker, data['next'])
self.assertIn('fields', data['next'])
def test_get_collection_pagination_no_uuid(self):
fields = 'extra'
limit = 2

View File

@ -736,6 +736,25 @@ class TestListNodes(test_api_base.BaseApiTest):
next_marker = data['nodes'][-1]['uuid']
self.assertIn(next_marker, data['next'])
def test_collection_links_custom_fields(self):
fields = 'driver_info,uuid'
cfg.CONF.set_override('max_limit', 3, 'api')
nodes = []
for id in range(5):
node = obj_utils.create_test_node(self.context,
uuid=uuidutils.generate_uuid(),
driver_info={'fake': 'value'},
properties={'fake': 'bar'})
nodes.append(node.uuid)
data = self.get_json(
'/nodes?fields=%s' % fields,
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(3, len(data['nodes']))
next_marker = data['nodes'][-1]['uuid']
self.assertIn(next_marker, data['next'])
self.assertIn('fields', data['next'])
def test_get_collection_pagination_no_uuid(self):
fields = 'name'
limit = 2

View File

@ -609,6 +609,25 @@ class TestListPorts(test_api_base.BaseApiTest):
next_marker = data['ports'][-1]['uuid']
self.assertIn(next_marker, data['next'])
def test_collection_links_custom_fields(self):
fields = 'address,uuid'
cfg.CONF.set_override('max_limit', 3, 'api')
for i in range(5):
obj_utils.create_test_port(
self.context,
uuid=uuidutils.generate_uuid(),
node_id=self.node.id,
address='52:54:00:cf:2d:3%s' % i)
data = self.get_json(
'/ports?fields=%s' % fields,
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(3, len(data['ports']))
next_marker = data['ports'][-1]['uuid']
self.assertIn(next_marker, data['next'])
self.assertIn('fields', data['next'])
def test_port_by_address(self):
address_template = "aa:bb:cc:dd:ee:f%d"
for id_ in range(3):

View File

@ -327,6 +327,26 @@ class TestListPortgroups(test_api_base.BaseApiTest):
next_marker = data['portgroups'][-1]['uuid']
self.assertIn(next_marker, data['next'])
def test_collection_links_custom_fields(self):
fields = 'address,uuid'
cfg.CONF.set_override('max_limit', 3, 'api')
for i in range(5):
obj_utils.create_test_portgroup(
self.context,
uuid=uuidutils.generate_uuid(),
node_id=self.node.id,
name='portgroup%s' % i,
address='52:54:00:cf:2d:3%s' % i)
data = self.get_json(
'/portgroups?fields=%s' % fields,
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(3, len(data['portgroups']))
next_marker = data['portgroups'][-1]['uuid']
self.assertIn(next_marker, data['next'])
self.assertIn('fields', data['next'])
def test_get_collection_pagination_no_uuid(self):
fields = 'address'
limit = 2

View File

@ -273,6 +273,28 @@ class TestListVolumeConnectors(test_api_base.BaseApiTest):
next_marker = data['connectors'][-1]['uuid']
self.assertIn(next_marker, data['next'])
def test_collection_links_custom_fields(self):
cfg.CONF.set_override('max_limit', 3, 'api')
connectors = []
fields = 'uuid,extra'
for i in range(5):
connector = obj_utils.create_test_volume_connector(
self.context, node_id=self.node.id,
uuid=uuidutils.generate_uuid(),
connector_id='test-connector_id-%s' % i)
connectors.append(connector.uuid)
data = self.get_json(
'/volume/connectors?fields=%s' % fields,
headers=self.headers)
self.assertEqual(3, len(data['connectors']))
self.assertIn('volume/connectors', data['next'])
next_marker = data['connectors'][-1]['uuid']
self.assertIn(next_marker, data['next'])
self.assertIn('fields', data['next'])
def test_get_collection_pagination_no_uuid(self):
fields = 'connector_id'
limit = 2

View File

@ -258,6 +258,24 @@ class TestListVolumeTargets(test_api_base.BaseApiTest):
self.assertIn(next_marker, data['next'])
self.assertIn('volume/targets', data['next'])
def test_collection_links_custom_fields(self):
fields = 'uuid,extra'
cfg.CONF.set_override('max_limit', 3, 'api')
targets = []
for id_ in range(5):
target = obj_utils.create_test_volume_target(
self.context, node_id=self.node.id,
uuid=uuidutils.generate_uuid(), boot_index=id_)
targets.append(target.uuid)
data = self.get_json('/volume/targets?fields=%s' % fields,
headers=self.headers)
self.assertEqual(3, len(data['targets']))
next_marker = data['targets'][-1]['uuid']
self.assertIn(next_marker, data['next'])
self.assertIn('volume/targets', data['next'])
self.assertIn('fields', data['next'])
def test_get_collection_pagination_no_uuid(self):
fields = 'boot_index'
limit = 2

View File

@ -0,0 +1,8 @@
---
fixes:
- |
Fixes issue where the resource list API returned results with requested
fields only until the API MAX_LIMIT. After the API MAX_LIMIT is reached the
API started ignoring user requested fields. This fix will make sure that
the next url generated by the pagination code will include the user
requested fields as query parameter.