diff options
| author | Daniil Baturin <daniil@vyos.io> | 2025-08-14 15:09:34 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-14 15:09:34 +0100 |
| commit | 4c8f5f0e0b7ab090e7bbba1c73f1dc17b5311a55 (patch) | |
| tree | 66e6a2f4f47304ba5db6d670f51621d380ddc073 /python | |
| parent | 471441d9d6541401c5236399da0b7a56a7dd0ead (diff) | |
| parent | c140f827f3117609908a3a18034027d3d78149ac (diff) | |
| download | vyos-1x-4c8f5f0e0b7ab090e7bbba1c73f1dc17b5311a55.tar.gz vyos-1x-4c8f5f0e0b7ab090e7bbba1c73f1dc17b5311a55.zip | |
Merge pull request #4657 from jestabro/sync-config-on-save
T7709: add explicit sync and atomic write on config file save
Diffstat (limited to 'python')
| -rw-r--r-- | python/vyos/component_version.py | 10 | ||||
| -rw-r--r-- | python/vyos/utils/file.py | 36 |
2 files changed, 46 insertions, 0 deletions
diff --git a/python/vyos/component_version.py b/python/vyos/component_version.py index 136bd36e8..13fb8333f 100644 --- a/python/vyos/component_version.py +++ b/python/vyos/component_version.py @@ -209,6 +209,16 @@ def version_info_prune_component(x: VersionInfo, y: VersionInfo) -> VersionInfo: x.component = {k: v for k, v in x.component.items() if k in y.component} +def add_system_version_string(config_str: str = None) -> str: + """Wrap config string with system version and return string.""" + version_info = version_info_from_system() + if config_str is not None: + version_info.update_config_body(config_str) + version_info.update_footer() + + return version_info.write_string() + + def add_system_version(config_str: str = None, out_file: str = None): """Wrap config string with system version and write to out_file. diff --git a/python/vyos/utils/file.py b/python/vyos/utils/file.py index 1e2de2b39..c363b5bdc 100644 --- a/python/vyos/utils/file.py +++ b/python/vyos/utils/file.py @@ -14,6 +14,9 @@ # License along with this library. If not, see <http://www.gnu.org/licenses/>. import os +import tempfile +from contextlib import contextmanager + from vyos.utils.permission import chown def makedir(path, user=None, group=None): @@ -185,3 +188,36 @@ def wait_for_file_write_complete(file_path, pre_hook=None, timeout=None, sleep_i """ Waits for a process to close a file after opening it in write mode. """ wait_for_inotify(file_path, event_type='IN_CLOSE_WRITE', pre_hook=pre_hook, timeout=timeout, sleep_interval=sleep_interval) + +def copy_chown(source, target): + import shutil + import stat + + shutil.copy2(source, target) + st = os.stat(source) + os.chown(target, st[stat.ST_UID], st[stat.ST_GID]) + + +@contextmanager +def write_file_atomic(file_path, mode='w'): + with open(file_path, mode) as _: + pass + temp_file = tempfile.NamedTemporaryFile( + delete=False, dir=os.path.dirname(file_path) + ) + if os.path.exists(file_path): + copy_chown(file_path, temp_file.name) + + file = open(temp_file.name, mode) + try: + yield file + finally: + file.flush() + os.fsync(file.fileno()) + file.close() + os.replace(temp_file.name, file_path) + if os.path.exists(temp_file.name): + try: + os.unlink(temp_file.name) + except Exception: + pass |
