diff options
Diffstat (limited to 'src/helpers')
-rwxr-xr-x | src/helpers/config_dependency.py | 79 | ||||
-rwxr-xr-x | src/helpers/vyos-save-config.py | 19 |
2 files changed, 84 insertions, 14 deletions
diff --git a/src/helpers/config_dependency.py b/src/helpers/config_dependency.py index 50c72956e..817bcc65a 100755 --- a/src/helpers/config_dependency.py +++ b/src/helpers/config_dependency.py @@ -18,22 +18,75 @@ import os import sys +import json from argparse import ArgumentParser from argparse import ArgumentTypeError - -try: - from vyos.configdep import check_dependency_graph - from vyos.defaults import directories -except ImportError: - # allow running during addon package build - _here = os.path.dirname(__file__) - sys.path.append(os.path.join(_here, '../../python/vyos')) - from configdep import check_dependency_graph - from defaults import directories +from graphlib import TopologicalSorter, CycleError # addon packages will need to specify the dependency directory -dependency_dir = os.path.join(directories['data'], - 'config-mode-dependencies') +data_dir = '/usr/share/vyos/' +dependency_dir = os.path.join(data_dir, 'config-mode-dependencies') + +def dict_merge(source, destination): + from copy import deepcopy + tmp = deepcopy(destination) + + for key, value in source.items(): + if key not in tmp: + tmp[key] = value + elif isinstance(source[key], dict): + tmp[key] = dict_merge(source[key], tmp[key]) + + return tmp + +def read_dependency_dict(dependency_dir: str = dependency_dir) -> dict: + res = {} + for dep_file in os.listdir(dependency_dir): + if not dep_file.endswith('.json'): + continue + path = os.path.join(dependency_dir, dep_file) + with open(path) as f: + d = json.load(f) + if dep_file == 'vyos-1x.json': + res = dict_merge(res, d) + else: + res = dict_merge(d, res) + + return res + +def graph_from_dependency_dict(d: dict) -> dict: + g = {} + for k in list(d): + g[k] = set() + # add the dependencies for every sub-case; should there be cases + # that are mutally exclusive in the future, the graphs will be + # distinguished + for el in list(d[k]): + g[k] |= set(d[k][el]) + + return g + +def is_acyclic(d: dict) -> bool: + g = graph_from_dependency_dict(d) + ts = TopologicalSorter(g) + try: + # get node iterator + order = ts.static_order() + # try iteration + _ = [*order] + except CycleError: + return False + + return True + +def check_dependency_graph(dependency_dir: str = dependency_dir, + supplement: str = None) -> bool: + d = read_dependency_dict(dependency_dir=dependency_dir) + if supplement is not None: + with open(supplement) as f: + d = dict_merge(json.load(f), d) + + return is_acyclic(d) def path_exists(s): if not os.path.exists(s): @@ -50,8 +103,10 @@ def main(): args = vars(parser.parse_args()) if not check_dependency_graph(**args): + print("dependency error: cycle exists") sys.exit(1) + print("dependency graph acyclic") sys.exit(0) if __name__ == '__main__': diff --git a/src/helpers/vyos-save-config.py b/src/helpers/vyos-save-config.py index 8af4a7916..518bd9864 100755 --- a/src/helpers/vyos-save-config.py +++ b/src/helpers/vyos-save-config.py @@ -19,6 +19,7 @@ import os import re import sys from tempfile import NamedTemporaryFile +from argparse import ArgumentParser from vyos.config import Config from vyos.remote import urlc @@ -28,8 +29,15 @@ from vyos.defaults import directories DEFAULT_CONFIG_PATH = os.path.join(directories['config'], 'config.boot') remote_save = None -if len(sys.argv) > 1: - save_file = sys.argv[1] +parser = ArgumentParser(description='Save configuration') +parser.add_argument('file', type=str, nargs='?', help='Save configuration to file') +parser.add_argument('--write-json-file', type=str, help='Save JSON of configuration to file') +args = parser.parse_args() +file = args.file +json_file = args.write_json_file + +if file is not None: + save_file = file else: save_file = DEFAULT_CONFIG_PATH @@ -51,6 +59,13 @@ with open(write_file, 'w') as f: f.write("\n") f.write(system_footer()) +if json_file is not None and ct is not None: + try: + with open(json_file, 'w') as f: + f.write(ct.to_json()) + except OSError as e: + print(f'failed to write JSON file: {e}') + if remote_save is not None: try: remote_save.upload(write_file) |