From 82193bbcf4a6ae8b661dd30eb627cf1a27593fe9 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 13 Nov 2020 21:50:51 +0100 Subject: isis: T1316: refactor config retrieval and Jinja2 template Make the entire template code more human readable by denesting it, as there can only be one ISIS daemon instance in FRR. --- src/conf_mode/protocols_isis.py | 91 ++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 38 deletions(-) (limited to 'src/conf_mode/protocols_isis.py') diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py index 4ee6b31f6..d5e5b64fb 100755 --- a/src/conf_mode/protocols_isis.py +++ b/src/conf_mode/protocols_isis.py @@ -19,29 +19,33 @@ import os from sys import exit from vyos.config import Config +from vyos.configdict import node_changed from vyos import ConfigError from vyos.util import call from vyos.template import render from vyos.template import render_to_string from vyos import frr from vyos import airbag -from pprint import pprint airbag.enable() config_file = r'/tmp/isis.frr' -default_config_data = { - 'interface': '' -} - -def get_config(): - conf = Config() +def get_config(config=None): + if config: + conf = config + else: + conf = Config() base = ['protocols', 'isis'] - isis = conf.get_config_dict(base, key_mangling=('-', '_')) - if not conf.exists(base): - isis = {} - pprint(isis) + isis = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + + # determine which members have been removed + for instance in isis: + conf.set_level(base + [instance]) + tmp = node_changed(conf, ['interface']) + if tmp: + isis[instance].update({'interface_remove': tmp}) + return isis def verify(isis): @@ -49,32 +53,31 @@ def verify(isis): if not isis: return None - for proc_id, foo_config in isis['isis'].items(): - + for process, isis_config in isis.items(): # If more then one isis process is defined (Frr only supports one) # http://docs.frrouting.org/en/latest/isisd.html#isis-router - if len(isis['isis']) > 1: + if len(isis) > 1: raise ConfigError('Only one isis process can be definded') # If network entity title (net) not defined - if not "net" in foo_config: - raise ConfigError('Define net format iso is mandatory in \"isis {} net"!'.format(proc_id)) + if 'net' not in isis_config: + raise ConfigError('ISIS net format iso is mandatory!') # If interface not set - if not "interface" in foo_config: - raise ConfigError('Define interface is mandatory in \"isis {} interface"!'.format(proc_id)) + if 'interface' not in isis_config: + raise ConfigError('ISIS interface is mandatory!') # If md5 and plaintext-password set at the same time - if 'area_password' in foo_config: - if "md5" in foo_config['area_password'] and "plaintext_password" in foo_config['area_password']: - raise ConfigError('Only one password type should be used in \"isis {} area-password"!'.format(proc_id)) + if 'area_password' in isis_config: + if {'md5', 'plaintext_password'} <= set(isis_config['encryption']): + raise ConfigError('Can not use both md5 and plaintext-password for ISIS area-password!') # If one param from deley set, but not set others - if 'spf_delay_ietf' in foo_config: + if 'spf_delay_ietf' in isis_config: required_timers = ['holddown', 'init_delay', 'long_delay', 'short_delay', 'time_to_learn'] exist_timers = [] for elm_timer in required_timers: - if elm_timer in foo_config['spf_delay_ietf']: + if elm_timer in isis_config['spf_delay_ietf']: exist_timers.append(elm_timer) exist_timers = set(required_timers).difference(set(exist_timers)) @@ -82,14 +85,14 @@ def verify(isis): raise ConfigError('All types of delay must be specified: ' + ', '.join(exist_timers).replace('_', '-')) # If Redistribute set, but level don't set - if 'redistribute' in foo_config: - proc_level = foo_config.get('level','').replace('-','_') - for proto, proto_config in foo_config.get('redistribute', {}).get('ipv4', {}).items(): + if 'redistribute' in isis_config: + proc_level = isis_config.get('level','').replace('-','_') + for proto, proto_config in isis_config.get('redistribute', {}).get('ipv4', {}).items(): if 'level_1' not in proto_config and 'level_2' not in proto_config: - raise ConfigError('Redistribute level-1 or level-2 should be specified in \"protocols isis {} redistribute ipv4 {}\"'.format(proc_id, proto)) + raise ConfigError('Redistribute level-1 or level-2 should be specified in \"protocols isis {} redistribute ipv4 {}\"'.format(process, proto)) for redistribute_level in proto_config.keys(): if proc_level and proc_level != 'level_1_2' and proc_level != redistribute_level: - raise ConfigError('\"protocols isis {0} redistribute ipv4 {2} {3}\" cannot be used with \"protocols isis {0} level {1}\"'.format(proc_id, proc_level, proto, redistribute_level)) + raise ConfigError('\"protocols isis {0} redistribute ipv4 {2} {3}\" cannot be used with \"protocols isis {0} level {1}\"'.format(process, proc_level, proto, redistribute_level)) return None @@ -98,31 +101,43 @@ def generate(isis): isis['new_frr_config'] = '' return None + # only one ISIS process is supported, so we can directly send the first key + # of the config dict + process = list(isis.keys())[0] + isis[process]['process'] = process + + import pprint + pprint.pprint(isis[process]) + # render(config) not needed, its only for debug - render(config_file, 'frr/isis.frr.tmpl', isis) + render(config_file, 'frr/isis.frr.tmpl', isis[process], trim_blocks=True) - isis['new_frr_config'] = render_to_string('frr/isis.frr.tmpl', isis) + isis['new_frr_config'] = render_to_string('frr/isis.frr.tmpl', + isis[process], trim_blocks=True) return None def apply(isis): # Save original configration prior to starting any commit actions - isis['original_config'] = frr.get_configuration(daemon='isisd') - isis['modified_config'] = frr.replace_section(isis['original_config'], isis['new_frr_config'], from_re='router isis .*') + frr_cfg = {} + frr_cfg['original_config'] = frr.get_configuration(daemon='isisd') + frr_cfg['modified_config'] = frr.replace_section(frr_cfg['original_config'], isis['new_frr_config'], from_re='router isis .*') # Debugging print('') print('--------- DEBUGGING ----------') - print(f'Existing config:\n{isis["original_config"]}\n\n') + print(f'Existing config:\n{frr_cfg["original_config"]}\n\n') print(f'Replacement config:\n{isis["new_frr_config"]}\n\n') - print(f'Modified config:\n{isis["modified_config"]}\n\n') + print(f'Modified config:\n{frr_cfg["modified_config"]}\n\n') - # Frr Mark configuration will test for syntax errors and exception out if any syntax errors are detected - frr.mark_configuration(isis['modified_config']) + # FRR mark configuration will test for syntax errors and throws an + # exception if any syntax errors is detected + frr.mark_configuration(frr_cfg['modified_config']) - # Commit the resulting new configuration to frr, this will render an frr.CommitError() Exception on fail - frr.reload_configuration(isis['modified_config'], daemon='isisd') + # Commit resulting configuration to FRR, this will throw CommitError + # on failure + frr.reload_configuration(frr_cfg['modified_config'], daemon='isisd') return None -- cgit v1.2.3