From 479c7201b61d674e54e2ee7c347cd90fc0aaf1d3 Mon Sep 17 00:00:00 2001 From: Adam Collard Date: Fri, 8 Apr 2022 20:20:18 +0100 Subject: [PATCH 8/8] util: atomically update sym links to avoid Suppress FileNotFoundError when reading status (#1298) Reference:https://github.com/canonical/cloud-init/commit/0450a1faff9e5095e6da0865916501772b3972e9 Conflict:change tests/unittests/test_util.py not cloudinit/tests/test_util.py. Atomically update the desired link file from a temporary file when a stale link already exists. This avoids FileNotFound errors due to races with cloud-init status --wait when the symlink /run/cloud-init/status.json already exists. LP:1962150 --- cloudinit/tests/test_util.py | 5 ++++- cloudinit/util.py | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cloudinit/tests/test_util.py b/cloudinit/tests/test_util.py index 671b8bc..5fb2508 100644 --- a/cloudinit/tests/test_util.py +++ b/cloudinit/tests/test_util.py @@ -328,13 +328,16 @@ class TestSymlink(CiTestCase): tmpd = self.tmp_dir() link = self.tmp_path("link", tmpd) target = self.tmp_path("target", tmpd) + target2 = self.tmp_path("target2", tmpd) util.write_file(target, "hello") + util.write_file(target2, "hello2") util.sym_link(target, link) self.assertTrue(os.path.exists(link)) - util.sym_link(target, link, force=True) + util.sym_link(target2, link, force=True) self.assertTrue(os.path.exists(link)) + self.assertEqual("hello2", util.load_file(link)) def test_sym_link_dangling_link(self): tmpd = self.tmp_dir() diff --git a/cloudinit/util.py b/cloudinit/util.py index d5e8277..0e0fc04 100644 --- a/cloudinit/util.py +++ b/cloudinit/util.py @@ -1797,7 +1797,12 @@ def is_link(path): def sym_link(source, link, force=False): LOG.debug("Creating symbolic link from %r => %r", link, source) if force and os.path.lexists(link): - del_file(link) + # Provide atomic update of symlink to avoid races with status --wait + # LP: #1962150 + tmp_link = os.path.join(os.path.dirname(link), "tmp" + rand_str(8)) + os.symlink(source, tmp_link) + os.replace(tmp_link, link) + return os.symlink(source, link) -- 2.40.0