Reference:fa53c7f4089c7502a8012e17a0d6269f0efc474ebb414c78669cbd94dd576d817e94be0450a1faff
66 lines
2.3 KiB
Diff
66 lines
2.3 KiB
Diff
From 479c7201b61d674e54e2ee7c347cd90fc0aaf1d3 Mon Sep 17 00:00:00 2001
|
|
From: Adam Collard <sparkiegeek@users.noreply.github.com>
|
|
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
|
|
|