|
|
ef3f20 |
From 2d29c7af0c45186d3031c0ecd9ae0b8881a33c0b Mon Sep 17 00:00:00 2001
|
|
|
ef3f20 |
From: Lars Kellogg-Stedman <lars@redhat.com>
|
|
|
ef3f20 |
Date: Thu, 2 Mar 2017 11:08:26 -0500
|
|
|
ef3f20 |
Subject: [PATCH] net: support both ipv4 and ipv6 gateways in sysconfig.
|
|
|
ef3f20 |
|
|
|
ef3f20 |
Previously, cloud-init would throw an exception if an interface had
|
|
|
ef3f20 |
both ipv4 and ipv6 addresses and a default gateway for each address
|
|
|
ef3f20 |
family. This change allows cloud-init to correctly configure
|
|
|
ef3f20 |
interfaces in this situation.
|
|
|
ef3f20 |
|
|
|
ef3f20 |
LP: #1669504
|
|
|
ef3f20 |
(cherry picked from commit 1d751a6f46f044e3c3827f3cef0e4a2e71d50fe7)
|
|
|
ef3f20 |
---
|
|
|
ef3f20 |
cloudinit/net/sysconfig.py | 33 ++++++++++++++++++++++++---------
|
|
|
ef3f20 |
1 file changed, 24 insertions(+), 9 deletions(-)
|
|
|
ef3f20 |
|
|
|
ef3f20 |
diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py
|
|
|
ef3f20 |
index 0b5f13c..29c906f 100644
|
|
|
ef3f20 |
--- a/cloudinit/net/sysconfig.py
|
|
|
ef3f20 |
+++ b/cloudinit/net/sysconfig.py
|
|
|
ef3f20 |
@@ -87,7 +87,8 @@ class Route(ConfigMap):
|
|
|
ef3f20 |
def __init__(self, route_name, base_sysconf_dir):
|
|
|
ef3f20 |
super(Route, self).__init__()
|
|
|
ef3f20 |
self.last_idx = 1
|
|
|
ef3f20 |
- self.has_set_default = False
|
|
|
ef3f20 |
+ self.has_set_default_ipv4 = False
|
|
|
ef3f20 |
+ self.has_set_default_ipv6 = False
|
|
|
ef3f20 |
self._route_name = route_name
|
|
|
ef3f20 |
self._base_sysconf_dir = base_sysconf_dir
|
|
|
ef3f20 |
|
|
|
ef3f20 |
@@ -95,7 +96,8 @@ class Route(ConfigMap):
|
|
|
ef3f20 |
r = Route(self._route_name, self._base_sysconf_dir)
|
|
|
ef3f20 |
r._conf = self._conf.copy()
|
|
|
ef3f20 |
r.last_idx = self.last_idx
|
|
|
ef3f20 |
- r.has_set_default = self.has_set_default
|
|
|
ef3f20 |
+ r.has_set_default_ipv4 = self.has_set_default_ipv4
|
|
|
ef3f20 |
+ r.has_set_default_ipv6 = self.has_set_default_ipv6
|
|
|
ef3f20 |
return r
|
|
|
ef3f20 |
|
|
|
ef3f20 |
@property
|
|
|
ef3f20 |
@@ -119,10 +121,10 @@ class NetInterface(ConfigMap):
|
|
|
ef3f20 |
super(NetInterface, self).__init__()
|
|
|
ef3f20 |
self.children = []
|
|
|
ef3f20 |
self.routes = Route(iface_name, base_sysconf_dir)
|
|
|
ef3f20 |
- self._kind = kind
|
|
|
ef3f20 |
+ self.kind = kind
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
self._iface_name = iface_name
|
|
|
ef3f20 |
self._conf['DEVICE'] = iface_name
|
|
|
ef3f20 |
- self._conf['TYPE'] = self.iface_types[kind]
|
|
|
ef3f20 |
self._base_sysconf_dir = base_sysconf_dir
|
|
|
ef3f20 |
|
|
|
ef3f20 |
@property
|
|
|
ef3f20 |
@@ -140,6 +142,8 @@ class NetInterface(ConfigMap):
|
|
|
ef3f20 |
|
|
|
ef3f20 |
@kind.setter
|
|
|
ef3f20 |
def kind(self, kind):
|
|
|
ef3f20 |
+ if kind not in self.iface_types:
|
|
|
ef3f20 |
+ raise ValueError(kind)
|
|
|
ef3f20 |
self._kind = kind
|
|
|
ef3f20 |
self._conf['TYPE'] = self.iface_types[kind]
|
|
|
ef3f20 |
|
|
|
ef3f20 |
@@ -172,7 +176,7 @@ class Renderer(renderer.Renderer):
|
|
|
ef3f20 |
('BOOTPROTO', 'none'),
|
|
|
ef3f20 |
])
|
|
|
ef3f20 |
|
|
|
ef3f20 |
- # If these keys exist, then there values will be used to form
|
|
|
ef3f20 |
+ # If these keys exist, then their values will be used to form
|
|
|
ef3f20 |
# a BONDING_OPTS grouping; otherwise no grouping will be set.
|
|
|
ef3f20 |
bond_tpl_opts = tuple([
|
|
|
ef3f20 |
('bond_mode', "mode=%s"),
|
|
|
ef3f20 |
@@ -198,6 +202,7 @@ class Renderer(renderer.Renderer):
|
|
|
ef3f20 |
def _render_iface_shared(cls, iface, iface_cfg):
|
|
|
ef3f20 |
for k, v in cls.iface_defaults:
|
|
|
ef3f20 |
iface_cfg[k] = v
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
for (old_key, new_key) in [('mac_address', 'HWADDR'), ('mtu', 'MTU')]:
|
|
|
ef3f20 |
old_value = iface.get(old_key)
|
|
|
ef3f20 |
if old_value is not None:
|
|
|
ef3f20 |
@@ -226,10 +231,20 @@ class Renderer(renderer.Renderer):
|
|
|
ef3f20 |
if 'netmask' in subnet:
|
|
|
ef3f20 |
iface_cfg['NETMASK'] = subnet['netmask']
|
|
|
ef3f20 |
for route in subnet.get('routes', []):
|
|
|
ef3f20 |
+ if subnet.get('ipv6'):
|
|
|
ef3f20 |
+ gw_cfg = 'IPV6_DEFAULTGW'
|
|
|
ef3f20 |
+ else:
|
|
|
ef3f20 |
+ gw_cfg = 'GATEWAY'
|
|
|
ef3f20 |
+
|
|
|
ef3f20 |
if _is_default_route(route):
|
|
|
ef3f20 |
- if route_cfg.has_set_default:
|
|
|
ef3f20 |
- raise ValueError("Duplicate declaration of default"
|
|
|
ef3f20 |
- " route found for interface '%s'"
|
|
|
ef3f20 |
+ if (
|
|
|
ef3f20 |
+ (subnet.get('ipv4') and
|
|
|
ef3f20 |
+ route_cfg.has_set_default_ipv4) or
|
|
|
ef3f20 |
+ (subnet.get('ipv6') and
|
|
|
ef3f20 |
+ route_cfg.has_set_default_ipv6)
|
|
|
ef3f20 |
+ ):
|
|
|
ef3f20 |
+ raise ValueError("Duplicate declaration of default "
|
|
|
ef3f20 |
+ "route found for interface '%s'"
|
|
|
ef3f20 |
% (iface_cfg.name))
|
|
|
ef3f20 |
# NOTE(harlowja): ipv6 and ipv4 default gateways
|
|
|
ef3f20 |
gw_key = 'GATEWAY0'
|
|
|
ef3f20 |
@@ -241,7 +256,7 @@ class Renderer(renderer.Renderer):
|
|
|
ef3f20 |
# also provided the default route?
|
|
|
ef3f20 |
iface_cfg['DEFROUTE'] = True
|
|
|
ef3f20 |
if 'gateway' in route:
|
|
|
ef3f20 |
- iface_cfg['GATEWAY'] = route['gateway']
|
|
|
ef3f20 |
+ iface_cfg[gw_cfg] = route['gateway']
|
|
|
ef3f20 |
route_cfg.has_set_default = True
|
|
|
ef3f20 |
else:
|
|
|
ef3f20 |
gw_key = 'GATEWAY%s' % route_cfg.last_idx
|