From 67f9cb1cee225806104095a0924fd8f43f23a4e3 Mon Sep 17 00:00:00 2001 From: Oliver Walsh Date: Fri, 7 Aug 2020 16:15:43 +0100 Subject: [PATCH] Ensure tripleo ansible inventory file update is atomic Multiple python-tripleoclient commands can run concurrently and all attempt to update the same inventory file in ~/tripleo-ansible-inventory.yaml. Make the update atomic to ensure the inventory file is always complete/valid. Change-Id: I28628100e1300e789114af420bf3ea0dfe9c0d70 (cherry picked from commit 8e082f45ddfb8f29bd02feb1c9fd1ace4e9ec6dd) --- tripleo_common/inventories.py | 7 +++++-- tripleo_common/inventory.py | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tripleo_common/inventories.py b/tripleo_common/inventories.py index 3151ed7e2..2551e66fb 100644 --- a/tripleo_common/inventories.py +++ b/tripleo_common/inventories.py @@ -16,7 +16,8 @@ # under the License. from collections import OrderedDict -import os.path +import os +import tempfile import yaml @@ -137,8 +138,10 @@ class TripleoInventories(object): if var in inventory: inventory[var]['vars'].update(value) - with open(inventory_file_path, 'w') as inventory_file: + # Atomic update as concurrent tripleoclient commands can call this + with tempfile.NamedTemporaryFile('w', delete=False) as inventory_file: yaml.dump(inventory, inventory_file, TemplateDumper) + os.rename(inventory_file.name, inventory_file_path) def host(self): # Dynamic inventory scripts must return empty json if they don't diff --git a/tripleo_common/inventory.py b/tripleo_common/inventory.py index d5881ef5c..6785a47f4 100644 --- a/tripleo_common/inventory.py +++ b/tripleo_common/inventory.py @@ -17,8 +17,9 @@ from collections import OrderedDict import logging -import os.path +import os import sys +import tempfile import yaml from heatclient.exc import HTTPNotFound @@ -383,5 +384,7 @@ class TripleoInventory(object): if var in inventory: inventory[var]['vars'].update(value) - with open(inventory_file_path, 'w') as inventory_file: + # Atomic update as concurrent tripleoclient commands can call this + with tempfile.NamedTemporaryFile('w', delete=False) as inventory_file: yaml.dump(inventory, inventory_file, TemplateDumper) + os.rename(inventory_file.name, inventory_file_path)