Add "fields" parameter to ListPort query

This new query parameter will allow to send a query to the Neutron
server filtering only by those parameters needed by the list
command: ID, name, MAC address, fixed IPs and status.

When using input parameter "long", security groups IDs, device owner
and tags will be added to the fields filter.

With 4500 ports, those are the execution times for the command
"openstack port list" (average values in a development environment):

                 Neutron API (seconds)  CLI (seconds)
Without filter:  3.05                   10.15
With filter:     2.76                   8.19

Depends-On: https://review.opendev.org/#/c/754113/

Change-Id: I1cccf0bc3533f8085e8dd61bf2fbe78c49b74b31
Closes-Bug: #1897100
This commit is contained in:
Rodolfo Alonso Hernandez 2020-09-24 14:49:55 +00:00
parent 7146deef00
commit 8387b114e3
4 changed files with 58 additions and 22 deletions

View File

@ -45,7 +45,7 @@ msgpack-python==0.4.0
munch==2.1.0
netaddr==0.7.18
netifaces==0.10.4
openstacksdk==0.48.0
openstacksdk==0.51.0
os-service-types==1.7.0
os-testr==1.0.0
osc-lib==2.2.0

View File

@ -665,7 +665,7 @@ class ListPort(command.Lister):
_tag.get_tag_filtering_args(parsed_args, filters)
data = network_client.ports(**filters)
data = network_client.ports(fields=columns, **filters)
headers, attrs = utils.calculate_header_and_attrs(
column_headers, columns, parsed_args)

View File

