Merge ~raharper/cloud-init:fix/sysconfig-skip-resolvconf-no-dns-config into cloud-init:master

Proposed by Ryan Harper
Status: Merged
Approved by: Ryan Harper
Approved revision: 6ac5b74e1a91cfad0edb999bfbbad9715ccd68a2
Merge reported by: Server Team CI bot
Merged at revision: not available
Proposed branch: ~raharper/cloud-init:fix/sysconfig-skip-resolvconf-no-dns-config
Merge into: cloud-init:master
Diff against target: 68 lines (+16/-2)
2 files modified
cloudinit/net/sysconfig.py (+4/-2)
tests/unittests/test_net.py (+12/-0)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Dan Watkins Approve
Review via email: mp+372727@code.launchpad.net

Commit message

sysconfig: only write resolv.conf if network_state has DNS values

If an OS image provided an /etc/resolv.conf file that was not empty
cloud-init would read and re-write it with a cloud-init header even
if no DNS network configuration was provided (e.g. DHCP only).

This can cause problems for some network services which don't
ignore cloud-init's header.

LP: #1843634

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:cc70b43e9becd6a469ed17430c5907b85b5f2b2d
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1139/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1139//rebuild

review: Approve (continuous-integration)
Revision history for this message
Scott Moser (smoser) wrote :

It can be argued that cloud-init *was* doing the right thing.
It was told that there were no dns servers and no dns 'search' (by lack of that in network config).

dhcp muddies that argument for sure.

That said, based on the content in the description of the bug (the
previously-existing /etc/resolv.conf), cloud-init should *never* be
writing that file when 'netconfig' is involved. It seems rather that
resolv.conf is generated based on contents of
/etc/sysconfig/network/config .

Would writing /etc/sysconfig/network/config with valid content for NETCONFIG_DNS_STATIC_SEARCHLIST and friends fix this?

Revision history for this message
Ryan Harper (raharper) wrote :

Maybe, but I don't think we really wanted to always append a header to the file, and we certainly wanted to avoid writing the file if we didn't have a config. Lastly the side-effect of modifying resolvconf without dns settings disabled system auto-generation.

We do need to be careful w.r.t detecting whether netconfig is present or not. I think that we could replace updating resolvconf directly if netconfig is present. This renderer is shared by a range of SuSE and RHEL releases which may or maynot have netconfig (or something equivalent).

I'd like Robert to comment on whether we want to move to netconfig or not. That can be done incrementally (land this fix of not touching resolv.conf at all if we don't have settings) and then separately replacing writing resolv.conf directly with using netconfig if present.

71a4b90... by Ryan Harper

Move network_state check up to top of _render_dns

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:485384fe14caf0a3da01dfd7d5c79027e2c00161
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1141/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1141//rebuild

