Avoid fetching metadata when no subnets found

Metadata service uses the provider id to identify the requesting
instance.
However, when provider query doesn't find any networks, the request
should fail.
The same goes to the case where multiple ports are found.

Closes-Bug: #1841933
Change-Id: I8ce3703ca86a3a0769edd42a790d82796d1071d7
This commit is contained in:
Kobi Samoray 2019-08-27 13:49:05 +03:00
parent 80539a5e84
commit 3177371568
2 changed files with 75 additions and 2 deletions

View File

@ -209,16 +209,21 @@ class MetadataRequestHandler(wsgi.Application):
advanced_service_providers=[provider_id], advanced_service_providers=[provider_id],
fields=['network_id']) fields=['network_id'])
if not md_subnets or not md_subnets.get('subnets'):
msg = _('Could not find any subnets for provider %s') % provider_id
LOG.error(msg)
raise webob.exc.HTTPBadRequest(explanation=msg)
md_networks = [subnet['network_id'] md_networks = [subnet['network_id']
for subnet in md_subnets['subnets']] for subnet in md_subnets['subnets']]
try: try:
# Retrieve the instance data from the instance's port # Retrieve the instance data from the instance's port
instance_data = neutron.list_ports( ports = neutron.list_ports(
context, context,
fixed_ips='ip_address=' + instance_address, fixed_ips='ip_address=' + instance_address,
network_id=md_networks, network_id=md_networks,
fields=['device_id', 'tenant_id'])['ports'][0] fields=['device_id', 'tenant_id'])['ports']
except Exception as e: except Exception as e:
LOG.error('Failed to get instance id for metadata ' LOG.error('Failed to get instance id for metadata '
'request, provider %(provider)s ' 'request, provider %(provider)s '
@ -232,6 +237,17 @@ class MetadataRequestHandler(wsgi.Application):
'Please try your request again.') 'Please try your request again.')
raise webob.exc.HTTPBadRequest(explanation=msg) raise webob.exc.HTTPBadRequest(explanation=msg)
if len(ports) != 1:
msg = _('Expected a single port matching provider %(pr)s '
'and IP %(ip)s. Found %(count)d.' % {
'pr': provider_id,
'ip': instance_address,
'count': len(ports)})
LOG.error(msg)
raise webob.exc.HTTPBadRequest(explanation=msg)
instance_data = ports[0]
instance_id = instance_data['device_id'] instance_id = instance_data['device_id']
tenant_id = instance_data['tenant_id'] tenant_id = instance_data['tenant_id']

View File

@ -1579,6 +1579,63 @@ class MetadataHandlerTestCase(test.TestCase):
'X-Metadata-Provider-Signature': signature}) 'X-Metadata-Provider-Signature': signature})
self.assertEqual(403, response.status_int) self.assertEqual(403, response.status_int)
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
def test_metadata_lb_net_not_found(self, mock_get_client):
self.flags(service_metadata_proxy=True, group='neutron')
# with X-Metadata-Provider
proxy_lb_id = 'edge-x'
mock_client = mock_get_client.return_value
mock_client.list_ports.return_value = {
'ports': [{'device_id': 'a-b-c-d', 'tenant_id': 'test'}]}
mock_client.list_subnets.return_value = {
'subnets': []}
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(400, response.status_int)
def _test_metadata_lb_incorrect_port_count(self, mock_get_client, ports):
self.flags(service_metadata_proxy=True, group='neutron')
# with X-Metadata-Provider
proxy_lb_id = 'edge-x'
mock_client = mock_get_client.return_value
mock_client.list_ports.return_value = {'ports': ports}
mock_client.list_ports.return_value = {
'ports': [{'device_id': 'a-b-c-d', 'tenant_id': 'test'},
{'device_id': 'x-y-z', 'tenant_id': 'test'}]}
mock_client.list_subnets.return_value = {
'subnets': [{'network_id': 'f-f-f-f'}]}
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(400, response.status_int)
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
def test_metadata_lb_too_many_ports(self, mock_get_client):
self._test_metadata_lb_incorrect_port_count(
mock_get_client,
[{'device_id': 'a-b-c-d', 'tenant_id': 'test'},
{'device_id': 'x-y-z', 'tenant_id': 'test'}])
@mock.patch.object(neutronapi, 'get_client', return_value=mock.Mock())
def test_metadata_no_ports_found(self, mock_get_client):
self._test_metadata_lb_incorrect_port_count(
mock_get_client, [])
@mock.patch.object(context, 'get_admin_context') @mock.patch.object(context, 'get_admin_context')
@mock.patch('nova.network.neutron.API') @mock.patch('nova.network.neutron.API')
def test_get_metadata_by_address(self, mock_net_api, mock_get_context): def test_get_metadata_by_address(self, mock_net_api, mock_get_context):