@ -26,6 +26,10 @@ from openstackclient.tests.unit.network.v2 import fakes as network_fakes
from openstackclient.tests.unit import utils as tests_utils
LIST_FIELDS_TO_RETRIEVE = ('id', 'name', 'mac_address', 'fixed_ips', 'status')
LIST_FIELDS_TO_RETRIEVE_LONG = ('security_group_ids', 'device_owner', 'tags')
class TestPort(network_fakes.TestNetworkV2):
def setUp(self):
@ -883,7 +887,8 @@ class TestListPort(TestPort):
columns, data = self.cmd.take_action(parsed_args)
self.network.ports.assert_called_once_with()
self.network.ports.assert_called_once_with(
fields=LIST_FIELDS_TO_RETRIEVE)
self.assertEqual(self.columns, columns)
self.assertListItemEqual(self.data, list(data))
@ -901,7 +906,8 @@ class TestListPort(TestPort):
columns, data = self.cmd.take_action(parsed_args)
self.network.ports.assert_called_once_with(**{
'device_id': 'fake-router-id'
'device_id': 'fake-router-id',
'fields': LIST_FIELDS_TO_RETRIEVE,
})
self.assertEqual(self.columns, columns)
self.assertListItemEqual(self.data, list(data))
@ -921,7 +927,8 @@ class TestListPort(TestPort):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.network.ports.assert_called_once_with(
device_id=fake_server.id)
device_id=fake_server.id,
fields=LIST_FIELDS_TO_RETRIEVE)
mock_find.assert_called_once_with(mock.ANY, 'fake-server-name')
self.assertEqual(self.columns, columns)
self.assertListItemEqual(self.data, list(data))
@ -940,7 +947,8 @@ class TestListPort(TestPort):
columns, data = self.cmd.take_action(parsed_args)
self.network.ports.assert_called_once_with(**{
'device_id': self._ports[0].device_id
'device_id': self._ports[0].device_id,
'fields': LIST_FIELDS_TO_RETRIEVE,
})
self.assertEqual(self.columns, columns)
self.assertListItemEqual(self.data, list(data))
@ -959,7 +967,8 @@ class TestListPort(TestPort):
columns, data = self.cmd.take_action(parsed_args)
self.network.ports.assert_called_once_with(**{
'device_owner': self._ports[0].device_owner
'device_owner': self._ports[0].device_owner,
'fields': LIST_FIELDS_TO_RETRIEVE,
})
self.assertEqual(self.columns, columns)
self.assertListItemEqual(self.data, list(data))
@ -987,7 +996,8 @@ class TestListPort(TestPort):
'device_owner': self._ports[0].device_owner,
'device_id': 'fake-router-id',
'network_id': 'fake-network-id',
'mac_address': self._ports[0].mac_address
'mac_address': self._ports[0].mac_address,
'fields': LIST_FIELDS_TO_RETRIEVE,
})
self.assertEqual(self.columns, columns)
self.assertListItemEqual(self.data, list(data))
@ -1006,7 +1016,8 @@ class TestListPort(TestPort):
columns, data = self.cmd.take_action(parsed_args)
self.network.ports.assert_called_once_with(**{
'mac_address': self._ports[0].mac_address
'mac_address': self._ports[0].mac_address,
'fields': LIST_FIELDS_TO_RETRIEVE,
})
self.assertEqual(self.columns, columns)
self.assertListItemEqual(self.data, list(data))
@ -1025,7 +1036,9 @@ class TestListPort(TestPort):
columns, data = self.cmd.take_action(parsed_args)
self.network.ports.assert_called_once_with(**{
'fixed_ips': ['ip_address=%s' % ip_address]})
'fixed_ips': ['ip_address=%s' % ip_address],
'fields': LIST_FIELDS_TO_RETRIEVE,
})
self.assertEqual(self.columns, columns)
self.assertListItemEqual(self.data, list(data))
@ -1043,7 +1056,9 @@ class TestListPort(TestPort):
columns, data = self.cmd.take_action(parsed_args)
self.network.ports.assert_called_once_with(**{
'fixed_ips': ['ip_address_substr=%s' % ip_address_ss]})
'fixed_ips': ['ip_address_substr=%s' % ip_address_ss],
'fields': LIST_FIELDS_TO_RETRIEVE,
})
self.assertEqual(self.columns, columns)
self.assertListItemEqual(self.data, list(data))
@ -1063,7 +1078,9 @@ class TestListPort(TestPort):
columns, data = self.cmd.take_action(parsed_args)
self.network.ports.assert_called_once_with(**{
'fixed_ips': ['subnet_id=%s' % subnet_id]})
'fixed_ips': ['subnet_id=%s' % subnet_id],
'fields': LIST_FIELDS_TO_RETRIEVE,
})
self.assertEqual(self.columns, columns)
self.assertListItemEqual(self.data, list(data))
@ -1087,7 +1104,9 @@ class TestListPort(TestPort):
self.network.ports.assert_called_once_with(**{
'fixed_ips': ['subnet_id=%s' % subnet_id,
'ip_address=%s' % ip_address]})
'ip_address=%s' % ip_address],
'fields': LIST_FIELDS_TO_RETRIEVE,
})
self.assertEqual(self.columns, columns)
self.assertListItemEqual(self.data, list(data))
@ -1103,15 +1122,19 @@ class TestListPort(TestPort):
{'ip-address': ip_address}])
]
self.fake_subnet = network_fakes.FakeSubnet.create_one_subnet(
{'id': subnet_id})
self.fake_subnet = network_fakes.FakeSubnet.create_one_subnet({
'id': subnet_id,
'fields': LIST_FIELDS_TO_RETRIEVE,
})
self.network.find_subnet = mock.Mock(return_value=self.fake_subnet)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.network.ports.assert_called_once_with(**{
'fixed_ips': ['subnet_id=%s' % subnet_id,
'ip_address=%s' % ip_address]})
'ip_address=%s' % ip_address],
'fields': LIST_FIELDS_TO_RETRIEVE,
})
self.assertEqual(self.columns, columns)
self.assertListItemEqual(self.data, list(data))
@ -1128,7 +1151,8 @@ class TestListPort(TestPort):
columns, data = self.cmd.take_action(parsed_args)
self.network.ports.assert_called_once_with()
self.network.ports.assert_called_once_with(
fields=LIST_FIELDS_TO_RETRIEVE + LIST_FIELDS_TO_RETRIEVE_LONG)
self.assertEqual(self.columns_long, columns)
self.assertListItemEqual(self.data_long, list(data))
@ -1142,7 +1166,10 @@ class TestListPort(TestPort):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
filters = {'binding:host_id': 'foobar'}
filters = {
'binding:host_id': 'foobar',
'fields': LIST_FIELDS_TO_RETRIEVE,
}
self.network.ports.assert_called_once_with(**filters)
self.assertEqual(self.columns, columns)
@ -1160,7 +1187,11 @@ class TestListPort(TestPort):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
filters = {'tenant_id': project.id, 'project_id': project.id}
filters = {
'tenant_id': project.id,
'project_id': project.id,
'fields': LIST_FIELDS_TO_RETRIEVE,
}
self.network.ports.assert_called_once_with(**filters)
self.assertEqual(self.columns, columns)
@ -1180,7 +1211,11 @@ class TestListPort(TestPort):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
filters = {'tenant_id': project.id, 'project_id': project.id}
filters = {
'tenant_id': project.id,
'project_id': project.id,
'fields': LIST_FIELDS_TO_RETRIEVE,
}
self.network.ports.assert_called_once_with(**filters)
self.assertEqual(self.columns, columns)
@ -1206,7 +1241,8 @@ class TestListPort(TestPort):
**{'tags': 'red,blue',
'any_tags': 'red,green',
'not_tags': 'orange,yellow',
'not_any_tags': 'black,white'}
'not_any_tags': 'black,white',
'fields': LIST_FIELDS_TO_RETRIEVE}
)
self.assertEqual(self.columns, columns)
self.assertListItemEqual(self.data, list(data))

View File

@ -5,7 +5,7 @@ pbr!=2.1.0,>=2.0.0 # Apache-2.0
cliff>=3.4.0 # Apache-2.0
iso8601>=0.1.11 # MIT
openstacksdk>=0.48.0 # Apache-2.0
openstacksdk>=0.51.0 # Apache-2.0
osc-lib>=2.2.0 # Apache-2.0
oslo.i18n>=3.15.3 # Apache-2.0
python-keystoneclient>=3.22.0 # Apache-2.0