summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan McCabe <rmccabe@redhat.com>2017-06-08 13:24:23 -0400
committerScott Moser <smoser@brickies.net>2017-06-12 12:07:26 -0400
commit67bab5bb804e2346673430868935f6bbcdb88f13 (patch)
tree39fb2663a0659411852e86bd220ea2cfe680fa25
parentb9cd8a82ee41e235df66801a02b2244226bee5ee (diff)
downloadvyos-cloud-init-67bab5bb804e2346673430868935f6bbcdb88f13.tar.gz
vyos-cloud-init-67bab5bb804e2346673430868935f6bbcdb88f13.zip
net: Allow for NetworkManager configuration
In cases where the config json specifies nameserver entries, if there are interfaces configured to use dhcp, NetworkManager, if enabled, will clobber the /etc/resolv.conf that cloud-init has produced, which can break dns. If there are no interfaces configured to use dhcp, NetworkManager could clobber /etc/resolv.conf with an empty file. This patch adds a mechanism for dropping additional configuration into /etc/NetworkManager/conf.d/ and disables management of /etc/resolv.conf by NetworkManager when nameserver information is provided in the config. LP: #1693251 Signed-off-by: Ryan McCabe <rmccabe@redhat.com>
-rw-r--r--cloudinit/distros/parsers/networkmanager_conf.py23
-rw-r--r--cloudinit/net/sysconfig.py25
-rw-r--r--tests/unittests/test_net.py21
3 files changed, 69 insertions, 0 deletions
diff --git a/cloudinit/distros/parsers/networkmanager_conf.py b/cloudinit/distros/parsers/networkmanager_conf.py
new file mode 100644
index 00000000..ac51f122
--- /dev/null
+++ b/cloudinit/distros/parsers/networkmanager_conf.py
@@ -0,0 +1,23 @@
+# Copyright (C) 2017 Red Hat, Inc.
+#
+# Author: Ryan McCabe <rmccabe@redhat.com>
+#
+# This file is part of cloud-init. See LICENSE file for license information.
+
+import configobj
+
+# This module is used to set additional NetworkManager configuration
+# in /etc/NetworkManager/conf.d
+#
+
+
+class NetworkManagerConf(configobj.ConfigObj):
+ def __init__(self, contents):
+ configobj.ConfigObj.__init__(self, contents,
+ interpolation=False,
+ write_empty_values=False)
+
+ def set_section_keypair(self, section_name, key, value):
+ if section_name not in self.sections:
+ self.main[section_name] = {}
+ self.main[section_name] = {key: value}
diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py
index 5d9b3d10..7ed11d1e 100644
--- a/cloudinit/net/sysconfig.py
+++ b/cloudinit/net/sysconfig.py
@@ -5,6 +5,7 @@ import re
import six
+from cloudinit.distros.parsers import networkmanager_conf
from cloudinit.distros.parsers import resolv_conf
from cloudinit import util
@@ -249,6 +250,9 @@ class Renderer(renderer.Renderer):
self.netrules_path = config.get(
'netrules_path', 'etc/udev/rules.d/70-persistent-net.rules')
self.dns_path = config.get('dns_path', 'etc/resolv.conf')
+ nm_conf_path = 'etc/NetworkManager/conf.d/99-cloud-init.conf'
+ self.networkmanager_conf_path = config.get('networkmanager_conf_path',
+ nm_conf_path)
@classmethod
def _render_iface_shared(cls, iface, iface_cfg):
@@ -438,6 +442,21 @@ class Renderer(renderer.Renderer):
content.add_search_domain(searchdomain)
return "\n".join([_make_header(';'), str(content)])
+ @staticmethod
+ def _render_networkmanager_conf(network_state):
+ content = networkmanager_conf.NetworkManagerConf("")
+
+ # If DNS server information is provided, configure
+ # NetworkManager to not manage dns, so that /etc/resolv.conf
+ # does not get clobbered.
+ if network_state.dns_nameservers:
+ content.set_section_keypair('main', 'dns', 'none')
+
+ if len(content) == 0:
+ return None
+ out = "".join([_make_header(), "\n", "\n".join(content.write()), "\n"])
+ return out
+
@classmethod
def _render_bridge_interfaces(cls, network_state, iface_contents):
bridge_filter = renderer.filter_by_type('bridge')
@@ -498,6 +517,12 @@ class Renderer(renderer.Renderer):
resolv_content = self._render_dns(network_state,
existing_dns_path=dns_path)
util.write_file(dns_path, resolv_content, file_mode)
+ if self.networkmanager_conf_path:
+ nm_conf_path = util.target_path(target,
+ self.networkmanager_conf_path)
+ nm_conf_content = self._render_networkmanager_conf(network_state)
+ if nm_conf_content:
+ util.write_file(nm_conf_path, nm_conf_content, file_mode)
if self.netrules_path:
netrules_content = self._render_persistent_net(network_state)
netrules_path = util.target_path(target, self.netrules_path)
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index 91e5fb59..8edc0b89 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -156,6 +156,13 @@ USERCTL=no
;
nameserver 172.19.0.12
""".lstrip()),
+ ('etc/NetworkManager/conf.d/99-cloud-init.conf',
+ """
+# Created by cloud-init on instance boot automatically, do not edit.
+#
+[main]
+dns = none
+""".lstrip()),
('etc/udev/rules.d/70-persistent-net.rules',
"".join(['SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n']))]
@@ -217,6 +224,13 @@ USERCTL=no
;
nameserver 172.19.0.12
""".lstrip()),
+ ('etc/NetworkManager/conf.d/99-cloud-init.conf',
+ """
+# Created by cloud-init on instance boot automatically, do not edit.
+#
+[main]
+dns = none
+""".lstrip()),
('etc/udev/rules.d/70-persistent-net.rules',
"".join(['SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n']))]
@@ -300,6 +314,13 @@ USERCTL=no
;
nameserver 172.19.0.12
""".lstrip()),
+ ('etc/NetworkManager/conf.d/99-cloud-init.conf',
+ """
+# Created by cloud-init on instance boot automatically, do not edit.
+#
+[main]
+dns = none
+""".lstrip()),
('etc/udev/rules.d/70-persistent-net.rules',
"".join(['SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ',
'ATTR{address}=="fa:16:3e:ed:9a:59", NAME="eth0"\n']))]