Assorted nxos_bgp_* fixes (#25080)

* Simplify apply_key_map

* Fix nxapi

* Clean up get_value

* Fix missing non-values

* Add test for existing bgp_af case

* Fix small issues with bgp_neighbor_af
This commit is contained in:
Nathaniel Case 2017-05-30 14:11:15 -04:00 committed by GitHub
parent a4131197e0
commit 53837c2ab0
5 changed files with 91 additions and 134 deletions

View file

@ -334,85 +334,52 @@ DAMPENING_PARAMS = [
] ]
def get_custom_list_value(config, arg, module): def get_value(arg, config, module):
value_list = [] command = PARAM_TO_COMMAND_KEYMAP[arg]
splitted_config = config.splitlines() command_val_re = re.compile(r'(?:{0}\s)(?P<value>.*)$'.format(command), re.M)
if arg == 'inject_map': has_command_val = command_val_re.search(config)
REGEX_INJECT = r'.*inject-map\s(?P<inject_map>\S+)\sexist-map\s(?P<exist_map>\S+)-*'
for line in splitted_config: if arg == 'inject_map':
value = [] inject_re = r'.*inject-map\s(?P<inject_map>\S+)\sexist-map\s(?P<exist_map>\S+)-*'
inject_group = {}
try: value = []
match_inject = re.match(REGEX_INJECT, line, re.DOTALL) match_inject = re.match(inject_re, config, re.DOTALL)
inject_group = match_inject.groupdict() if match_inject:
inject_map = inject_group['inject_map'] inject_group = match_inject.groupdict()
exist_map = inject_group['exist_map'] inject_map = inject_group['inject_map']
value.append(inject_map) exist_map = inject_group['exist_map']
value.append(exist_map) value.append(inject_map)
except AttributeError: value.append(exist_map)
value = []
inject_map_command = ('inject-map {0} exist-map {1} '
'copy-attributes'.format(
inject_group['inject_map'],
inject_group['exist_map']))
inject_re = re.compile(r'\s+{0}\s*$'.format(inject_map_command), re.M)
if inject_re.search(config):
value.append('copy_attributes')
elif arg in ['networks', 'redistribute']:
value = []
if has_command_val:
value = has_command_val.group('value').split()
if value: if value:
copy_attributes = False if len(value) == 3:
inject_map_command = ('inject-map {0} exist-map {1} ' value.pop(1)
'copy-attributes'.format( elif arg == 'redistribute' and len(value) == 4:
inject_group['inject_map'], value = ['{0} {1}'.format(
inject_group['exist_map'])) value[0], value[1]), value[3]]
REGEX = re.compile(r'\s+{0}\s*$'.format(inject_map_command), re.M) elif command == 'distance':
try: distance_re = r'.*distance\s(?P<d_ebgp>\w+)\s(?P<d_ibgp>\w+)\s(?P<d_local>\w+)'
if REGEX.search(config): match_distance = re.match(distance_re, config, re.DOTALL)
copy_attributes = True
except TypeError:
copy_attributes = False
if copy_attributes: value = ''
value.append('copy_attributes') if match_distance:
value_list.append(value)
elif arg == 'networks':
REGEX_NETWORK = re.compile(r'(?:network\s)(?P<value>.*)$')
for line in splitted_config:
value = []
if 'network' in line:
value = REGEX_NETWORK.search(line).group('value').split()
if value:
if len(value) == 3:
value.pop(1)
value_list.append(value)
elif arg == 'redistribute':
RED_REGEX = re.compile(r'(?:{0}\s)(?P<value>.*)$'.format(
PARAM_TO_COMMAND_KEYMAP[arg]), re.M)
for line in splitted_config:
value = []
if 'redistribute' in line:
value = RED_REGEX.search(line).group('value').split()
if value:
if len(value) == 3:
value.pop(1)
elif len(value) == 4:
value = ['{0} {1}'.format(
value[0], value[1]), value[3]]
value_list.append(value)
return value_list
def get_custom_string_value(config, arg, module):
value = ''
if arg.startswith('distance'):
REGEX_DISTANCE = ('.*distance\s(?P<d_ebgp>\w+)\s(?P<d_ibgp>\w+)'
'\s(?P<d_local>\w+)')
try:
match_distance = re.match(REGEX_DISTANCE, config, re.DOTALL)
distance_group = match_distance.groupdict() distance_group = match_distance.groupdict()
except AttributeError:
distance_group = {}
if distance_group:
if arg == 'distance_ebgp': if arg == 'distance_ebgp':
value = distance_group['d_ebgp'] value = distance_group['d_ebgp']
elif arg == 'distance_ibgp': elif arg == 'distance_ibgp':
@ -420,22 +387,17 @@ def get_custom_string_value(config, arg, module):
elif arg == 'distance_local': elif arg == 'distance_local':
value = distance_group['d_local'] value = distance_group['d_local']
elif arg.startswith('dampening'): elif command.split()[0] == 'dampening':
REGEX = re.compile(r'(?:{0}\s)(?P<value>.*)$'.format( value = ''
PARAM_TO_COMMAND_KEYMAP[arg]), re.M)
if arg == 'dampen_igp_metric' or arg == 'dampening_routemap': if arg == 'dampen_igp_metric' or arg == 'dampening_routemap':
value = '' if command in config:
if PARAM_TO_COMMAND_KEYMAP[arg] in config: value = has_command_val.group('value')
value = REGEX.search(config).group('value')
else: else:
REGEX_DAMPENING = r'.*dampening\s(?P<half>\w+)\s(?P<reuse>\w+)\s(?P<suppress>\w+)\s(?P<max_suppress>\w+)' dampening_re = r'.*dampening\s(?P<half>\w+)\s(?P<reuse>\w+)\s(?P<suppress>\w+)\s(?P<max_suppress>\w+)'
try: match_dampening = re.match(dampening_re, config, re.DOTALL)
match_dampening = re.match(REGEX_DAMPENING, config, re.DOTALL) if match_dampening:
dampening_group = match_dampening.groupdict() dampening_group = match_dampening.groupdict()
except AttributeError:
dampening_group = {}
if dampening_group:
if arg == 'dampening_half_time': if arg == 'dampening_half_time':
value = dampening_group['half'] value = dampening_group['half']
elif arg == 'dampening_reuse_time': elif arg == 'dampening_reuse_time':
@ -446,34 +408,17 @@ def get_custom_string_value(config, arg, module):
value = dampening_group['max_suppress'] value = dampening_group['max_suppress']
elif arg == 'table_map_filter': elif arg == 'table_map_filter':
TMF_REGEX = re.compile(r'\s+table-map.*filter$', re.M) tmf_regex = re.compile(r'\s+table-map.*filter$', re.M)
value = False value = False
try: if tmf_regex.search(config):
if TMF_REGEX.search(config): value = True
value = True
except TypeError:
value = False
elif arg == 'table_map': elif arg == 'table_map':
TM_REGEX = re.compile(r'(?:table-map\s)(?P<value>\S+)(\sfilter)?$', re.M) tm_regex = re.compile(r'(?:table-map\s)(?P<value>\S+)(\sfilter)?$', re.M)
has_tablemap = tm_regex.search(config)
value = '' value = ''
if PARAM_TO_COMMAND_KEYMAP[arg] in config: if has_tablemap:
value = TM_REGEX.search(config).group('value') value = has_tablemap.group('value')
return value
def get_value(arg, config, module):
custom = [
'inject_map',
'networks',
'redistribute'
]
if arg in custom:
value = get_custom_list_value(config, arg, module)
elif (arg.startswith('distance') or arg.startswith('dampening') or
arg.startswith('table_map')):
value = get_custom_string_value(config, arg, module)
elif arg in BOOL_PARAMS: elif arg in BOOL_PARAMS:
command_re = re.compile(r'\s+{0}\s*'.format(command), re.M) command_re = re.compile(r'\s+{0}\s*'.format(command), re.M)
@ -483,12 +428,10 @@ def get_value(arg, config, module):
value = True value = True
else: else:
command_val_re = re.compile(r'(?:{0}\s)(?P<value>.*)$'.format(PARAM_TO_COMMAND_KEYMAP[arg]), re.M)
value = '' value = ''
has_command = command_val_re.search(config) if has_command_val:
if has_command: value = has_command_val.group('value')
value = has_command.group('value')
return value return value
@ -526,10 +469,10 @@ def get_existing(module, args, warnings):
def apply_key_map(key_map, table): def apply_key_map(key_map, table):
new_dict = {} new_dict = {}
for key in table: for key, value in table.items():
new_key = key_map.get(key) new_key = key_map.get(key)
if new_key: if new_key:
new_dict[new_key] = table.get(key) new_dict[new_key] = value
return new_dict return new_dict
@ -741,7 +684,7 @@ def state_present(module, existing, proposed, candidate):
candidate.add(commands, parents=parents) candidate.add(commands, parents=parents)
def state_absent(module, existing, proposed, candidate): def state_absent(module, candidate):
commands = [] commands = []
parents = ["router bgp {0}".format(module.params['asn'])] parents = ["router bgp {0}".format(module.params['asn'])]
if module.params['vrf'] != 'default': if module.params['vrf'] != 'default':
@ -830,12 +773,10 @@ def main():
proposed_args = dict((k, v) for k, v in module.params.items() proposed_args = dict((k, v) for k, v in module.params.items()
if v is not None and k in args) if v is not None and k in args)
if proposed_args.get('networks'): for arg in ['networks', 'inject_map']:
if proposed_args['networks'][0] == 'default': if proposed_args.get(arg):
proposed_args['networks'] = 'default' if proposed_args[arg][0] == 'default':
if proposed_args.get('inject_map'): proposed_args[arg] = 'default'
if proposed_args['inject_map'][0] == 'default':
proposed_args['inject_map'] = 'default'
proposed = {} proposed = {}
for key, value in proposed_args.items(): for key, value in proposed_args.items():
@ -849,12 +790,13 @@ def main():
if state == 'present': if state == 'present':
state_present(module, existing, proposed, candidate) state_present(module, existing, proposed, candidate)
elif state == 'absent' and existing: elif state == 'absent' and existing:
state_absent(module, existing, proposed, candidate) state_absent(module, candidate)
if candidate: if candidate:
candidate = candidate.items_text()
load_config(module, candidate) load_config(module, candidate)
result['changed'] = True result['changed'] = True
result['commands'] = candidate.items_text() result['commands'] = candidate
else: else:
result['commands'] = [] result['commands'] = []

