Merge "Simplify using external routers and metadata"

This commit is contained in:
Jenkins 2013-11-11 13:06:44 +00:00 committed by Gerrit Code Review
commit cb5000b0ca
2 changed files with 84 additions and 14 deletions

View File

@ -29,6 +29,7 @@ from oslo.config import cfg
from neutron.agent.linux import ip_lib
from neutron.agent.linux import utils
from neutron.common import constants
from neutron.common import exceptions
from neutron.openstack.common import importutils
from neutron.openstack.common import jsonutils
@ -445,12 +446,8 @@ class Dnsmasq(DhcpLocalProcess):
host_routes.append("%s,%s" % (hr.destination, hr.nexthop))
# Add host routes for isolated network segments
enable_metadata = (
self.conf.enable_isolated_metadata
and not subnet.gateway_ip
and subnet.ip_version == 4)
if enable_metadata:
if self._enable_metadata(subnet):
subnet_dhcp_ip = subnet_to_interface_ip[subnet.id]
host_routes.append(
'%s/32,%s' % (METADATA_DEFAULT_IP, subnet_dhcp_ip)
@ -519,6 +516,25 @@ class Dnsmasq(DhcpLocalProcess):
return ','.join((set_tag + tag, '%s' % option) + args)
def _enable_metadata(self, subnet):
'''Determine if the metadata route will be pushed to hosts on subnet.
If subnet has a Neutron router attached, we want the hosts to get
metadata from the router's proxy via their default route instead.
'''
if self.conf.enable_isolated_metadata and subnet.ip_version == 4:
if subnet.gateway_ip is None:
return True
else:
for port in self.network.ports:
if port.device_owner == constants.DEVICE_OWNER_ROUTER_INTF:
for alloc in port.fixed_ips:
if alloc.subnet_id == subnet.id:
return False
return True
else:
return False
@classmethod
def lease_update(cls):
network_id = os.environ.get(cls.NEUTRON_NETWORK_ID_KEY)

View File

@ -30,8 +30,9 @@ LOG = logging.getLogger(__name__)
class FakeIPAllocation:
def __init__(self, address):
def __init__(self, address, subnet_id=None):
self.ip_address = address
self.subnet_id = subnet_id
class DhcpOpt(object):
@ -45,6 +46,7 @@ class DhcpOpt(object):
class FakePort1:
id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
admin_state_up = True
device_owner = 'foo1'
fixed_ips = [FakeIPAllocation('192.168.0.2')]
mac_address = '00:00:80:aa:bb:cc'
@ -55,6 +57,7 @@ class FakePort1:
class FakePort2:
id = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
admin_state_up = False
device_owner = 'foo2'
fixed_ips = [FakeIPAllocation('fdca:3ba5:a17a:4ba3::2')]
mac_address = '00:00:f3:aa:bb:cc'
@ -65,6 +68,7 @@ class FakePort2:
class FakePort3:
id = '44444444-4444-4444-4444-444444444444'
admin_state_up = True
device_owner = 'foo3'
fixed_ips = [FakeIPAllocation('192.168.0.3'),
FakeIPAllocation('fdca:3ba5:a17a:4ba3::3')]
mac_address = '00:00:0f:aa:bb:cc'
@ -73,6 +77,18 @@ class FakePort3:
self.extra_dhcp_opts = []
class FakeRouterPort:
id = 'rrrrrrrr-rrrr-rrrr-rrrr-rrrrrrrrrrrr'
admin_state_up = True
device_owner = 'network:router_interface'
fixed_ips = [FakeIPAllocation('192.168.0.1',
'dddddddd-dddd-dddd-dddd-dddddddddddd')]
mac_address = '00:00:0f:rr:rr:rr'
def __init__(self):
self.extra_dhcp_opts = []
class FakeV4HostRoute:
destination = '20.0.0.1/24'
nexthop = '20.0.0.1'
@ -138,6 +154,16 @@ class FakeV4SubnetNoGateway:
dns_nameservers = []
class FakeV4SubnetNoRouter:
id = 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee'
ip_version = 4
cidr = '192.168.1.0/24'
gateway_ip = '192.168.1.1'
enable_dhcp = True
host_routes = []
dns_nameservers = []
class FakeV4Network:
id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'
subnets = [FakeV4Subnet()]
@ -155,21 +181,21 @@ class FakeV6Network:
class FakeDualNetwork:
id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
subnets = [FakeV4Subnet(), FakeV6Subnet()]
ports = [FakePort1(), FakePort2(), FakePort3()]
ports = [FakePort1(), FakePort2(), FakePort3(), FakeRouterPort()]
namespace = 'qdhcp-ns'
class FakeDualNetworkGatewayRoute:
id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
subnets = [FakeV4SubnetGatewayRoute(), FakeV6Subnet()]
ports = [FakePort1(), FakePort2(), FakePort3()]
ports = [FakePort1(), FakePort2(), FakePort3(), FakeRouterPort()]
namespace = 'qdhcp-ns'
class FakeDualNetworkSingleDHCP:
id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
subnets = [FakeV4Subnet(), FakeV4SubnetNoDHCP()]
ports = [FakePort1(), FakePort2(), FakePort3()]
ports = [FakePort1(), FakePort2(), FakePort3(), FakeRouterPort()]
namespace = 'qdhcp-ns'
@ -179,10 +205,16 @@ class FakeV4NoGatewayNetwork:
ports = [FakePort1()]
class FakeV4NetworkNoRouter:
id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
subnets = [FakeV4SubnetNoRouter()]
ports = [FakePort1()]
class FakeDualV4Pxe3Ports:
id = 'cccccccc-cccc-cccc-cccc-cccccccccccc'
subnets = [FakeV4Subnet(), FakeV4SubnetNoDHCP()]
ports = [FakePort1(), FakePort2(), FakePort3()]
ports = [FakePort1(), FakePort2(), FakePort3(), FakeRouterPort()]
namespace = 'qdhcp-ns'
def __init__(self, port_detail="portsSame"):
@ -217,7 +249,7 @@ class FakeDualV4Pxe3Ports:
class FakeV4NetworkPxe2Ports:
id = 'dddddddd-dddd-dddd-dddd-dddddddddddd'
subnets = [FakeV4Subnet()]
ports = [FakePort1(), FakePort2()]
ports = [FakePort1(), FakePort2(), FakeRouterPort()]
namespace = 'qdhcp-ns'
def __init__(self, port_detail="portsSame"):
@ -244,7 +276,7 @@ class FakeV4NetworkPxe2Ports:
class FakeV4NetworkPxe3Ports:
id = 'dddddddd-dddd-dddd-dddd-dddddddddddd'
subnets = [FakeV4Subnet()]
ports = [FakePort1(), FakePort2(), FakePort3()]
ports = [FakePort1(), FakePort2(), FakePort3(), FakeRouterPort()]
namespace = 'qdhcp-ns'
def __init__(self, port_detail="portsSame"):
@ -716,6 +748,24 @@ tag:tag0,option:router""".lstrip()
self.safe.assert_called_once_with('/foo/opts', expected)
def test_output_opts_file_no_neutron_router_on_subnet(self):
expected = """
tag:tag0,option:classless-static-route,169.254.169.254/32,192.168.1.2
tag:tag0,249,169.254.169.254/32,192.168.1.2
tag:tag0,option:router,192.168.1.1""".lstrip()
with mock.patch.object(dhcp.Dnsmasq, 'get_conf_file_name') as conf_fn:
conf_fn.return_value = '/foo/opts'
dm = dhcp.Dnsmasq(self.conf, FakeV4NetworkNoRouter(),
version=float(2.59))
with mock.patch.object(dm, '_make_subnet_interface_ip_map') as ipm:
ipm.return_value = {FakeV4SubnetNoRouter.id: '192.168.1.2'}
dm._output_opts_file()
self.assertTrue(ipm.called)
self.safe.assert_called_once_with('/foo/opts', expected)
def test_release_lease(self):
dm = dhcp.Dnsmasq(self.conf, FakeDualNetwork(), version=float(2.59))
dm.release_lease(mac_address=FakePort2.mac_address,
@ -830,7 +880,9 @@ tag:44444444-4444-4444-4444-444444444444,option:bootfile-name,pxelinux3.0"""
'00:00:0f:aa:bb:cc,host-192-168-0-3.openstacklocal,'
'192.168.0.3\n'
'00:00:0f:aa:bb:cc,host-fdca-3ba5-a17a-4ba3--3.'
'openstacklocal,fdca:3ba5:a17a:4ba3::3\n').lstrip()
'openstacklocal,fdca:3ba5:a17a:4ba3::3\n'
'00:00:0f:rr:rr:rr,host-192-168-0-1.openstacklocal,'
'192.168.0.1\n').lstrip()
exp_opt_name = '/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/opts'
exp_opt_data = "tag:tag0,option:router,192.168.0.1"
fake_v6 = 'gdca:3ba5:a17a:4ba3::1'
@ -877,7 +929,9 @@ tag:tag1,249,%s,%s""".lstrip() % (fake_v6,
'00:00:0f:aa:bb:cc,host-192-168-0-3.openstacklocal,'
'192.168.0.3\n'
'00:00:0f:aa:bb:cc,host-fdca-3ba5-a17a-4ba3--3.'
'openstacklocal,fdca:3ba5:a17a:4ba3::3\n').lstrip()
'openstacklocal,fdca:3ba5:a17a:4ba3::3\n'
'00:00:0f:rr:rr:rr,host-192-168-0-1.openstacklocal,'
'192.168.0.1\n').lstrip()
exp_host_data.replace('\n', '')
exp_opt_name = '/dhcp/cccccccc-cccc-cccc-cccc-cccccccccccc/opts'
exp_opt_data = "tag:tag0,option:router,192.168.0.1"