Skip to content

Commit

Permalink
bug(schema): only write network-config if instance dir present (#4635)
Browse files Browse the repository at this point in the history
In Local boot stage (pre-systemnetworking) only write
/var/lib/cloud/instance/network-config.json if the symlink
/v/l/c/instance already exits. This instance symlink is created only
once a datasource is discovered in either Local or Network boot
stage.

This bug affects any environment where the detected datasource is
only discovered in the Network boot stage.
If no viable datasource is detected during the Local boot stage,
cloud-init calls apply_network_config to minimally setup a basic
fallback network config with DHCP on the primary NIC.

In this case, cloud-init will no longer attempt to write the
fallback network-config.json during Local boot. Defer writing the
networ-config.json to Network boot stage once
/var/lib/cloud/instance exists for a detected datasource.

Fixes GH-4630
  • Loading branch information
blackboxsw committed Nov 28, 2023
1 parent 05f039c commit 3fe919f
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 13 deletions.
7 changes: 4 additions & 3 deletions cloudinit/stages.py
Original file line number Diff line number Diff line change
Expand Up @@ -936,8 +936,9 @@ def _find_networking_config(self):
def _apply_netcfg_names(self, netcfg):
ncfg_instance_path = self.paths.get_ipath_cur("network_config")
network_link = self.paths.get_runpath("network_config")
if not self._network_already_configured():
if os.path.islink(self.paths.instance_link):
if os.path.exists(ncfg_instance_path):
# Compare write on delta of current network-config
if netcfg != util.load_json(
util.load_file(ncfg_instance_path)
):
Expand All @@ -948,8 +949,8 @@ def _apply_netcfg_names(self, netcfg):
atomic_helper.write_json(
ncfg_instance_path, netcfg, mode=0o600
)
if not os.path.islink(network_link):
util.sym_link(ncfg_instance_path, network_link)
if not os.path.islink(network_link):
util.sym_link(ncfg_instance_path, network_link)
try:
LOG.debug("applying net config names for %s", netcfg)
self.distro.networking.apply_network_config_names(netcfg)
Expand Down
34 changes: 24 additions & 10 deletions tests/unittests/test_stages.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from cloudinit import sources, stages
from cloudinit.event import EventScope, EventType
from cloudinit.sources import NetworkConfigSource
from cloudinit.util import write_file
from cloudinit.util import sym_link, write_file
from tests.unittests.helpers import mock
from tests.unittests.util import TEST_INSTANCE_ID, FakeDataSource

Expand All @@ -28,7 +28,8 @@ def setup(self, tmpdir):
"paths": {"cloud_dir": self.tmpdir, "run_dir": self.tmpdir},
}
}
tmpdir.mkdir("instance")
tmpdir.mkdir("instance-uuid")
sym_link(tmpdir.join("instance-uuid"), tmpdir.join("instance"))
self.init.datasource = FakeDataSource(paths=self.init.paths)
self._real_is_new_instance = self.init.is_new_instance
self.init.is_new_instance = mock.Mock(return_value=True)
Expand Down Expand Up @@ -393,9 +394,12 @@ def fake_network_config():
assert caplog.records[0].levelname == "INFO"
assert f"network config is disabled by {disable_file}" in caplog.text

@pytest.mark.parametrize("instance_dir_present", (True, False))
@mock.patch("cloudinit.net.get_interfaces_by_mac")
@mock.patch("cloudinit.distros.ubuntu.Distro")
def test_apply_network_on_new_instance(self, m_ubuntu, m_macs):
def test_apply_network_on_new_instance(
self, m_ubuntu, m_macs, instance_dir_present
):
"""Call distro apply_network_config methods on is_new_instance."""
net_cfg = {
"version": 1,
Expand All @@ -415,20 +419,30 @@ def fake_network_config():
m_macs.return_value = {"42:42:42:42:42:42": "eth9"}

self.init._find_networking_config = fake_network_config
if not instance_dir_present:
self.tmpdir.join("instance").remove()
self.tmpdir.join("instance-uuid").remove()

self.init.apply_network_config(True)
networking = self.init.distro.networking
networking.apply_network_config_names.assert_called_with(net_cfg)
self.init.distro.apply_network_config.assert_called_with(
net_cfg, bring_up=True
)
assert net_cfg == json.loads(
self.tmpdir.join("instance/network-config.json").read()
)
assert net_cfg == json.loads(
self.tmpdir.join("network-config.json").read()
)
assert os.path.islink(self.tmpdir.join("network-config.json"))
if instance_dir_present:
assert net_cfg == json.loads(
self.tmpdir.join("instance/network-config.json").read()
)
assert net_cfg == json.loads(
self.tmpdir.join("network-config.json").read()
)
assert os.path.islink(self.tmpdir.join("network-config.json"))
else:
for path in (
"instance/network-config.json",
"network-config.json",
):
assert not self.tmpdir.join(path).exists()

@mock.patch("cloudinit.distros.ubuntu.Distro")
def test_apply_network_on_same_instance_id(self, m_ubuntu, caplog):
Expand Down

0 comments on commit 3fe919f

Please sign in to comment.