From 456abc2aa4ae10981c2aec2d2e6d975ef30fb8d6 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Tue, 28 May 2019 14:39:39 -0500 Subject: T1397: Rewrite the config merge script Add the script vyos-merge-config.py to separate the merge function from the config load script and remove dependency on XorpConfigParser. --- src/helpers/vyos-merge-config.py | 96 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100755 src/helpers/vyos-merge-config.py (limited to 'src/helpers/vyos-merge-config.py') diff --git a/src/helpers/vyos-merge-config.py b/src/helpers/vyos-merge-config.py new file mode 100755 index 000000000..f0d5d1595 --- /dev/null +++ b/src/helpers/vyos-merge-config.py @@ -0,0 +1,96 @@ +#!/usr/bin/python3 + +# Copyright 2019 VyOS maintainers and contributors +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see . + +import sys +import os +import subprocess +import vyos.defaults +import vyos.remote +from vyos.config import Config +from vyos.configtree import ConfigTree + + +if (len(sys.argv) < 2): + print("Need config file name to merge.") + print("Usage: merge [config path]") + sys.exit(0) + +file_name = sys.argv[1] + +configdir = vyos.defaults.directories['config'] + +protocols = ['scp', 'sftp', 'http', 'https', 'ftp', 'tftp'] + +if any(x in file_name for x in protocols): + config_file = vyos.remote.get_remote_config(file_name) + if not config_file: + sys.exit("No config file by that name.") +else: + canonical_path = "{0}/{1}".format(configdir, file_name) + first_err = None + try: + with open(canonical_path, 'r') as f: + config_file = f.read() + except Exception as err: + first_err = err + try: + with open(file_name, 'r') as f: + config_file = f.read() + except Exception as err: + print(first_err) + print(err) + sys.exit(1) + +path = None +if (len(sys.argv) > 2): + path = " ".join(sys.argv[2:]) + +merge_config_tree = ConfigTree(config_file) + +effective_config = Config() + +output_effective_config = effective_config.show_config() +effective_config_tree = ConfigTree(output_effective_config) + +effective_cmds = effective_config_tree.to_commands() +merge_cmds = merge_config_tree.to_commands() + +effective_cmd_list = effective_cmds.splitlines() +merge_cmd_list = merge_cmds.splitlines() + +effective_cmd_set = set(effective_cmd_list) +add_cmds = [ cmd for cmd in merge_cmd_list if cmd not in effective_cmd_set ] + +if path: + if not effective_config.exists(path): + print("path {} does not exist in running config; will use " + "root.".format(path)) + else: + add_cmds = [ cmd for cmd in add_cmds if path in cmd ] + +for cmd in add_cmds: + cmd = "/opt/vyatta/sbin/my_" + cmd + + try: + subprocess.check_call(cmd, shell=True) + except subprocess.CalledProcessError as err: + print("Called process error: {}.".format(err)) + +if effective_config.session_changed(): + print("Merge complete. Use 'commit' to make changes effective.") +else: + print("No configuration changes to commit.") -- cgit v1.2.3 From aa88d5192338e2263516de791665f819a00b5c36 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Wed, 12 Jun 2019 11:29:07 -0500 Subject: T1397: escape backslashes in output passed to configtree The ouput of config.show_config (cli-shell-api showConfig) does not escape backslashes, whereas configtree expects escaped backslashes. Values containing unescaped backslashes consequently lead to a parsing error; cf. T1001. --- src/helpers/vyos-merge-config.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/helpers/vyos-merge-config.py') diff --git a/src/helpers/vyos-merge-config.py b/src/helpers/vyos-merge-config.py index f0d5d1595..bb2919de2 100755 --- a/src/helpers/vyos-merge-config.py +++ b/src/helpers/vyos-merge-config.py @@ -64,6 +64,10 @@ merge_config_tree = ConfigTree(config_file) effective_config = Config() output_effective_config = effective_config.show_config() +# showConfig (called by config.show_config() does not escape +# backslashes, which configtree expects; cf. T1001. +output_effective_config = output_effective_config.replace("\\", "\\\\") + effective_config_tree = ConfigTree(output_effective_config) effective_cmds = effective_config_tree.to_commands() -- cgit v1.2.3 From 441f95d499f42f57b3a15d78aec826f794fab59f Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Wed, 12 Jun 2019 12:04:34 -0500 Subject: T1397: use revised migration method --- python/vyos/migrator.py | 2 ++ src/helpers/vyos-merge-config.py | 12 ++++++++++++ 2 files changed, 14 insertions(+) (limited to 'src/helpers/vyos-merge-config.py') diff --git a/python/vyos/migrator.py b/python/vyos/migrator.py index 2d4bc7ffc..59d68f0f7 100644 --- a/python/vyos/migrator.py +++ b/python/vyos/migrator.py @@ -165,6 +165,8 @@ class Migrator(object): self.write_config_file_versions(rev_versions) + def config_changed(self): + return self._changed class VirtualMigrator(Migrator): def __init__(self, config_file, vintage='vyos'): diff --git a/src/helpers/vyos-merge-config.py b/src/helpers/vyos-merge-config.py index bb2919de2..e97a1c08d 100755 --- a/src/helpers/vyos-merge-config.py +++ b/src/helpers/vyos-merge-config.py @@ -18,8 +18,10 @@ import sys import os import subprocess +import tempfile import vyos.defaults import vyos.remote +import vyos.migrator from vyos.config import Config from vyos.configtree import ConfigTree @@ -59,6 +61,16 @@ path = None if (len(sys.argv) > 2): path = " ".join(sys.argv[2:]) +with tempfile.NamedTemporaryFile() as file_to_migrate: + with open(file_to_migrate.name, 'w') as fd: + fd.write(config_file) + + migration = vyos.migrator.Migrator(file_to_migrate.name) + migration.run() + if migration.config_changed(): + with open(file_to_migrate.name, 'r') as fd: + config_file = fd.read() + merge_config_tree = ConfigTree(config_file) effective_config = Config() -- cgit v1.2.3 From bd6f3f6534a93f8a8c64e06967c24d4c3827c517 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Wed, 12 Jun 2019 12:45:00 -0500 Subject: T1397: check for path argument in both effective and merge config The merge config script restores the ability to restrict changes to a specified path. In the initial implementation, the path was checked for validity only with respect to the effective config; fix to allow valid paths from merge config as well. --- src/helpers/vyos-merge-config.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'src/helpers/vyos-merge-config.py') diff --git a/src/helpers/vyos-merge-config.py b/src/helpers/vyos-merge-config.py index e97a1c08d..e9a14ae98 100755 --- a/src/helpers/vyos-merge-config.py +++ b/src/helpers/vyos-merge-config.py @@ -57,10 +57,6 @@ else: print(err) sys.exit(1) -path = None -if (len(sys.argv) > 2): - path = " ".join(sys.argv[2:]) - with tempfile.NamedTemporaryFile() as file_to_migrate: with open(file_to_migrate.name, 'w') as fd: fd.write(config_file) @@ -91,12 +87,19 @@ merge_cmd_list = merge_cmds.splitlines() effective_cmd_set = set(effective_cmd_list) add_cmds = [ cmd for cmd in merge_cmd_list if cmd not in effective_cmd_set ] -if path: - if not effective_config.exists(path): - print("path {} does not exist in running config; will use " - "root.".format(path)) +path = None +if (len(sys.argv) > 2): + path = sys.argv[2:] + if (not effective_config_tree.exists(path) and not + merge_config_tree.exists(path)): + print("path {} does not exist in either effective or merge" + " config; will use root.".format(path)) + path = None else: - add_cmds = [ cmd for cmd in add_cmds if path in cmd ] + path = " ".join(path) + +if path: + add_cmds = [ cmd for cmd in add_cmds if path in cmd ] for cmd in add_cmds: cmd = "/opt/vyatta/sbin/my_" + cmd -- cgit v1.2.3