diff options
-rw-r--r-- | .github/workflows/package-smoketest.yml | 2 | ||||
-rw-r--r-- | data/templates/frr/zebra.route-map.frr.j2 | 6 | ||||
-rw-r--r-- | interface-definitions/system_ip.xml.in | 16 | ||||
-rw-r--r-- | python/vyos/config_mgmt.py | 4 | ||||
-rw-r--r-- | python/vyos/configsession.py | 9 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_system_ip.py | 21 | ||||
-rwxr-xr-x | src/conf_mode/system_ip.py | 5 | ||||
-rw-r--r-- | src/services/api/rest/models.py | 4 | ||||
-rw-r--r-- | src/services/api/rest/routers.py | 14 |
9 files changed, 75 insertions, 6 deletions
diff --git a/.github/workflows/package-smoketest.yml b/.github/workflows/package-smoketest.yml index 5ed764217..8bdcc598d 100644 --- a/.github/workflows/package-smoketest.yml +++ b/.github/workflows/package-smoketest.yml @@ -49,7 +49,7 @@ jobs: - name: Generate ISO version string id: version run: | - echo "build_version=1.5-integration-$(date -u +%Y%m%d%H%M)" >> $GITHUB_OUTPUT + echo "build_version=$(date -u +%Y.%m.%d-%H%M-integration)" >> $GITHUB_OUTPUT - name: Build custom ISO image shell: bash run: | diff --git a/data/templates/frr/zebra.route-map.frr.j2 b/data/templates/frr/zebra.route-map.frr.j2 index 70a810f43..0d6d01930 100644 --- a/data/templates/frr/zebra.route-map.frr.j2 +++ b/data/templates/frr/zebra.route-map.frr.j2 @@ -1,6 +1,12 @@ ! {{ 'no ' if disable_forwarding is vyos_defined }}{{ afi }} forwarding ! +{% if import_table is vyos_defined %} +{% for table_num, table_config in import_table.items() %} +ip import-table {{ table_num }} {{ 'distance ' ~ table_config.distance if table_config.distance is vyos_defined }} {{ 'route-map ' ~ table_config.route_map if table_config.route_map is vyos_defined }} +{% endfor %} +{% endif %} +! {% if nht.no_resolve_via_default is vyos_defined %} no {{ afi }} nht resolve-via-default {% endif %} diff --git a/interface-definitions/system_ip.xml.in b/interface-definitions/system_ip.xml.in index b4b5092fe..f2bb5bd8a 100644 --- a/interface-definitions/system_ip.xml.in +++ b/interface-definitions/system_ip.xml.in @@ -17,6 +17,22 @@ #include <include/arp-ndp-table-size.xml.i> </children> </node> + <tagNode name="import-table"> + <properties> + <help>Routing table for import</help> + <valueHelp> + <format>u32:1-252</format> + <description>Table number</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 1-252"/> + </constraint> + </properties> + <children> + #include <include/static/static-route-distance.xml.i> + #include <include/route-map.xml.i> + </children> + </tagNode> <leafNode name="disable-forwarding"> <properties> <help>Disable IPv4 forwarding on all interfaces</help> diff --git a/python/vyos/config_mgmt.py b/python/vyos/config_mgmt.py index dd8910afb..308eb1cdb 100644 --- a/python/vyos/config_mgmt.py +++ b/python/vyos/config_mgmt.py @@ -151,7 +151,9 @@ class ConfigMgmt: self.num_revisions = 0 self.locations = d.get('commit_archive', {}).get('location', []) self.source_address = d.get('commit_archive', {}).get('source_address', '') - self.reboot_unconfirmed = bool(d.get('commit_confirm') == 'reboot') + self.reboot_unconfirmed = bool( + d.get('commit_confirm', {}).get('action') == 'reboot' + ) self.config_dict = d if config.exists(['system', 'host-name']): diff --git a/python/vyos/configsession.py b/python/vyos/configsession.py index b6394d139..4e0dd23a4 100644 --- a/python/vyos/configsession.py +++ b/python/vyos/configsession.py @@ -36,6 +36,7 @@ DISCARD = '/opt/vyatta/sbin/my_discard' SHOW_CONFIG = ['/bin/cli-shell-api', 'showConfig'] LOAD_CONFIG = ['/bin/cli-shell-api', 'loadFile'] MIGRATE_LOAD_CONFIG = ['/usr/libexec/vyos/vyos-load-config.py'] +MERGE_CONFIG = ['/usr/libexec/vyos/vyos-merge-config.py'] SAVE_CONFIG = ['/usr/libexec/vyos/vyos-save-config.py'] INSTALL_IMAGE = [ '/usr/libexec/vyos/op_mode/image_installer.py', @@ -339,6 +340,14 @@ class ConfigSession(object): return out + def merge_config(self, file_path): + if self._vyconf_session is None: + out = self.__run_command(MERGE_CONFIG + [file_path]) + else: + out, _ = 'unimplemented' + + return out + def save_config(self, file_path): if self._vyconf_session is None: out = self.__run_command(SAVE_CONFIG + [file_path]) diff --git a/smoketest/scripts/cli/test_system_ip.py b/smoketest/scripts/cli/test_system_ip.py index 5b6ef2046..a5d1f7743 100755 --- a/smoketest/scripts/cli/test_system_ip.py +++ b/smoketest/scripts/cli/test_system_ip.py @@ -128,5 +128,26 @@ class TestSystemIP(VyOSUnitTestSHIM.TestCase): frrconfig = self.getFRRconfig('', end='') self.assertNotIn(f'no ip nht resolve-via-default', frrconfig) + def test_system_ip_import_table(self): + table_num = '100' + distance = '200' + route_map_in = 'foo-map-in' + self.cli_set(['policy', 'route-map', route_map_in, 'rule', '10', 'action', 'permit']) + self.cli_set(base_path + ['import-table', table_num, 'distance', distance]) + self.cli_set(base_path + ['import-table', table_num, 'route-map', route_map_in]) + + self.cli_commit() + # Verify CLI config applied to FRR + frrconfig = self.getFRRconfig('', end='') + self.assertIn(f'ip import-table {table_num} distance {distance} route-map {route_map_in}', frrconfig) + + self.cli_delete(['policy', 'route-map', route_map_in]) + + self.cli_delete(base_path + ['import-table']) + self.cli_commit() + # Verify CLI config removed to FRR + frrconfig = self.getFRRconfig('', end='') + self.assertNotIn(f'ip import-table {table_num} distance {distance}', frrconfig) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/system_ip.py b/src/conf_mode/system_ip.py index 7f3796168..7f8b00ceb 100755 --- a/src/conf_mode/system_ip.py +++ b/src/conf_mode/system_ip.py @@ -53,6 +53,11 @@ def verify(config_dict): for protocol, protocol_options in opt['protocol'].items(): if 'route_map' in protocol_options: verify_route_map(protocol_options['route_map'], opt) + + if dict_search('import_table', opt): + for table_num, import_config in opt['import_table'].items(): + if dict_search('route_map', import_config): + verify_route_map(import_config['route_map'], opt) return def generate(config_dict): diff --git a/src/services/api/rest/models.py b/src/services/api/rest/models.py index da60e1220..47c7a65b3 100644 --- a/src/services/api/rest/models.py +++ b/src/services/api/rest/models.py @@ -134,13 +134,15 @@ class RetrieveModel(ApiModel): class ConfigFileModel(ApiModel): op: StrictStr file: StrictStr = None + string: StrictStr = None class Config: json_schema_extra = { 'example': { 'key': 'id_key', - 'op': 'save | load', + 'op': 'save | load | merge', 'file': 'filename', + 'string': 'config_string' } } diff --git a/src/services/api/rest/routers.py b/src/services/api/rest/routers.py index d3df91ef5..4866ec5d8 100644 --- a/src/services/api/rest/routers.py +++ b/src/services/api/rest/routers.py @@ -508,13 +508,21 @@ def config_file_op(data: ConfigFileModel, background_tasks: BackgroundTasks): else: path = '/config/config.boot' msg = session.save_config(path) - elif op == 'load': + elif op in ('load', 'merge'): if data.file: path = data.file + elif data.string: + path = '/tmp/config.file' + with open(path, 'w') as f: + f.write(data.string) else: - return error(400, 'Missing required field "file"') + return error(400, 'Missing required field "file | string"') - session.migrate_and_load_config(path) + match op: + case 'load': + session.migrate_and_load_config(path) + case 'merge': + session.merge_config(path) config = Config(session_env=env) d = get_config_diff(config) |