diff options
| author | John Estabrook <jestabro@vyos.io> | 2026-05-04 14:35:42 -0500 |
|---|---|---|
| committer | John Estabrook <jestabro@vyos.io> | 2026-05-28 08:31:26 -0500 |
| commit | 4113da576b6f934d0340cb18ae184bb25c1619c0 (patch) | |
| tree | a1e8469da215e2e9b8d69fbdaf3b6e24419f6fd5 /src | |
| parent | 9b6e4c75c8a362afa82c711a4254f38e8986662a (diff) | |
| download | vyos-1x-4113da576b6f934d0340cb18ae184bb25c1619c0.tar.gz vyos-1x-4113da576b6f934d0340cb18ae184bb25c1619c0.zip | |
T8502: add client support for config-sync excluded paths
Diffstat (limited to 'src')
| -rwxr-xr-x | src/helpers/vyos_config_sync.py | 77 |
1 files changed, 60 insertions, 17 deletions
diff --git a/src/helpers/vyos_config_sync.py b/src/helpers/vyos_config_sync.py index f0650c5fc..9e425d7c4 100755 --- a/src/helpers/vyos_config_sync.py +++ b/src/helpers/vyos_config_sync.py @@ -17,6 +17,7 @@ # import os +import sys import json import requests import urllib3 @@ -26,6 +27,9 @@ from typing import Optional, List, Tuple, Dict, Any from vyos.config import Config from vyos.configtree import ConfigTree from vyos.configtree import mask_inclusive +from vyos.configtree import mask_exclusive +from vyos.defaults import config_sync_exclusion_list +from vyos.derivedtree import subtree_from_list_of_partial_paths from vyos.template import bracketize_ipv6 @@ -68,8 +72,9 @@ def post_request( return response - -def retrieve_config(sections: List[list[str]]) -> Tuple[Dict[str, Any], Dict[str, Any]]: +def retrieve_config( + sections: List[list[str]], exclusions: List[list[str]] +) -> Tuple[Dict[str, Any], Dict[str, Any]]: """Retrieves the configuration from the local server. Args: @@ -82,18 +87,32 @@ def retrieve_config(sections: List[list[str]]) -> Tuple[Dict[str, Any], Dict[str - config: The subtree of masked config data, as a dictionary. """ - mask = ConfigTree('') - for section in sections: - mask.set(section) - mask_dict = json.loads(mask.to_json()) - config = Config() config_tree = config.get_config_tree() - masked = mask_inclusive(config_tree, mask) + + # set inclusion mask + mask_in = ConfigTree('') + for section in sections: + mask_in.set(section) + mask_in_str = mask_in.write_internal_string() + + ## set exclusion mask + # pass global settings, read at startup: + exclude_list = exclusions + # read local settings from Config + # ... exclude_list += ... + mask_ex = subtree_from_list_of_partial_paths(config_tree, exclude_list) + mask_ex_str = json.dumps(exclude_list) + + masked = mask_inclusive(config_tree, mask_in) + masked = mask_exclusive(masked, mask_ex) + + mask_dict = {'inclusive': mask_in_str, 'exclusive': mask_ex_str} config_dict = json.loads(masked.to_json()) return mask_dict, config_dict + def set_remote_config( address: str, key: str, @@ -147,14 +166,19 @@ def is_section_revised(section: List[str]) -> bool: return is_node_revised(section) -def config_sync(secondary_address: str, - secondary_key: str, - sections: List[list[str]], - mode: str, - secondary_port: int): +def config_sync( + secondary_address: str, + secondary_key: str, + sections: List[list[str]], + mode: str, + secondary_port: int, + exclusions: List[list[str]], +): """Retrieve a config section from primary router in JSON format and send it to secondary router """ + # pylint: disable=too-many-arguments + if not any(map(is_section_revised, sections)): return @@ -163,7 +187,7 @@ def config_sync(secondary_address: str, ) # Sync sections ("nat", "firewall", etc) - mask_dict, config_dict = retrieve_config(sections) + mask_dict, config_dict = retrieve_config(sections, exclusions) logger.debug( f"Retrieved config for sections '{sections}': {config_dict}") @@ -181,7 +205,19 @@ if __name__ == '__main__': # Read configuration from file if not os.path.exists(CONFIG_FILE): logger.error(f"Post-commit: No config file '{CONFIG_FILE}' exists") - exit(0) + sys.exit() + + try: + with open(config_sync_exclusion_list) as f: + exclude_list = json.load(f) + except FileNotFoundError: + logger.error(f"Exclusion list '{config_sync_exclusion_list}' not found") + sys.exit() + except (json.JSONDecodeError, OSError) as e: + logger.error( + f"Failed to load config-sync exclusion list '{config_sync_exclusion_list}': {e}" + ) + sys.exit() with open(CONFIG_FILE, 'r') as f: config_data = f.read() @@ -198,7 +234,7 @@ if __name__ == '__main__': if not all([mode, secondary_address, secondary_key, sections]): logger.error("Missing required configuration data for config synchronization.") - exit(0) + sys.exit() # Generate list_sections of sections/subsections # [ @@ -212,4 +248,11 @@ if __name__ == '__main__': else: list_sections.append([section]) - config_sync(secondary_address, secondary_key, list_sections, mode, secondary_port) + config_sync( + secondary_address, + secondary_key, + list_sections, + mode, + secondary_port, + exclude_list, + ) |
