← Back to team overview

cloud-init-dev team mailing list archive

[Merge] ~smoser/cloud-init:feature/curtin-centos7 into cloud-init:master

 

Scott Moser has proposed merging ~smoser/cloud-init:feature/curtin-centos7 into cloud-init:master.

Requested reviews:
  cloud-init commiters (cloud-init-dev)
Related bugs:
  Bug #1701097 in cloud-init: "eni rendering of ipv6 gateways fails"
  https://bugs.launchpad.net/cloud-init/+bug/1701097
  Bug #1702513 in cloud-init: "sysconfig should render MTU values from subnets/routes including ipv6"
  https://bugs.launchpad.net/cloud-init/+bug/1702513

For more details, see:
https://code.launchpad.net/~smoser/cloud-init/+git/cloud-init/+merge/327836
-- 
Your team cloud-init commiters is requested to review the proposed merge of ~smoser/cloud-init:feature/curtin-centos7 into cloud-init:master.
diff --git a/cloudinit/net/eni.py b/cloudinit/net/eni.py
index b707146..bb80ec0 100644
--- a/cloudinit/net/eni.py
+++ b/cloudinit/net/eni.py
@@ -355,7 +355,7 @@ class Renderer(renderer.Renderer):
             default_gw = " default gw %s" % route['gateway']
             content.append(up + default_gw + or_true)
             content.append(down + default_gw + or_true)
-        elif route['network'] == '::' and route['netmask'] == 0:
+        elif route['network'] == '::' and route['prefix'] == 0:
             # ipv6!
             default_gw = " -A inet6 default gw %s" % route['gateway']
             content.append(up + default_gw + or_true)
diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py
index b0f2ccf..c7df36c 100644
--- a/cloudinit/net/sysconfig.py
+++ b/cloudinit/net/sysconfig.py
@@ -273,6 +273,7 @@ class Renderer(renderer.Renderer):
 
         # modifying base values according to subnets
         for i, subnet in enumerate(subnets, start=len(iface_cfg.children)):
+            mtu_key = 'MTU'
             subnet_type = subnet.get('type')
             if subnet_type == 'dhcp6':
                 iface_cfg['IPV6INIT'] = True
@@ -292,7 +293,11 @@ class Renderer(renderer.Renderer):
                 # if iface_cfg['BOOTPROTO'] == 'none':
                 #    iface_cfg['BOOTPROTO'] = 'static'
                 if subnet_is_ipv6(subnet):
+                    mtu_key = 'IPV6_MTU'
                     iface_cfg['IPV6INIT'] = True
+
+                if 'mtu' in subnet:
+                    iface_cfg[mtu_key] = subnet['mtu']
             else:
                 raise ValueError("Unknown subnet type '%s' found"
                                  " for interface '%s'" % (subnet_type,
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index e625934..d15cd1f 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -482,6 +482,62 @@ NETWORK_CONFIGS = {
                 - {'type': 'dhcp6'}
         """).rstrip(' '),
     },
+    'v4_and_v6_static': {
+        'expected_eni': textwrap.dedent("""\
+            auto lo
+            iface lo inet loopback
+
+            auto iface0
+            iface iface0 inet static
+                address 192.168.14.2/24
+                mtu 9000
+
+            # control-alias iface0
+            iface iface0 inet6 static
+                address 2001:1::1/64
+                mtu 1500
+        """).rstrip(' '),
+        'expected_netplan': textwrap.dedent("""
+            network:
+                version: 2
+                ethernets:
+                    iface0:
+                        addresses:
+                        - 192.168.14.2/24
+                        - 2001:1::1/64
+                        mtu: 9000
+                        mtu6: 1500
+        """).rstrip(' '),
+        'yaml': textwrap.dedent("""\
+            version: 1
+            config:
+              - type: 'physical'
+                name: 'iface0'
+                subnets:
+                  - type: static
+                    address: 192.168.14.2/24
+                    mtu: 9000
+                  - type: static
+                    address: 2001:1::1/64
+                    mtu: 1500
+        """).rstrip(' '),
+        'expected_sysconfig': {
+            'ifcfg-iface0': textwrap.dedent("""\
+                BOOTPROTO=none
+                DEVICE=iface0
+                IPADDR=192.168.14.2
+                IPV6ADDR=2001:1::1/64
+                IPV6INIT=yes
+                NETMASK=255.255.255.0
+                NM_CONTROLLED=no
+                ONBOOT=yes
+                TYPE=Ethernet
+                USERCTL=no
+                MTU=9000
+                IPV6_MTU=1500
+                """),
+        },
+    },
     'all': {
         'expected_eni': ("""\
 auto lo
@@ -541,6 +597,8 @@ iface br0 inet static
 # control-alias br0
 iface br0 inet6 static
     address 2001:1::1/64
+    post-up route add -A inet6 default gw 2001:4800:78ff:1b::1 || true
+    pre-down route del -A inet6 default gw 2001:4800:78ff:1b::1 || true
 
 auto bond0.200
 iface bond0.200 inet dhcp
@@ -675,6 +733,9 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true
                                 eth3: 50
                                 eth4: 75
                             priority: 22
+                        routes:
+                        -   to: ::/0
+                            via: 2001:4800:78ff:1b::1
                 vlans:
                     bond0.200:
                         dhcp4: true
@@ -807,6 +868,10 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true
                         address: 192.168.14.2/24
                       - type: static
                         address: 2001:1::1/64 # default to /64
+                        routes:
+                          - gateway: 2001:4800:78ff:1b::1
+                            netmask: '::'
+                            network: '::'
                 # A global nameserver.
                 - type: nameserver
                   address: 8.8.8.8
@@ -1499,6 +1564,12 @@ USERCTL=no
         self._compare_files_to_expected(entry['expected_sysconfig'], found)
         self._assert_headers(found)
 
+    def test_v4_and_v6_static_config(self):
+        entry = NETWORK_CONFIGS['v4_and_v6_static']
+        found = self._render_and_read(network_config=yaml.load(entry['yaml']))
+        self._compare_files_to_expected(entry['expected_sysconfig'], found)
+        self._assert_headers(found)
+
 
 class TestEniNetRendering(CiTestCase):
 
@@ -1892,6 +1963,13 @@ class TestNetplanRoundTrip(CiTestCase):
             entry['expected_netplan'].splitlines(),
             files['/etc/netplan/50-cloud-init.yaml'].splitlines())
 
+    def testsimple_render_v4_and_v6_static(self):
+        entry = NETWORK_CONFIGS['v4_and_v6_static']
+        files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+        self.assertEqual(
+            entry['expected_netplan'].splitlines(),
+            files['/etc/netplan/50-cloud-init.yaml'].splitlines())
+
     def testsimple_render_all(self):
         entry = NETWORK_CONFIGS['all']
         files = self._render_and_read(network_config=yaml.load(entry['yaml']))
@@ -1950,6 +2028,13 @@ class TestEniRoundTrip(CiTestCase):
             entry['expected_eni'].splitlines(),
             files['/etc/network/interfaces'].splitlines())
 
+    def testsimple_render_v4_and_v6_static(self):
+        entry = NETWORK_CONFIGS['v4_and_v6_static']
+        files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+        self.assertEqual(
+            entry['expected_eni'].splitlines(),
+            files['/etc/network/interfaces'].splitlines())
+
     def testsimple_render_manual(self):
         entry = NETWORK_CONFIGS['manual']
         files = self._render_and_read(network_config=yaml.load(entry['yaml']))

Follow ups