View file

@ -352,7 +352,8 @@ def get_value(arg, config, module):
] ]
command = PARAM_TO_COMMAND_KEYMAP[arg] command = PARAM_TO_COMMAND_KEYMAP[arg]
has_command = re.search(r'\s+{0}\s*'.format(command), config, re.M) has_command = re.search(r'\s+{0}\s*'.format(command), config, re.M)
has_command_val = command_val_re.search(r'(?:{0}\s)(?P<value>.*)$'.format(command), config, re.M) has_command_val = re.search(r'(?:{0}\s)(?P<value>.*)$'.format(command), config, re.M)
value = ''
if arg in custom: if arg in custom:
value = get_custom_value(arg, config, module) value = get_custom_value(arg, config, module)
@ -363,7 +364,6 @@ def get_value(arg, config, module):
value = True value = True
elif command.split()[0] in ['filter-list', 'prefix-list', 'route-map']: elif command.split()[0] in ['filter-list', 'prefix-list', 'route-map']:
value = ''
direction = arg.rsplit('_', 1)[1] direction = arg.rsplit('_', 1)[1]
if has_command_val: if has_command_val:
params = has_command_val.group('value').split() params = has_command_val.group('value').split()
@ -376,11 +376,8 @@ def get_value(arg, config, module):
if has_command_val: if has_command_val:
value = has_command_val.group('value') value = has_command_val.group('value')
else: elif has_command_val:
value = '' value = has_command_val.group('value')
if has_command_val:
value = has_command_val.group('value')
return value return value
@ -747,7 +744,7 @@ def main():
if state == 'present': if state == 'present':
state_present(module, existing, proposed, candidate) state_present(module, existing, proposed, candidate)
elif state == 'absent' and existing: elif state == 'absent' and existing:
state_absent(module, existing, proposed, candidate) state_absent(module, existing, candidate)
if candidate: if candidate:
candidate = candidate.items_text() candidate = candidate.items_text()

