Support networks without gateway

Launching an instance when using network injection on a network
containing a subnet that has no gateway fails in scheduling with
a KeyError when using a legacy network_info provider and generates
an invalid network file for the others.

The following changes were done:

* The legacy transformer for network_info now always provides
  a gateway/gateway_v6 field, with a value of None if no gateway
  is available (this is similar to the other fields that are empty).
* The interfaces template was modified to include the gateway line
  only if a gateway is provided for the interface.

Fixes: bug #1207878
Change-Id: I887757a6bcba528059ace8831a7d23a31b08c630
This commit is contained in:
Mathieu Mitchell
2013-06-28 12:31:54 -04:00
committed by Mathieu Gagné
parent e685a72424
commit 27fc4648b7
3 changed files with 68 additions and 29 deletions

View File

@@ -419,6 +419,7 @@ class NetworkInfo(list):
'qbg_params': vif.get('qbg_params'), 'qbg_params': vif.get('qbg_params'),
'rxtx_cap': vif.get_meta('rxtx_cap', 0), 'rxtx_cap': vif.get_meta('rxtx_cap', 0),
'dns': [get_ip(ip) for ip in subnet_v4['dns']], 'dns': [get_ip(ip) for ip in subnet_v4['dns']],
'gateway': gateway,
'ips': [fixed_ip_dict(ip, subnet) 'ips': [fixed_ip_dict(ip, subnet)
for subnet in v4_subnets for subnet in v4_subnets
for ip in subnet['ips']], for ip in subnet['ips']],
@@ -428,11 +429,7 @@ class NetworkInfo(list):
if routes: if routes:
info_dict['routes'] = routes info_dict['routes'] = routes
if gateway:
info_dict['gateway'] = gateway
if v6_subnets: if v6_subnets:
if subnet_v6['gateway']:
info_dict['gateway_v6'] = get_ip(subnet_v6['gateway']) info_dict['gateway_v6'] = get_ip(subnet_v6['gateway'])
# NOTE(tr3buchet): only supporting single v6 subnet here # NOTE(tr3buchet): only supporting single v6 subnet here
info_dict['ip6s'] = [fixed_ip_dict(ip, subnet_v6) info_dict['ip6s'] = [fixed_ip_dict(ip, subnet_v6)

View File

@@ -379,28 +379,34 @@ class NetworkInfoTests(test.TestCase):
{'address': '10.10.0.3'})] * 4) {'address': '10.10.0.3'})] * 4)
def _test_injected_network_template(self, should_inject, use_ipv6=False, def _test_injected_network_template(self, should_inject, use_ipv6=False,
legacy=False): legacy=False, gateway=True):
"""Check that netutils properly decides whether to inject based on """Check that netutils properly decides whether to inject based on
whether the supplied subnet is static or dynamic. whether the supplied subnet is static or dynamic.
""" """
network = fake_network_cache_model.new_network({'subnets': []}) network = fake_network_cache_model.new_network({'subnets': []})
if should_inject: subnet_dict = {}
network.add_subnet(fake_network_cache_model.new_subnet()) if not gateway:
if use_ipv6: subnet_dict['gateway'] = None
if not should_inject:
subnet_dict['dhcp_server'] = '10.10.0.1'
network.add_subnet(fake_network_cache_model.new_subnet(subnet_dict))
if should_inject and use_ipv6:
gateway_ip = fake_network_cache_model.new_ip(dict( gateway_ip = fake_network_cache_model.new_ip(dict(
address='1234:567::1')) address='1234:567::1'))
ip = fake_network_cache_model.new_ip(dict( ip = fake_network_cache_model.new_ip(dict(
address='1234:567::2')) address='1234:567::2'))
subnet_dict = dict( ipv6_subnet_dict = dict(
cidr='1234:567::/48', cidr='1234:567::/48',
gateway=gateway_ip, gateway=gateway_ip,
ips=[ip]) ips=[ip])
if not gateway:
ipv6_subnet_dict['gateway'] = None
network.add_subnet(fake_network_cache_model.new_subnet( network.add_subnet(fake_network_cache_model.new_subnet(
subnet_dict)) ipv6_subnet_dict))
else:
subnet_dict = dict(dhcp_server='10.10.0.1')
network.add_subnet(fake_network_cache_model.new_subnet(
subnet_dict))
# Behave as though CONF.flat_injected is True # Behave as though CONF.flat_injected is True
network['meta']['injected'] = True network['meta']['injected'] = True
vif = fake_network_cache_model.new_vif({'network': network}) vif = fake_network_cache_model.new_vif({'network': network})
@@ -424,30 +430,62 @@ class NetworkInfoTests(test.TestCase):
self.assertTrue('address 10.10.0.2' in template) self.assertTrue('address 10.10.0.2' in template)
self.assertTrue('netmask 255.255.255.0' in template) self.assertTrue('netmask 255.255.255.0' in template)
self.assertTrue('broadcast 10.10.0.255' in template) self.assertTrue('broadcast 10.10.0.255' in template)
if gateway:
self.assertTrue('gateway 10.10.0.1' in template) self.assertTrue('gateway 10.10.0.1' in template)
else:
self.assertFalse('gateway' in template)
self.assertTrue('dns-nameservers 1.2.3.4 2.3.4.5' in template) self.assertTrue('dns-nameservers 1.2.3.4 2.3.4.5' in template)
if use_ipv6: if use_ipv6:
self.assertTrue('iface eth0 inet6 static' in template) self.assertTrue('iface eth0 inet6 static' in template)
self.assertTrue('address 1234:567::2' in template) self.assertTrue('address 1234:567::2' in template)
self.assertTrue('netmask 48' in template) self.assertTrue('netmask 48' in template)
if gateway:
self.assertTrue('gateway 1234:567::1' in template) self.assertTrue('gateway 1234:567::1' in template)
def test_injection_static(self): def test_injection_static(self):
self._test_injected_network_template(should_inject=True) self._test_injected_network_template(should_inject=True)
def test_injection_static_ipv6(self): def test_injection_static_nogateway(self):
self._test_injected_network_template(should_inject=True, use_ipv6=True) self._test_injected_network_template(should_inject=True, gateway=False)
def test_injection_dynamic(self):
self._test_injected_network_template(should_inject=False)
def test_injection_static_legacy(self): def test_injection_static_legacy(self):
self._test_injected_network_template(should_inject=True, legacy=True) self._test_injected_network_template(should_inject=True, legacy=True)
def test_injection_static_legacy_nogateway(self):
self._test_injected_network_template(should_inject=True,
legacy=True,
gateway=False)
def test_injection_static_ipv6(self):
self._test_injected_network_template(should_inject=True, use_ipv6=True)
def test_injection_static_ipv6_nogateway(self):
self._test_injected_network_template(should_inject=True,
use_ipv6=True,
gateway=False)
def test_injection_static_ipv6_legacy(self): def test_injection_static_ipv6_legacy(self):
self._test_injected_network_template(should_inject=True, self._test_injected_network_template(should_inject=True,
use_ipv6=True, use_ipv6=True,
legacy=True) legacy=True)
def test_injection_static_ipv6_legacy_nogateway(self):
self._test_injected_network_template(should_inject=True,
use_ipv6=True,
legacy=True,
gateway=False)
def test_injection_dynamic(self):
self._test_injected_network_template(should_inject=False)
def test_injection_dynamic_nogateway(self):
self._test_injected_network_template(should_inject=False,
gateway=False)
def test_injection_dynamic_legacy(self): def test_injection_dynamic_legacy(self):
self._test_injected_network_template(should_inject=False, legacy=True) self._test_injected_network_template(should_inject=False, legacy=True)
def test_injection_dynamic_legacy_nogateway(self):
self._test_injected_network_template(should_inject=False,
legacy=True,
gateway=False)

View File

@@ -13,7 +13,9 @@ iface ${ifc.name} inet static
address ${ifc.address} address ${ifc.address}
netmask ${ifc.netmask} netmask ${ifc.netmask}
broadcast ${ifc.broadcast} broadcast ${ifc.broadcast}
#if $ifc.gateway
gateway ${ifc.gateway} gateway ${ifc.gateway}
#end if
#if $ifc.dns #if $ifc.dns
dns-nameservers ${ifc.dns} dns-nameservers ${ifc.dns}
#end if #end if
@@ -22,7 +24,9 @@ iface ${ifc.name} inet static
iface ${ifc.name} inet6 static iface ${ifc.name} inet6 static
address ${ifc.address_v6} address ${ifc.address_v6}
netmask ${ifc.netmask_v6} netmask ${ifc.netmask_v6}
#if $ifc.gateway_v6
gateway ${ifc.gateway_v6} gateway ${ifc.gateway_v6}
#end if #end if
#end if
#end for #end for