From 1a0ccb22b74757d597dc388a062c3a52017ac072 Mon Sep 17 00:00:00 2001 From: "Peter J. Holzer" Date: Wed, 20 Sep 2023 10:50:29 +0200 Subject: [PATCH] Avoid race condition during config update --- app.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/app.py b/app.py index a8a184a..e4dae99 100644 --- a/app.py +++ b/app.py @@ -97,8 +97,9 @@ def verify_node(d): if "/" in node: raise ValueError("invalid node name %s", node) try: - log.info("getting client config from %s", "config/" + node) - with open("config/" + node) as fh: + fn = "config/" + node + log.info("getting client config from %s", fn) + with open(fn) as fh: node_conf = json.load(fh) except Exception as e: log.warning("got %s opening %s", e, "config/" + node) @@ -112,8 +113,19 @@ def verify_node(d): if timestamp > node_conf["last"]: node_conf["last"] = timestamp os.replace("config/" + node, "config/" + node + ".old") - with open("config/" + node, "w") as fh: + tmpfn = fn + "." + str(os.getpid()) + oldfn = fn + ".old" + with open(tmpfn, "w") as fh: json.dump(node_conf, fh) # XXX + try: + os.unlink(oldfn) + except FileNotFoundError: + pass + try: + os.link(fn, oldfn) + except FileNotFoundError: + pass + os.rename(tmpfn, fn) return node else: abort(409, "timestamp out of sync")