Browse Source

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
tags/21.0.0.0rc1
Kobi Samoray 11 months ago
parent
commit
3177371568
2 changed files with 75 additions and 2 deletions
  1. +18
    -2
      nova/api/metadata/handler.py
  2. +57
    -0
      nova/tests/unit/test_metadata.py

+ 18
- 2
nova/api/metadata/handler.py View File

@@ -209,16 +209,21 @@ class MetadataRequestHandler(wsgi.Application):
advanced_service_providers=[provider_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']
for subnet in md_subnets['subnets']]

try:
# Retrieve the instance data from the instance's port
instance_data = neutron.list_ports(
ports = neutron.list_ports(
context,
fixed_ips='ip_address=' + instance_address,
network_id=md_networks,
fields=['device_id', 'tenant_id'])['ports'][0]
fields=['device_id', 'tenant_id'])['ports']
except Exception as e:
LOG.error('Failed to get instance id for metadata '
'request, provider %(provider)s '
@@ -232,6 +237,17 @@ class MetadataRequestHandler(wsgi.Application):
'Please try your request again.')
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']
tenant_id = instance_data['tenant_id']



+ 57
- 0
nova/tests/unit/test_metadata.py View File

@@ -1579,6 +1579,63 @@ class MetadataHandlerTestCase(test.TestCase):
'X-Metadata-Provider-Signature': signature})
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('nova.network.neutron.API')
def test_get_metadata_by_address(self, mock_net_api, mock_get_context):


Loading…
Cancel
Save