Support large network queries towards neutron

While querying metadata from an LB source, the subnet query may result
with a large number of networks.
That might exceed the maximum request length on the following port query
towards Neutron.
The patch addresses such issue.

Closes-Bug: #1861087
Change-Id: I9d72c80574d08d8409ed0dcc0476f52a0d173a1e
This commit is contained in:
Kobi Samoray
2020-01-27 12:03:35 +02:00
parent b9ac4e4905
commit bfb8dcded6
2 changed files with 53 additions and 5 deletions
+14 -5
View File
@@ -39,6 +39,12 @@ from nova.network import neutron as neutronapi
CONF = nova.conf.CONF
LOG = logging.getLogger(__name__)
# 160 networks is large enough to satisfy most cases.
# Yet while reaching 182 networks Neutron server will break as URL length
# exceeds the maximum. Left this at 160 to allow additional parameters when
# they're needed.
MAX_QUERY_NETWORKS = 160
class MetadataRequestHandler(wsgi.Application):
"""Serve metadata."""
@@ -219,11 +225,14 @@ class MetadataRequestHandler(wsgi.Application):
try:
# Retrieve the instance data from the instance's port
ports = neutron.list_ports(
context,
fixed_ips='ip_address=' + instance_address,
network_id=md_networks,
fields=['device_id', 'tenant_id'])['ports']
ports = []
while md_networks:
ports.extend(neutron.list_ports(
context,
fixed_ips='ip_address=' + instance_address,
network_id=md_networks[:MAX_QUERY_NETWORKS],
fields=['device_id', 'tenant_id'])['ports'])
md_networks = md_networks[MAX_QUERY_NETWORKS:]
except Exception as e:
LOG.error('Failed to get instance id for metadata '
'request, provider %(provider)s '
+39
View File
@@ -1400,6 +1400,45 @@ class MetadataHandlerTestCase(test.TestCase):
self.assertEqual(200, response.status_int)
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
def test_metadata_lb_proxy_many_networks(self, mock_get_client):
def fake_list_ports(context, fixed_ips, network_id, fields):
if 'f-f-f-f' in network_id:
return {'ports':
[{'device_id': 'a-b-c-d', 'tenant_id': 'test'}]}
return {'ports': []}
self.flags(service_metadata_proxy=True, group='neutron')
handler.MAX_QUERY_NETWORKS = 10
self.expected_instance_id = b'a-b-c-d'
# with X-Metadata-Provider
proxy_lb_id = 'edge-x'
mock_client = mock_get_client.return_value
subnet_list = [{'network_id': 'f-f-f-' + chr(c)}
for c in range(ord('a'), ord('z'))]
mock_client.list_subnets.return_value = {
'subnets': subnet_list}
with mock.patch.object(
mock_client, 'list_ports',
side_effect=fake_list_ports) as mock_list_ports:
response = fake_request(
self, self.mdinst,
relpath="/2009-04-04/user-data",
address="192.192.192.2",
fake_get_metadata_by_instance_id=self._fake_x_get_metadata,
headers={'X-Forwarded-For': '192.192.192.2',
'X-Metadata-Provider': proxy_lb_id})
self.assertEqual(3, mock_list_ports.call_count)
self.assertEqual(200, response.status_int)
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
def _metadata_handler_with_provider_id(self, hnd, mock_get_client):
# with X-Metadata-Provider