Blob Blame History Raw
From 3ee8f2f5dde1bb27e682c5985bffe6fb9f9e5e0b Mon Sep 17 00:00:00 2001
From: Eduardo Otubo <otubo@redhat.com>
Date: Thu, 5 Nov 2020 12:42:26 +0100
Subject: [PATCH 5/5] net: fix rendering of 'static6' in network config (#77)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

RH-Author: Eduardo Terrell Ferrari Otubo (eterrell)
RH-MergeRequest: 17: Explicit set IPV6_AUTOCONF and IPV6_FORCE_ACCEPT_RA on static6 (#634)
RH-Commit: [2/2] 30eb756aceb37761d50c70eb4f684662a11afa3f (eterrell/cloud-init)
RH-Bugzilla: 1894015

commit dacdd30080bd8183d1f1c1dc9dbcbc8448301529
Author: Ryan Harper <ryan.harper@canonical.com>
Date:   Wed Jan 8 11:30:17 2020 -0600

    net: fix rendering of 'static6' in network config (#77)

    * net: fix rendering of 'static6' in network config

    A V1 static6 network typo was misrendered in eni, it's not valid.
    It was ignored in sysconfig and netplan.  This branch fixes eni,
    updates sysconfig, netplan to render it correctly and adds unittests
    for all cases.

    Reported-by: Raphaƫl Enrici

    LP: #1850988

    * net: add comment about static6 type in subnet_is_ipv6

    Co-authored-by: Chad Smith <blackboxsw@gmail.com>
    Co-authored-by: Daniel Watkins <daniel@daniel-watkins.co.uk>

Signed-off-by: Eduardo Otubo <otubo@redhat.com>
---
 cloudinit/net/eni.py                           |  4 +-
 cloudinit/net/netplan.py                       |  2 +-
 cloudinit/net/network_state.py                 |  2 +-
 cloudinit/net/sysconfig.py                     |  4 +-
 tests/unittests/test_distros/test_netconfig.py | 55 +++++++++++++++++++++++++-
 5 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/cloudinit/net/eni.py b/cloudinit/net/eni.py
index 7077106..2f71456 100644
--- a/cloudinit/net/eni.py
+++ b/cloudinit/net/eni.py
@@ -429,7 +429,9 @@ class Renderer(renderer.Renderer):
                     iface['mode'] = 'auto'
                     # Use stateless DHCPv6 (0=off, 1=on)
                     iface['dhcp'] = '0'
-                elif subnet_is_ipv6(subnet) and subnet['type'] == 'static':
+                elif subnet_is_ipv6(subnet):
+                    # mode might be static6, eni uses 'static'
+                    iface['mode'] = 'static'
                     if accept_ra is not None:
                         # Accept router advertisements (0=off, 1=on)
                         iface['accept_ra'] = '1' if accept_ra else '0'
diff --git a/cloudinit/net/netplan.py b/cloudinit/net/netplan.py
index 14d3999..8985527 100644
--- a/cloudinit/net/netplan.py
+++ b/cloudinit/net/netplan.py
@@ -98,7 +98,7 @@ def _extract_addresses(config, entry, ifname, features=None):
             entry.update({sn_type: True})
         elif sn_type in IPV6_DYNAMIC_TYPES:
             entry.update({'dhcp6': True})
-        elif sn_type in ['static']:
+        elif sn_type in ['static', 'static6']:
             addr = "%s" % subnet.get('address')
             if 'prefix' in subnet:
                 addr += "/%d" % subnet.get('prefix')
diff --git a/cloudinit/net/network_state.py b/cloudinit/net/network_state.py
index 2525fc9..48e5b6e 100644
--- a/cloudinit/net/network_state.py
+++ b/cloudinit/net/network_state.py
@@ -942,7 +942,7 @@ def subnet_is_ipv6(subnet):
     # 'static6', 'dhcp6', 'ipv6_dhcpv6-stateful', 'ipv6_dhcpv6-stateless' or
     # 'ipv6_slaac'
     if subnet['type'].endswith('6') or subnet['type'] in IPV6_DYNAMIC_TYPES:
-        # This is a request for DHCPv6.
+        # This is a request either static6 type or DHCPv6.
         return True
     elif subnet['type'] == 'static' and is_ipv6_addr(subnet.get('address')):
         return True
diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py
index 4210544..1989d01 100644
--- a/cloudinit/net/sysconfig.py
+++ b/cloudinit/net/sysconfig.py
@@ -378,7 +378,7 @@ class Renderer(renderer.Renderer):
                 iface_cfg['IPV6_AUTOCONF'] = True
             elif subnet_type in ['dhcp4', 'dhcp']:
                 iface_cfg['BOOTPROTO'] = 'dhcp'
-            elif subnet_type == 'static':
+            elif subnet_type in ['static', 'static6']:
                 # grep BOOTPROTO sysconfig.txt -A2 | head -3
                 # BOOTPROTO=none|bootp|dhcp
                 # 'bootp' or 'dhcp' cause a DHCP client
@@ -434,7 +434,7 @@ class Renderer(renderer.Renderer):
                 continue
             elif subnet_type in IPV6_DYNAMIC_TYPES:
                 continue
-            elif subnet_type == 'static':
+            elif subnet_type in ['static', 'static6']:
                 if subnet_is_ipv6(subnet):
                     ipv6_index = ipv6_index + 1
                     ipv6_cidr = "%s/%s" % (subnet['address'], subnet['prefix'])
diff --git a/tests/unittests/test_distros/test_netconfig.py b/tests/unittests/test_distros/test_netconfig.py
index b85a333..e277bca 100644
--- a/tests/unittests/test_distros/test_netconfig.py
+++ b/tests/unittests/test_distros/test_netconfig.py
@@ -109,13 +109,31 @@ auto eth1
 iface eth1 inet dhcp
 """
 
+V1_NET_CFG_IPV6_OUTPUT = """\
+# This file is generated from information provided by the datasource.  Changes
+# to it will not persist across an instance reboot.  To disable cloud-init's
+# network configuration capabilities, write a file
+# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
+# network: {config: disabled}
+auto lo
+iface lo inet loopback
+
+auto eth0
+iface eth0 inet6 static
+    address 2607:f0d0:1002:0011::2/64
+    gateway 2607:f0d0:1002:0011::1
+
+auto eth1
+iface eth1 inet dhcp
+"""
+
 V1_NET_CFG_IPV6 = {'config': [{'name': 'eth0',
                                'subnets': [{'address':
                                             '2607:f0d0:1002:0011::2',
                                             'gateway':
                                             '2607:f0d0:1002:0011::1',
                                             'netmask': '64',
-                                            'type': 'static'}],
+                                            'type': 'static6'}],
                                'type': 'physical'},
                               {'name': 'eth1',
                                'subnets': [{'control': 'auto',
@@ -141,6 +159,23 @@ network:
             dhcp4: true
 """
 
+V1_TO_V2_NET_CFG_IPV6_OUTPUT = """\
+# This file is generated from information provided by the datasource.  Changes
+# to it will not persist across an instance reboot.  To disable cloud-init's
+# network configuration capabilities, write a file
+# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
+# network: {config: disabled}
+network:
+    version: 2
+    ethernets:
+        eth0:
+            addresses:
+            - 2607:f0d0:1002:0011::2/64
+            gateway6: 2607:f0d0:1002:0011::1
+        eth1:
+            dhcp4: true
+"""
+
 V2_NET_CFG = {
     'ethernets': {
         'eth7': {
@@ -376,6 +411,14 @@ class TestNetCfgDistroUbuntuEni(TestNetCfgDistroBase):
                                    V1_NET_CFG,
                                    expected_cfgs=expected_cfgs.copy())
 
+    def test_apply_network_config_ipv6_ub(self):
+        expected_cfgs = {
+            self.eni_path(): V1_NET_CFG_IPV6_OUTPUT
+        }
+        self._apply_and_verify_eni(self.distro.apply_network_config,
+                                   V1_NET_CFG_IPV6,
+                                   expected_cfgs=expected_cfgs.copy())
+
 
 class TestNetCfgDistroUbuntuNetplan(TestNetCfgDistroBase):
     def setUp(self):
@@ -419,6 +462,16 @@ class TestNetCfgDistroUbuntuNetplan(TestNetCfgDistroBase):
                                        V1_NET_CFG,
                                        expected_cfgs=expected_cfgs.copy())
 
+    def test_apply_network_config_v1_ipv6_to_netplan_ub(self):
+        expected_cfgs = {
+            self.netplan_path(): V1_TO_V2_NET_CFG_IPV6_OUTPUT,
+        }
+
+        # ub_distro.apply_network_config(V1_NET_CFG_IPV6, False)
+        self._apply_and_verify_netplan(self.distro.apply_network_config,
+                                       V1_NET_CFG_IPV6,
+                                       expected_cfgs=expected_cfgs.copy())
+
     def test_apply_network_config_v2_passthrough_ub(self):
         expected_cfgs = {
             self.netplan_path(): V2_TO_V2_NET_CFG_OUTPUT,
-- 
1.8.3.1