review: Approve (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:ac38c650c1b6cb9df4021786d772450470f17aff
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1176/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1176//rebuild

review: Approve (continuous-integration)
Revision history for this message
Dan Watkins (oddbloke) wrote :

One nit inline, so leaving this to Ryan to merge (whether or not the nit is addressed). Thanks!

review: Approve
6ac5b74... by Ryan Harper

Clarify content variable names

Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:6ac5b74e1a91cfad0edb999bfbbad9715ccd68a2
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1182/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1182//rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py
index be5dede..1708990 100644
--- a/cloudinit/net/sysconfig.py
+++ b/cloudinit/net/sysconfig.py
@@ -578,6 +578,10 @@ class Renderer(renderer.Renderer):
578578
579 @staticmethod579 @staticmethod
580 def _render_dns(network_state, existing_dns_path=None):580 def _render_dns(network_state, existing_dns_path=None):
581 # skip writing resolv.conf if network_state doesn't include any input.
582 if not any([len(network_state.dns_nameservers),
583 len(network_state.dns_searchdomains)]):
584 return None
581 content = resolv_conf.ResolvConf("")585 content = resolv_conf.ResolvConf("")
582 if existing_dns_path and os.path.isfile(existing_dns_path):586 if existing_dns_path and os.path.isfile(existing_dns_path):
583 content = resolv_conf.ResolvConf(util.load_file(existing_dns_path))587 content = resolv_conf.ResolvConf(util.load_file(existing_dns_path))
@@ -585,8 +589,6 @@ class Renderer(renderer.Renderer):
585 content.add_nameserver(nameserver)589 content.add_nameserver(nameserver)
586 for searchdomain in network_state.dns_searchdomains:590 for searchdomain in network_state.dns_searchdomains:
587 content.add_search_domain(searchdomain)591 content.add_search_domain(searchdomain)
588 if not str(content):
589 return None
590 header = _make_header(';')592 header = _make_header(';')
591 content_str = str(content)593 content_str = str(content)
592 if not content_str.startswith(header):594 if not content_str.startswith(header):
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index e578992..92c7c3c 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -2701,6 +2701,10 @@ USERCTL=no
2701 ns = network_state.parse_net_config_data(CONFIG_V1_EXPLICIT_LOOPBACK)2701 ns = network_state.parse_net_config_data(CONFIG_V1_EXPLICIT_LOOPBACK)
2702 render_dir = self.tmp_path("render")2702 render_dir = self.tmp_path("render")
2703 os.makedirs(render_dir)2703 os.makedirs(render_dir)
2704 # write an etc/resolv.conf and expect it to not be modified
2705 resolvconf = os.path.join(render_dir, 'etc/resolv.conf')
2706 resolvconf_content = "# Original Content"
2707 util.write_file(resolvconf, resolvconf_content)
2704 renderer = self._get_renderer()2708 renderer = self._get_renderer()
2705 renderer.render_network_state(ns, target=render_dir)2709 renderer.render_network_state(ns, target=render_dir)
2706 found = dir2dict(render_dir)2710 found = dir2dict(render_dir)
@@ -2718,6 +2722,8 @@ TYPE=Ethernet
2718USERCTL=no2722USERCTL=no
2719"""2723"""
2720 self.assertEqual(expected, found[nspath + 'ifcfg-eth0'])2724 self.assertEqual(expected, found[nspath + 'ifcfg-eth0'])
2725 # a dhcp only config should not modify resolv.conf
2726 self.assertEqual(resolvconf_content, found['/etc/resolv.conf'])
27212727
2722 def test_bond_config(self):2728 def test_bond_config(self):
2723 expected_name = 'expected_sysconfig_rhel'2729 expected_name = 'expected_sysconfig_rhel'
@@ -3202,6 +3208,10 @@ USERCTL=no
3202 ns = network_state.parse_net_config_data(CONFIG_V1_EXPLICIT_LOOPBACK)3208 ns = network_state.parse_net_config_data(CONFIG_V1_EXPLICIT_LOOPBACK)
3203 render_dir = self.tmp_path("render")3209 render_dir = self.tmp_path("render")
3204 os.makedirs(render_dir)3210 os.makedirs(render_dir)
3211 # write an etc/resolv.conf and expect it to not be modified
3212 resolvconf = os.path.join(render_dir, 'etc/resolv.conf')
3213 resolvconf_content = "# Original Content"
3214 util.write_file(resolvconf, resolvconf_content)
3205 renderer = self._get_renderer()3215 renderer = self._get_renderer()
3206 renderer.render_network_state(ns, target=render_dir)3216 renderer.render_network_state(ns, target=render_dir)
3207 found = dir2dict(render_dir)3217 found = dir2dict(render_dir)
@@ -3219,6 +3229,8 @@ TYPE=Ethernet
3219USERCTL=no3229USERCTL=no
3220"""3230"""
3221 self.assertEqual(expected, found[nspath + 'ifcfg-eth0'])3231 self.assertEqual(expected, found[nspath + 'ifcfg-eth0'])
3232 # a dhcp only config should not modify resolv.conf
3233 self.assertEqual(resolvconf_content, found['/etc/resolv.conf'])
32223234
3223 def test_bond_config(self):3235 def test_bond_config(self):
3224 expected_name = 'expected_sysconfig_opensuse'3236 expected_name = 'expected_sysconfig_opensuse'

Subscribers

People subscribed via source and target branches