View file

@ -5,4 +5,7 @@ router bgp 65535
event-history cli size medium event-history cli size medium
event-history detail event-history detail
vrf test2 vrf test2
address-family ipv4 unicast
timers bgp 1 10 timers bgp 1 10
neighbor 3.3.3.5
address-family ipv4 unicast

View file

@ -48,17 +48,21 @@ class TestNxosBgpAfModule(TestNxosModule):
def test_nxos_bgp_af(self): def test_nxos_bgp_af(self):
set_module_args(dict(asn=65535, afi='ipv4', safi='unicast')) set_module_args(dict(asn=65535, afi='ipv4', safi='unicast'))
self.execute_module( self.execute_module(
changed=True, changed=True, sort=False,
commands=['router bgp 65535', 'address-family ipv4 unicast'] commands=['router bgp 65535', 'address-family ipv4 unicast']
) )
def test_nxos_bgp_af_vrf(self): def test_nxos_bgp_af_vrf(self):
set_module_args(dict(asn=65535, vrf='test', afi='ipv4', safi='unicast')) set_module_args(dict(asn=65535, vrf='test', afi='ipv4', safi='unicast'))
self.execute_module( self.execute_module(
changed=True, changed=True, sort=False,
commands=['router bgp 65535', 'vrf test', 'address-family ipv4 unicast'] commands=['router bgp 65535', 'vrf test', 'address-family ipv4 unicast']
) )
def test_nxos_bgp_af_vrf_exists(self):
set_module_args(dict(asn=65535, vrf='test2', afi='ipv4', safi='unicast'))
self.execute_module(changed=False, commands=[])
def test_nxos_bgp_af_dampening_routemap(self): def test_nxos_bgp_af_dampening_routemap(self):
set_module_args(dict(asn=65535, afi='ipv4', safi='unicast', set_module_args(dict(asn=65535, afi='ipv4', safi='unicast',
dampening_routemap='route-map-a')) dampening_routemap='route-map-a'))

View file

@ -53,3 +53,14 @@ class TestNxosBgpNeighborAfModule(TestNxosModule):
'router bgp 65535', 'neighbor 3.3.3.3', 'address-family ipv4 unicast', 'router bgp 65535', 'neighbor 3.3.3.3', 'address-family ipv4 unicast',
'route-reflector-client' 'route-reflector-client'
]) ])
def test_nxos_bgp_neighbor_af_exists(self):
set_module_args(dict(asn=65535, neighbor='3.3.3.5', afi='ipv4', safi='unicast'))
self.execute_module(changed=False, commands=[])
def test_nxos_bgp_neighbor_af_absent(self):
set_module_args(dict(asn=65535, neighbor='3.3.3.5', afi='ipv4', safi='unicast', state='absent'))
self.execute_module(
changed=True, sort=False,
commands=['router bgp 65535', 'neighbor 3.3.3.5', 'no address-family ipv4 unicast']
)