Always Set dhcp_server in network_info

If enable_dhcp is set on subnet, but, for
some reason neutron did not have any DHCP port yet, we still
want the network_info to be populated with a valid dhcp_server
value. This is mostly useful for the metadata API (which is
relying on this value to give network_data to the instance).

This will also help some providers which are using external
DHCP servers not handled by neutron.
In this case, neutron will never create any DHCP port in the
subnet.

Also note that we cannot set the value to None because then the
value would be discarded by the metadata API.
So the subnet gateway will be used as fallback.

Change-Id: Ie2cd54c159ea693e48e00d0ca3b0ca5a468d79cb
Signed-off-by: Arnaud Morin <arnaud.morin@corp.ovh.com>
This commit is contained in:
Arnaud Morin 2019-05-16 10:48:11 +02:00 committed by Stephen Finucane
parent 1e2327991d
commit c7f572d65b
3 changed files with 65 additions and 0 deletions

View File

@ -3103,6 +3103,23 @@ class API(base_api.NetworkAPI):
subnet_dict['dhcp_server'] = ip_pair['ip_address']
break
# NOTE(arnaudmorin): If enable_dhcp is set on subnet, but, for
# some reason neutron did not have any DHCP port yet, we still
# want the network_info to be populated with a valid dhcp_server
# value. This is mostly useful for the metadata API (which is
# relying on this value to give network_data to the instance).
#
# This will also help some providers which are using external
# DHCP servers not handled by neutron.
# In this case, neutron will never create any DHCP port in the
# subnet.
#
# Also note that we cannot set the value to None because then the
# value would be discarded by the metadata API.
# So the subnet gateway will be used as fallback.
if subnet.get('enable_dhcp') and 'dhcp_server' not in subnet_dict:
subnet_dict['dhcp_server'] = subnet['gateway_ip']
subnet_object = network_model.Subnet(**subnet_dict)
for dns in subnet.get('dns_nameservers', []):
subnet_object.add_dns(

View File

@ -2507,6 +2507,49 @@ class TestNeutronv2(TestNeutronv2Base):
self.assertEqual(subnet_data1[0]['host_routes'][0]['nexthop'],
subnets[0]['routes'][0]['gateway']['address'])
@mock.patch.object(neutronapi, 'get_client')
def test_get_subnets_from_port_enabled_dhcp(self, mock_get_client):
api = neutronapi.API()
mocked_client = mock.create_autospec(client.Client)
mock_get_client.return_value = mocked_client
port_data = copy.copy(self.port_data1[0])
# add another IP on the same subnet and verify the subnet is deduped
port_data['fixed_ips'].append({'ip_address': '10.0.1.3',
'subnet_id': 'my_subid1'})
subnet_data1 = copy.copy(self.subnet_data1)
subnet_data1[0]['enable_dhcp'] = True
mocked_client.list_subnets.return_value = {'subnets': subnet_data1}
mocked_client.list_ports.return_value = {'ports': self.dhcp_port_data1}
subnets = api._get_subnets_from_port(self.context, port_data)
self.assertEqual(self.dhcp_port_data1[0]['fixed_ips'][0]['ip_address'],
subnets[0]['meta']['dhcp_server'])
@mock.patch.object(neutronapi, 'get_client')
def test_get_subnets_from_port_enabled_dhcp_no_dhcp_ports(self,
mock_get_client):
api = neutronapi.API()
mocked_client = mock.create_autospec(client.Client)
mock_get_client.return_value = mocked_client
port_data = copy.copy(self.port_data1[0])
# add another IP on the same subnet and verify the subnet is deduped
port_data['fixed_ips'].append({'ip_address': '10.0.1.3',
'subnet_id': 'my_subid1'})
subnet_data1 = copy.copy(self.subnet_data1)
subnet_data1[0]['enable_dhcp'] = True
mocked_client.list_subnets.return_value = {'subnets': subnet_data1}
mocked_client.list_ports.return_value = {'ports': []}
subnets = api._get_subnets_from_port(self.context, port_data)
self.assertEqual(subnet_data1[0]['gateway_ip'],
subnets[0]['meta']['dhcp_server'])
def test_get_all_empty_list_networks(self):
api = neutronapi.API()
neutronapi.get_client(mox.IgnoreArg()).AndReturn(self.moxed_client)

View File

@ -0,0 +1,5 @@
---
features:
- When ``enable_dhcp`` is set on a subnet but there is no DHCP port on neutron
then the ``dhcp_server`` value in meta hash will contain the subnet
gateway IP instead of being absent.