networkd: support drop-in directories for .network files
authorJean-Sébastien Bour <jean-sebastien@bour.name>
Sat, 9 Jul 2016 14:55:26 +0000 (16:55 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 16 Sep 2016 14:31:58 +0000 (10:31 -0400)
Fixes #3655.

[zj: Fix the tests.]

src/network/networkd-network.c
test/networkd-test.py

index 49faba5..0b36f13 100644 (file)
@@ -40,6 +40,10 @@ static int network_load_one(Manager *manager, const char *filename) {
         _cleanup_network_free_ Network *network = NULL;
         _cleanup_fclose_ FILE *file = NULL;
         char *d;
+        const char *dropin_dirname;
+        _cleanup_strv_free_ char **dropin_dirs = NULL;
+        _cleanup_free_ char *dropin_dirs_nulstr = NULL;
+        size_t dropin_dirs_nulstr_size;
         Route *route;
         Address *address;
         int r;
@@ -137,7 +141,17 @@ static int network_load_one(Manager *manager, const char *filename) {
         network->arp = -1;
         network->ipv6_accept_ra_use_dns = true;
 
-        r = config_parse(NULL, filename, file,
+        dropin_dirname = strjoina("/", network->name, ".network.d");
+
+        r = strv_extend_strv_concat(&dropin_dirs, (char**) network_dirs, dropin_dirname);
+        if (r < 0)
+                return r;
+
+        r = strv_make_nulstr(dropin_dirs, &dropin_dirs_nulstr, &dropin_dirs_nulstr_size);
+        if (r < 0)
+                return r;
+
+        r = config_parse_many(filename, dropin_dirs_nulstr,
                          "Match\0"
                          "Link\0"
                          "Network\0"
@@ -151,7 +165,7 @@ static int network_load_one(Manager *manager, const char *filename) {
                          "BridgeFDB\0"
                          "BridgeVLAN\0",
                          config_item_perf_lookup, network_network_gperf_lookup,
-                         false, false, true, network);
+                         false, network);
         if (r < 0)
                 return r;
 
index 57f4c04..baa1dc2 100755 (executable)
@@ -456,6 +456,36 @@ Domains={p}0 {p}1 {p}2 {p}3 {p}4'''.format(p=name_prefix))
         self.assertRegex(contents, 'search .*{p}0 {p}1 {p}2'.format(p=name_prefix))
         self.assertIn('# Total length of all search domains is too long, remaining ones ignored.', contents)
 
+    def test_dropin(self):
+        # we don't use this interface for this test
+        self.if_router = None
+
+        self.writeConfig('/run/systemd/network/test.netdev', '''\
+[NetDev]
+Name=dummy0
+Kind=dummy
+MACAddress=12:34:56:78:9a:bc''')
+        self.writeConfig('/run/systemd/network/test.network', '''\
+[Match]
+Name=dummy0
+[Network]
+Address=192.168.42.100
+DNS=192.168.42.1''')
+        self.writeConfig('/run/systemd/network/test.network.d/dns.conf', '''\
+[Network]
+DNS=127.0.0.1''')
+
+        subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+
+        for timeout in range(50):
+            with open(RESOLV_CONF) as f:
+                contents = f.read()
+            if ' 127.0.0.1' in contents:
+                break
+            time.sleep(0.1)
+        self.assertIn('nameserver 192.168.42.1\n', contents)
+        self.assertIn('nameserver 127.0.0.1\n', contents)
+
 if __name__ == '__main__':
     unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
                                                      verbosity=2))