Add aggregate functionality to eos_vrf (#27915)

* Add aggregate functionality to eos_vrf

* Add tests for eos_vrf aggregate option

* Remove test2 and test3 vrfs at the beginning of the eos_vrf tests

* Pull all vrfs

With aggregate, we need to get all VRFs and we then compare with
desired VRFs, instead of assuming it will be just one.
This commit is contained in:
Ricardo Carrillo Cruz 2017-08-10 10:54:13 +02:00 committed by GitHub
parent eee09565b1
commit 7e2169f6d5
2 changed files with 188 additions and 54 deletions

View file

@ -81,100 +81,152 @@ import re
import time
def search_obj_in_list(name, lst):
for o in lst:
if o['name'] == name:
return o
def map_obj_to_commands(updates, module):
commands = list()
want, have = updates
state = module.params['state']
if state == 'absent':
if have:
commands.append('no vrf definition %s' % want['name'])
elif state == 'present':
if not have:
commands.append('vrf definition %s' % want['name'])
for w in want:
name = w['name']
rd = w['rd']
interfaces = w['interfaces']
if want['rd'] is not None:
commands.append('rd %s' % want['rd'])
obj_in_have = search_obj_in_list(name, have)
if want['interfaces']:
for i in want['interfaces']:
commands.append('interface %s' % i)
commands.append('vrf forwarding %s' % want['name'])
else:
if want['rd'] is not None and want['rd'] != have['rd']:
commands.append('vrf definition %s' % want['name'])
commands.append('rd %s' % want['rd'])
if state == 'absent':
if have:
commands.append('no vrf definition %s' % name)
elif state == 'present':
if not obj_in_have:
commands.append('vrf definition %s' % name)
if want['interfaces']:
if not have['interfaces']:
for i in want['interfaces']:
if rd is not None:
commands.append('rd %s' % rd)
if w['interfaces']:
for i in w['interfaces']:
commands.append('interface %s' % i)
commands.append('vrf forwarding %s' % want['name'])
elif set(want['interfaces']) != have['interfaces']:
missing_interfaces = list(set(want['interfaces']) - set(have['interfaces']))
commands.append('vrf forwarding %s' % w['name'])
else:
if w['rd'] is not None and w['rd'] != obj_in_have['rd']:
commands.append('vrf definition %s' % w['name'])
commands.append('rd %s' % w['rd'])
for i in missing_interfaces:
commands.append('interface %s' % i)
commands.append('vrf forwarding %s' % want['name'])
if w['interfaces']:
if not obj_in_have['interfaces']:
for i in w['interfaces']:
commands.append('interface %s' % i)
commands.append('vrf forwarding %s' % w['name'])
elif set(w['interfaces']) != obj_in_have['interfaces']:
missing_interfaces = list(set(w['interfaces']) - set(obj_in_have['interfaces']))
for i in missing_interfaces:
commands.append('interface %s' % i)
commands.append('vrf forwarding %s' % w['name'])
return commands
def map_config_to_obj(module):
obj = {}
output = run_commands(module, ['show vrf %s' % module.params['name']])
lines = output[0].strip().splitlines()
objs = []
output = run_commands(module, ['show vrf'])
lines = output[0].strip().splitlines()[2:]
if len(lines) > 2:
splitted_line = re.split(r'\s{2,}', lines[2].strip())
obj['name'] = splitted_line[0]
obj['rd'] = splitted_line[1]
obj['interfaces'] = None
for l in lines:
if not l:
continue
if len(splitted_line) > 4:
obj['interfaces'] = []
for i in splitted_line[4].split(','):
obj['interfaces'].append(i.strip())
splitted_line = re.split(r'\s{2,}', l.strip())
if len(splitted_line) == 1:
continue
else:
obj = {}
obj['name'] = splitted_line[0]
obj['rd'] = splitted_line[1]
obj['interfaces'] = None
if len(splitted_line) > 4:
obj['interfaces'] = []
for i in splitted_line[4].split(','):
obj['interfaces'].append(i.strip())
objs.append(obj)
return objs
def map_params_to_obj(module):
obj = []
if 'aggregate' in module.params and module.params['aggregate']:
for c in module.params['aggregate']:
d = c.copy()
if 'state' not in d:
d['state'] = module.params['state']
if 'rd' not in d:
d['rd'] = module.params['rd']
if 'interfaces' not in d:
d['interfaces'] = module.params['interfaces']
obj.append(d)
else:
name = module.params['name'],
state = module.params['state'],
rd = module.params['rd'],
interfaces = module.params['interfaces']
obj.append({
'name': module.params['name'],
'state': module.params['state'],
'rd': module.params['rd'],
'interfaces': module.params['interfaces']
})
return obj
def map_params_to_obj(module):
return {
'name': module.params['name'],
'state': module.params['state'],
'rd': module.params['rd'],
'interfaces': module.params['interfaces']
}
def check_declarative_intent_params(module):
def check_declarative_intent_params(want, module):
if module.params['interfaces']:
time.sleep(module.params['delay'])
have = map_config_to_obj(module)
vrf = module.params['name']
for i in module.params['interfaces']:
if i not in have['interfaces']:
module.fail_json(msg="Interface %s not configured on vrf %s" % (i, vrf))
for w in want:
for i in w['interfaces']:
obj_in_have = search_obj_in_list(w['name'], have)
if obj_in_have and 'interfaces' in obj_in_have and i not in obj_in_have['interfaces']:
module.fail_json(msg="Interface %s not configured on vrf %s" % (i, w['name']))
def main():
""" main entry point for module execution
"""
argument_spec = dict(
name=dict(required=True),
name=dict(),
interfaces=dict(type='list'),
delay=dict(default=10, type='int'),
rd=dict(),
aggregate=dict(),
aggregate=dict(type='list'),
purge=dict(default=False, type='bool'),
state=dict(default='present', choices=['present', 'absent'])
)
argument_spec.update(eos_argument_spec)
required_one_of = [['name', 'aggregate']]
mutually_exclusive = [['name', 'aggregate']]
module = AnsibleModule(argument_spec=argument_spec,
required_one_of=required_one_of,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True)
warnings = list()
@ -200,7 +252,7 @@ def main():
result['changed'] = True
if result['changed']:
check_declarative_intent_params(module)
check_declarative_intent_params(want, module)
module.exit_json(**result)

View file

@ -7,6 +7,20 @@
authorize: yes
provider: "{{ cli }}"
- name: setup - remove vrf
eos_vrf:
name: test2
state: absent
authorize: yes
provider: "{{ cli }}"
- name: setup - remove vrf
eos_vrf:
name: test3
state: absent
authorize: yes
provider: "{{ cli }}"
- name: Create vrf
eos_vrf:
name: test
@ -110,6 +124,74 @@
# Ensure sessions contains epoc. Will fail after 18th May 2033
- "'session_name' not in result.commands"
- name: Create aggregate of VRFs
eos_vrf:
aggregate:
- { name: test2, rd: "1:202" }
- { name: test3, rd: "1:203" }
state: present
authorize: yes
provider: "{{ cli }}"
register: result
- assert:
that:
- "result.changed == true"
- "'vrf definition test2' in result.commands"
- "'rd 1:202' in result.commands"
- "'vrf definition test3' in result.commands"
- "'rd 1:203' in result.commands"
# Ensure sessions contains epoc. Will fail after 18th May 2033
- "'ansible_1' in result.session_name"
- name: Create aggregate of VRFs again (idempotent)
eos_vrf:
aggregate:
- { name: test2, rd: "1:202" }
- { name: test3, rd: "1:203" }
state: present
authorize: yes
provider: "{{ cli }}"
register: result
- assert:
that:
- "result.changed == false"
- "result.commands | length == 0"
# Ensure sessions contains epoc. Will fail after 18th May 2033
- "result.session_name is not defined"
- name: Delete VRFs
eos_vrf:
name: test
state: absent
authorize: yes
provider: "{{ cli }}"
- name: Delete VRFs again (idempotent)
eos_vrf:
name: test
state: absent
authorize: yes
provider: "{{ cli }}"
- name: Delete aggregate of VRFs
eos_vrf:
aggregate:
- { name: test2 }
- { name: test3 }
state: absent
authorize: yes
provider: "{{ cli }}"
- name: Delete VRFs again (idempotent)
eos_vrf:
aggregate:
- { name: test2 }
- { name: test3 }
state: absent
authorize: yes
provider: "{{ cli }}"
# FIXME add in tests for everything defined in docs
# FIXME Test state:absent + test: