Merge ~smoser/cloud-init:bug/1675576-netplan-delete-builtin into cloud-init:master

Proposed by Scott Moser
Status: Merged
Merged at revision: d23543eb206326a53a59d86afba862edbd02c231
Proposed branch: ~smoser/cloud-init:bug/1675576-netplan-delete-builtin
Merge into: cloud-init:master
Diff against target: 162 lines (+106/-1)
2 files modified
cloudinit/net/netplan.py (+40/-0)
tests/unittests/test_net.py (+66/-1)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Ryan Harper Approve
Review via email: mp+321471@code.launchpad.net

Commit message

net: in netplan renderer delete known image-builtin content.

When rendering network configuration to netplan, remove known
"builtin" configurations. The specific example here is Ubuntu Core
that has netplan configuration in etc/netplan/00-snapd-config.yaml.

We also delete the derived files since netplan will have created
these derived files in its generator that runs well before cloud-init.

LP: #1675576

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ryan Harper (raharper) wrote :

Looks good, noted some leftover print statements that likely need removed or converted to LOG.debug()

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

Thanks

review: Approve
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
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/netplan.py b/cloudinit/net/netplan.py
index 7444ae3..825fe83 100644
--- a/cloudinit/net/netplan.py
+++ b/cloudinit/net/netplan.py
@@ -10,6 +10,21 @@ from cloudinit import log as logging
10from cloudinit import util10from cloudinit import util
11from cloudinit.net import SYS_CLASS_NET, get_devicelist11from cloudinit.net import SYS_CLASS_NET, get_devicelist
1212
13KNOWN_SNAPD_CONFIG = b"""\
14# This is the initial network config.
15# It can be overwritten by cloud-init or console-conf.
16network:
17 version: 2
18 ethernets:
19 all-en:
20 match:
21 name: "en*"
22 dhcp4: true
23 all-eth:
24 match:
25 name: "eth*"
26 dhcp4: true
27"""
1328
14LOG = logging.getLogger(__name__)29LOG = logging.getLogger(__name__)
15NET_CONFIG_TO_V2 = {30NET_CONFIG_TO_V2 = {
@@ -154,6 +169,28 @@ def _extract_bond_slaves_by_name(interfaces, entry, bond_master):
154 entry.update({'interfaces': bond_slave_names})169 entry.update({'interfaces': bond_slave_names})
155170
156171
172def _clean_default(target=None):
173 # clean out any known default files and derived files in target
174 # LP: #1675576
175 tpath = util.target_path(target, "etc/netplan/00-snapd-config.yaml")
176 if not os.path.isfile(tpath):
177 return
178 content = util.load_file(tpath, decode=False)
179 if content != KNOWN_SNAPD_CONFIG:
180 return
181
182 derived = [util.target_path(target, f) for f in (
183 'run/systemd/network/10-netplan-all-en.network',
184 'run/systemd/network/10-netplan-all-eth.network',
185 'run/systemd/generator/netplan.stamp')]
186 existing = [f for f in derived if os.path.isfile(f)]
187 LOG.debug("removing known config '%s' and derived existing files: %s",
188 tpath, existing)
189
190 for f in [tpath] + existing:
191 os.unlink(f)
192
193
157class Renderer(renderer.Renderer):194class Renderer(renderer.Renderer):
158 """Renders network information in a /etc/netplan/network.yaml format."""195 """Renders network information in a /etc/netplan/network.yaml format."""
159196
@@ -166,6 +203,7 @@ class Renderer(renderer.Renderer):
166 'etc/netplan/50-cloud-init.yaml')203 'etc/netplan/50-cloud-init.yaml')
167 self.netplan_header = config.get('netplan_header', None)204 self.netplan_header = config.get('netplan_header', None)
168 self._postcmds = config.get('postcmds', False)205 self._postcmds = config.get('postcmds', False)
206 self.clean_default = config.get('clean_default', True)
169207
170 def render_network_state(self, target, network_state):208 def render_network_state(self, target, network_state):
171 # check network state for version209 # check network state for version
@@ -182,6 +220,8 @@ class Renderer(renderer.Renderer):
182 header += "\n"220 header += "\n"
183 util.write_file(fpnplan, header + content)221 util.write_file(fpnplan, header + content)
184222
223 if self.clean_default:
224 _clean_default(target=target)
185 self._netplan_generate(run=self._postcmds)225 self._netplan_generate(run=self._postcmds)
186 self._net_setup_link(run=self._postcmds)226 self._net_setup_link(run=self._postcmds)
187227
diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
index 4f07d80..bfd04ba 100644
--- a/tests/unittests/test_net.py
+++ b/tests/unittests/test_net.py
@@ -974,12 +974,14 @@ iface eth0 inet dhcp
974974
975class TestNetplanNetRendering(CiTestCase):975class TestNetplanNetRendering(CiTestCase):
976976
977 @mock.patch("cloudinit.net.netplan._clean_default")
977 @mock.patch("cloudinit.net.sys_dev_path")978 @mock.patch("cloudinit.net.sys_dev_path")
978 @mock.patch("cloudinit.net.read_sys_net")979 @mock.patch("cloudinit.net.read_sys_net")
979 @mock.patch("cloudinit.net.get_devicelist")980 @mock.patch("cloudinit.net.get_devicelist")
980 def test_default_generation(self, mock_get_devicelist,981 def test_default_generation(self, mock_get_devicelist,
981 mock_read_sys_net,982 mock_read_sys_net,
982 mock_sys_dev_path):983 mock_sys_dev_path,
984 mock_clean_default):
983 tmp_dir = self.tmp_dir()985 tmp_dir = self.tmp_dir()
984 _setup_test(tmp_dir, mock_get_devicelist,986 _setup_test(tmp_dir, mock_get_devicelist,
985 mock_read_sys_net, mock_sys_dev_path)987 mock_read_sys_net, mock_sys_dev_path)
@@ -1013,6 +1015,69 @@ network:
1013 set-name: eth10001015 set-name: eth1000
1014"""1016"""
1015 self.assertEqual(expected.lstrip(), contents.lstrip())1017 self.assertEqual(expected.lstrip(), contents.lstrip())
1018 self.assertEqual(1, mock_clean_default.call_count)
1019
1020
1021class TestNetplanCleanDefault(CiTestCase):
1022 snapd_known_path = 'etc/netplan/00-snapd-config.yaml'
1023 snapd_known_content = textwrap.dedent("""\
1024 # This is the initial network config.
1025 # It can be overwritten by cloud-init or console-conf.
1026 network:
1027 version: 2
1028 ethernets:
1029 all-en:
1030 match:
1031 name: "en*"
1032 dhcp4: true
1033 all-eth:
1034 match:
1035 name: "eth*"
1036 dhcp4: true
1037 """)
1038 stub_known = {
1039 'run/systemd/network/10-netplan-all-en.network': 'foo-en',
1040 'run/systemd/network/10-netplan-all-eth.network': 'foo-eth',
1041 'run/systemd/generator/netplan.stamp': 'stamp',
1042 }
1043
1044 def test_clean_known_config_cleaned(self):
1045 content = {self.snapd_known_path: self.snapd_known_content, }
1046 content.update(self.stub_known)
1047 tmpd = self.tmp_dir()
1048 files = sorted(populate_dir(tmpd, content))
1049 netplan._clean_default(target=tmpd)
1050 found = [t for t in files if os.path.exists(t)]
1051 self.assertEqual([], found)
1052
1053 def test_clean_unknown_config_not_cleaned(self):
1054 content = {self.snapd_known_path: self.snapd_known_content, }
1055 content.update(self.stub_known)
1056 content[self.snapd_known_path] += "# user put a comment\n"
1057 tmpd = self.tmp_dir()
1058 files = sorted(populate_dir(tmpd, content))
1059 netplan._clean_default(target=tmpd)
1060 found = [t for t in files if os.path.exists(t)]
1061 self.assertEqual(files, found)
1062
1063 def test_clean_known_config_cleans_only_expected(self):
1064 astamp = "run/systemd/generator/another.stamp"
1065 anet = "run/systemd/network/10-netplan-all-lo.network"
1066 ayaml = "etc/netplan/01-foo-config.yaml"
1067 content = {
1068 self.snapd_known_path: self.snapd_known_content,
1069 astamp: "stamp",
1070 anet: "network",
1071 ayaml: "yaml",
1072 }
1073 content.update(self.stub_known)
1074
1075 tmpd = self.tmp_dir()
1076 files = sorted(populate_dir(tmpd, content))
1077 netplan._clean_default(target=tmpd)
1078 found = [t for t in files if os.path.exists(t)]
1079 expected = [util.target_path(tmpd, f) for f in (astamp, anet, ayaml)]
1080 self.assertEqual(sorted(expected), found)
10161081
10171082
1018class TestNetplanPostcommands(CiTestCase):1083class TestNetplanPostcommands(CiTestCase):

Subscribers

People subscribed via source and target branches