summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/vyos/config_mgmt.py70
1 files changed, 67 insertions, 3 deletions
diff --git a/python/vyos/config_mgmt.py b/python/vyos/config_mgmt.py
index 06cfb3d78..d75122ddb 100644
--- a/python/vyos/config_mgmt.py
+++ b/python/vyos/config_mgmt.py
@@ -27,6 +27,7 @@ from textwrap import dedent
from pathlib import Path
from shutil import copy, chown
from subprocess import Popen
+from subprocess import PIPE
from subprocess import DEVNULL
from urllib.parse import urlsplit
from urllib.parse import urlunsplit
@@ -45,11 +46,14 @@ from vyos.version import get_full_version_data
from vyos.utils.io import ask_yes_no
from vyos.utils.io import catch_broken_pipe
from vyos.utils.boot import boot_configuration_complete
+from vyos.utils.backend import vyconf_backend
from vyos.utils.process import is_systemd_service_active
from vyos.utils.process import rc_cmd
from vyos.defaults import DEFAULT_COMMIT_CONFIRM_MINUTES
from vyos.component_version import append_system_version
+from vyos.component_version import add_system_version_string
from vyos.utils.file import file_compare
+from vyos.utils.file import write_file
SAVE_CONFIG = '/usr/libexec/vyos/vyos-save-config.py'
config_json = '/run/vyatta/config/config.json'
@@ -625,7 +629,7 @@ Proceed ?"""
cmp_saved = f'/tmp/config.boot.{ext}'
if boot_configuration_complete():
- save_config(cmp_saved, json_out=config_json)
+ self._save_active_config(cmp_saved)
else:
copy(config_file, cmp_saved)
@@ -657,6 +661,26 @@ Proceed ?"""
return True
+ def _save_active_config(self, target):
+ """Write the active config and its JSON the way vyos-save-config.py
+ does, from the tree this object already holds: running that script
+ built a second full Config() for the same content."""
+ ct = self.active_config
+ if ct is None:
+ save_config(target, json_out=config_json)
+ return
+ try:
+ write_file(target, add_system_version_string(ct.to_string()))
+ except OSError as e:
+ # as save_config() does when vyos-save-config.py fails
+ logger.critical(f'save config failed: {e}')
+ return
+ try:
+ with open(config_json, 'w') as f:
+ f.write(ct.to_json())
+ except OSError as e:
+ logger.warning(f'cannot write {config_json}: {e}')
+
@staticmethod
def _update_archive():
cmd = f'sudo logrotate -f -s {logrotate_state} {logrotate_conf}'
@@ -802,16 +826,54 @@ Proceed ?"""
os.umask(mask)
+def _committed_config():
+ """Config for the post-commit hooks.
+
+ The hooks run after the commit has written the active config, so the
+ working config is the same tree. Read it once, from the active store.
+ Config() reads it twice, and its working-config read goes through the
+ session's unionfs-fuse, which takes seconds on a large config.
+ """
+ from vyos.configsource import ConfigSourceString
+
+ # after a failed or partial commit read the config the stock way (full
+ # Config()): a faster read here lets a scripted discard + set land inside
+ # vyatta-cfg's unionfs-fuse cache window after discard, where the set fails
+ if os.environ.get('COMMIT_STATUS', 'SUCCESS') != 'SUCCESS':
+ return None
+
+ # with the vyconf backend Config() reads the vyconf session, not the
+ # legacy store: keep that path
+ if vyconf_backend() and boot_configuration_complete():
+ return None
+
+ # read stdout only, unmodified, as ConfigSourceSession does
+ p = Popen(['/bin/cli-shell-api', '--show-active-only', '--show-show-defaults',
+ '--show-ignore-edit', 'showConfig'], stdout=PIPE)
+ text = p.communicate()[0].decode()
+ if p.returncode != 0 or not text:
+ return None
+ # as ConfigSourceSession: no running config until the boot config is
+ # loaded, so the boot commit's hooks see no effective values (and do not
+ # upload the archive)
+ running = text if boot_configuration_complete() else ''
+ return Config(config_source=ConfigSourceString(running_config_text=running,
+ session_config_text=text))
+
+
# entry_point for console script
#
@catch_broken_pipe
def run():
from argparse import ArgumentParser, REMAINDER
- config_mgmt = ConfigMgmt()
-
for s in list(commit_hooks):
if sys.argv[0].replace('-', '_').endswith(s):
+ try:
+ config = _committed_config()
+ except Exception: # pylint: disable=broad-exception-caught
+ config = None # ConfigMgmt() falls back to a full Config()
+ config_mgmt = ConfigMgmt(config=config)
func = getattr(config_mgmt, s)
try:
func()
@@ -819,6 +881,8 @@ def run():
print(f'{s}: {e}')
sys.exit(0)
+ config_mgmt = ConfigMgmt()
+
parser = ArgumentParser()
subparsers = parser.add_subparsers(dest='subcommand')