← Back to team overview

cloud-init-dev team mailing list archive

[Merge] ~raphael-glon/cloud-init:master into cloud-init:master

 

raphael.glon has proposed merging ~raphael-glon/cloud-init:master into cloud-init:master.

Commit message:
Fix net/eni static routes for ipv6
    
eni: post-up/pre down commands were not correct for ipv6

unittests:
additional test to check the
rendered static routes for eni config

beware: detected but not fixed, a problem with ipv6 and
sysconfig (bug for opensuse only). Not fixing because I do not
have such distrib at hand to validate rendered files
btw, this problem seems currently ignored in the test_bond unit test


Requested reviews:
  cloud-init commiters (cloud-init-dev)

For more details, see:
https://code.launchpad.net/~raphael-glon/cloud-init/+git/cloud-init/+merge/363970
-- 
Your team cloud-init commiters is requested to review the proposed merge of ~raphael-glon/cloud-init:master into cloud-init:master.
diff --git a/cloudinit/net/eni.py b/cloudinit/net/eni.py
index 6423632..f787a1e 100644
--- a/cloudinit/net/eni.py
+++ b/cloudinit/net/eni.py
@@ -366,26 +366,43 @@ class Renderer(renderer.Renderer):
         down = indent + "pre-down route del"
         or_true = " || true"
         mapping = {
-            'network': '-net',
-            'netmask': 'netmask',
-            'gateway': 'gw',
-            'metric': 'metric',
+            'network': ' -net',
+            'netmask': ' netmask',
+            'gateway': ' gw',
+            'metric': ' metric',
         }
 
         default_gw = ''
-        if route['network'] == '0.0.0.0' and route['netmask'] == '0.0.0.0':
+        if ':' in route['network']:
+            version = 6
+            up += " -A inet6"
+            down += " -A inet6"
+            mapping['network'] = ''
+        else:
+            version = 4
+
+        if version == 4 and route['network'] == '0.0.0.0' \
+                and route['netmask'] == '0.0.0.0':
+            default_gw = ' default'
+        elif version == 6 and route['network'] == '::' and \
+                route['prefix'] == 0:
             default_gw = ' default'
-        elif route['network'] == '::' and route['prefix'] == 0:
-            default_gw = ' -A inet6 default'
+        elif version == 6:
+            route['network'] = '{}/{}'.format(route['network'],
+                                              route['prefix'])
+            route.pop('netmask', None)
 
         route_line = ''
         for k in ['network', 'netmask', 'gateway', 'metric']:
             if default_gw and k in ['network', 'netmask']:
                 continue
-            if k == 'gateway':
-                route_line += '%s %s %s' % (default_gw, mapping[k], route[k])
-            elif k in route:
-                route_line += ' %s %s' % (mapping[k], route[k])
+            if k in route:
+                if k == 'gateway':
+                    route_line += '%s%s %s' % (default_gw, mapping[k],
+                                               route[k])
+                else:
+                    route_line += '%s %s' % (mapping[k], route[k])
+
         content.append(up + route_line + or_true)
         content.append(down + route_line + or_true)
         return content
diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py
index 19b3e60..a658930 100644
--- a/cloudinit/net/sysconfig.py
+++ b/cloudinit/net/sysconfig.py
@@ -653,6 +653,11 @@ class Renderer(renderer.Renderer):
                 for cpath, proto in zip([iface_cfg.routes.path_ipv4,
                                          iface_cfg.routes.path_ipv6],
                                         ["ipv4", "ipv6"]):
+                    # FIXME: there is a problem here for Opensuse:
+                    # it has the same route template file path for both ipv4
+                    # and ipv6... This means that you
+                    # cannot have ipv6 static routes for this distribution,
+                    # because the ipv4 fills the place before.
                     if cpath not in contents:
                         contents[cpath] = iface_cfg.routes.to_string(proto)
         return contents
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index e3b9e02..e7dad9e 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -799,6 +799,37 @@ iface eth1 inet static
 """.lstrip()
 
 NETWORK_CONFIGS = {
+    'ipv6_static_route': {
+        'yaml': textwrap.dedent("""
+            config:
+            - mac_address: aa:12:bc:34:ee:ac
+              name: eno3
+              subnets:
+              - address: fd00::12/64
+                dns_nameservers: ['fd00:2::15']
+                gateway: fd00::1
+                ipv6: true
+                routes:
+                - netmask: '32'
+                  network: 'fd00:12::'
+                  gateway: fd00::2
+                type: static
+              type: physical
+            version: 1
+"""),
+        'expected_eni': textwrap.dedent("""\
+            auto lo
+            iface lo inet loopback
+
+            auto eno3
+            iface eno3 inet6 static
+                address fd00::12/64
+                dns-nameservers fd00:2::15
+                gateway fd00::1
+                post-up route add -A inet6 fd00:12::/32 gw fd00::2 || true
+                pre-down route del -A inet6 fd00:12::/32 gw fd00::2 || true
+    """),
+    },
     'small': {
         'expected_eni': textwrap.dedent("""\
             auto lo
@@ -1664,6 +1695,7 @@ pre-down route del -net 10.0.0.0 netmask 255.0.0.0 gw 11.0.0.1 metric 3 || true
         TYPE=Ethernet
         USERCTL=no
         """),
+            # FIXME: what about static ipv6 routes? Dropped ?
             'ifroute-bond0': textwrap.dedent("""\
         ADDRESS0=10.1.3.0
         GATEWAY0=192.168.0.3
@@ -3486,6 +3518,13 @@ class TestEniRoundTrip(CiTestCase):
         renderer.render_network_state(ns, target=dir)
         return dir2dict(dir)
 
+    def testsimple_render_static_ipv6(self):
+        entry = NETWORK_CONFIGS['ipv6_static_route']
+        files = self._render_and_read(network_config=yaml.load(entry['yaml']))
+        self.assertEqual(
+            entry['expected_eni'].splitlines(),
+            files['/etc/network/interfaces'].splitlines())
+
     def testsimple_convert_and_render(self):
         network_config = eni.convert_eni_data(EXAMPLE_ENI)
         files = self._render_and_read(network_config=network_config)

Follow ups