diff --git a/cloud-init-handle-def-route-set.patch b/cloud-init-handle-def-route-set.patch new file mode 100644 index 0000000..7656475 --- /dev/null +++ b/cloud-init-handle-def-route-set.patch @@ -0,0 +1,189 @@ +--- cloudinit/net/network_state.py.orig ++++ cloudinit/net/network_state.py +@@ -148,6 +148,7 @@ class NetworkState(object): + self._network_state = copy.deepcopy(network_state) + self._version = version + self.use_ipv6 = network_state.get('use_ipv6', False) ++ self._has_default_route = self._find_default_route() + + @property + def config(self): +@@ -157,6 +158,10 @@ class NetworkState(object): + def version(self): + return self._version + ++ @property ++ def has_default_route(self): ++ return self._has_default_route ++ + def iter_routes(self, filter_func=None): + for route in self._network_state.get('routes', []): + if filter_func is not None: +@@ -188,6 +193,23 @@ class NetworkState(object): + if filter_func(iface): + yield iface + ++ def _find_default_route(self): ++ for route in self.iter_routes(): ++ if self._is_default_route(route): ++ return True ++ for iface in self.iter_interfaces(): ++ for subnet in iface.get('subnets', []): ++ for route in subnet.get('routes', []): ++ if self._is_default_route(route): ++ return True ++ ++ def _is_default_route(self, route): ++ default_nets = ('::', '0.0.0.0') ++ return ( ++ route.get('prefix') == 0 and ++ route.get('network') in default_nets ++ ) ++ + + @six.add_metaclass(CommandHandlerMeta) + class NetworkStateInterpreter(object): +--- cloudinit/net/sysconfig.py.orig ++++ cloudinit/net/sysconfig.py +@@ -310,6 +310,7 @@ class Renderer(renderer.Renderer): + mtu_key = 'MTU' + subnet_type = subnet.get('type') + if subnet_type == 'dhcp6': ++ # TODO need to set BOOTPROTO to dhcp6 on SUSE + iface_cfg['IPV6INIT'] = True + iface_cfg['DHCPV6C'] = True + elif subnet_type in ['dhcp4', 'dhcp']: +@@ -355,9 +356,12 @@ class Renderer(renderer.Renderer): + ipv6_index = -1 + for i, subnet in enumerate(subnets, start=len(iface_cfg.children)): + subnet_type = subnet.get('type') +- if subnet_type == 'dhcp6': +- continue +- elif subnet_type in ['dhcp4', 'dhcp']: ++ if subnet_type in ['dhcp', 'dhcp4', 'dhcp6']: ++ if ( ++ cls._network_default_route and ++ iface_cfg['BOOTPROTO'] != 'none' ++ ): ++ iface_cfg['DHCLIENT_SET_DEFAULT_ROUTE'] = False + continue + elif subnet_type == 'static': + if subnet_is_ipv6(subnet): +@@ -423,6 +427,8 @@ class Renderer(renderer.Renderer): + # TODO(harlowja): add validation that no other iface has + # also provided the default route? + iface_cfg['DEFROUTE'] = True ++ if iface_cfg['BOOTPROTO'] in ('dhcp', 'dhcp4', 'dhcp6'): ++ iface_cfg['DHCLIENT_SET_DEFAULT_ROUTE'] = True + if 'gateway' in route: + if is_ipv6 or is_ipv6_addr(route['gateway']): + iface_cfg['IPV6_DEFAULTGW'] = route['gateway'] +@@ -636,6 +642,10 @@ class Renderer(renderer.Renderer): + return contents + + def render_network_state(self, network_state, templates=None, target=None): ++ # Force the knowledge of a default route for the network state ++ # into the renderer, this is needed to write the proper ifcfg- ++ # on SUSE distros ++ self.__class__._network_default_route = network_state.has_default_route + if not templates: + templates = self.templates + file_mode = 0o644 +--- tests/unittests/test_net.py.orig ++++ tests/unittests/test_net.py +@@ -538,6 +538,7 @@ NETWORK_CONFIGS = { + BOOTPROTO=dhcp + DEFROUTE=yes + DEVICE=eth99 ++ DHCLIENT_SET_DEFAULT_ROUTE=yes + DNS1=8.8.8.8 + DNS2=8.8.4.4 + DOMAIN="barley.maas sach.maas" +@@ -912,6 +913,7 @@ pre-down route del -net 10.0.0.0 netmask + 'ifcfg-bond0.200': textwrap.dedent("""\ + BOOTPROTO=dhcp + DEVICE=bond0.200 ++ DHCLIENT_SET_DEFAULT_ROUTE=no + NM_CONTROLLED=no + ONBOOT=yes + STARTMODE=auto +@@ -1011,6 +1013,7 @@ pre-down route del -net 10.0.0.0 netmask + 'ifcfg-eth5': textwrap.dedent("""\ + BOOTPROTO=dhcp + DEVICE=eth5 ++ DHCLIENT_SET_DEFAULT_ROUTE=no + HWADDR=98:bb:9f:2c:e8:8a + NM_CONTROLLED=no + ONBOOT=no +@@ -1666,6 +1669,23 @@ CONFIG_V1_SIMPLE_SUBNET = { + 'type': 'static'}], + 'type': 'physical'}]} + ++CONFIG_V1_MULTI_IFACE = { ++ 'version': 1, ++ 'config': [{'type': 'physical', ++ 'mtu': 1500, ++ 'subnets': [{'type': 'static', ++ 'netmask': '255.255.240.0', ++ 'routes': [{'netmask': '0.0.0.0', ++ 'network': '0.0.0.0', ++ 'gateway': '51.68.80.1'}], ++ 'address': '51.68.89.122', ++ 'ipv4': True}], ++ 'mac_address': 'fa:16:3e:25:b4:59', ++ 'name': 'eth0'}, ++ {'type': 'physical', ++ 'mtu': 9000, ++ 'subnets': [{'type': 'dhcp4'}], ++ 'mac_address': 'fa:16:3e:b1:ca:29', 'name': 'eth1'}]} + + DEFAULT_DEV_ATTRS = { + 'eth1000': { +@@ -2133,6 +2153,47 @@ USERCTL=no + """ + self.assertEqual(expected, found[nspath + 'ifcfg-interface0']) + ++ def test_network_config_v1_multi_iface_samples(self): ++ ns = network_state.parse_net_config_data(CONFIG_V1_MULTI_IFACE) ++ render_dir = self.tmp_path("render") ++ os.makedirs(render_dir) ++ renderer = self._get_renderer() ++ renderer.render_network_state(ns, target=render_dir) ++ found = dir2dict(render_dir) ++ nspath = '/etc/sysconfig/network-scripts/' ++ self.assertNotIn(nspath + 'ifcfg-lo', found.keys()) ++ expected_i1 = """\ ++# Created by cloud-init on instance boot automatically, do not edit. ++# ++BOOTPROTO=none ++DEFROUTE=yes ++DEVICE=eth0 ++GATEWAY=51.68.80.1 ++HWADDR=fa:16:3e:25:b4:59 ++IPADDR=51.68.89.122 ++MTU=1500 ++NETMASK=255.255.240.0 ++NM_CONTROLLED=no ++ONBOOT=yes ++TYPE=Ethernet ++USERCTL=no ++""" ++ self.assertEqual(expected_i1, found[nspath + 'ifcfg-eth0']) ++ expected_i2 = """\ ++# Created by cloud-init on instance boot automatically, do not edit. ++# ++BOOTPROTO=dhcp ++DEVICE=eth1 ++DHCLIENT_SET_DEFAULT_ROUTE=no ++HWADDR=fa:16:3e:b1:ca:29 ++MTU=9000 ++NM_CONTROLLED=no ++ONBOOT=yes ++TYPE=Ethernet ++USERCTL=no ++""" ++ self.assertEqual(expected_i2, found[nspath + 'ifcfg-eth1']) ++ + def test_config_with_explicit_loopback(self): + ns = network_state.parse_net_config_data(CONFIG_V1_EXPLICIT_LOOPBACK) + render_dir = self.tmp_path("render") diff --git a/cloud-init.changes b/cloud-init.changes index 4a6c463..c792340 100644 --- a/cloud-init.changes +++ b/cloud-init.changes @@ -9,6 +9,7 @@ Mon Jan 7 20:22:39 UTC 2019 - Robert Schweikert included upstream + Forward port cloud-init-sysconf-ethsetup.patch + Add cloud-init-write-routes.patch + + Add cloud-init-handle-def-route-set.patch + tests: add Disco release [Joshua Powers] + net: render 'metric' values in per-subnet routes (LP: #1805871) + write_files: add support for appending to files. [James Baxter] diff --git a/cloud-init.spec b/cloud-init.spec index ed7e58c..5c20d5d 100644 --- a/cloud-init.spec +++ b/cloud-init.spec @@ -48,6 +48,9 @@ Patch41: cloud-init-static-net.patch Patch42: cloud-init-ostack-metadat-dencode.patch # FIXME (lp#1812117) Patch43: cloud-init-write-routes.patch +# Following submitted upstream +Patch44: cloud-init-handle-def-route-set.patch +# End lp#1812117 BuildRequires: fdupes BuildRequires: filesystem @@ -193,6 +196,7 @@ Documentation and examples for cloud-init tools %patch41 %patch42 %patch43 +%patch44 %build %if 0%{?suse_version} && 0%{?suse_version} <= 1315