New module for BGP configuration management in Arista EOS (#52722)

* New module for BGP in EOS

Signed-off-by: NilashishC <nilashishchakraborty8@gmail.com>

* Add function to validate input

Signed-off-by: NilashishC <nilashishchakraborty8@gmail.com>

* Fix line indentation

Signed-off-by: NilashishC <nilashishchakraborty8@gmail.com>

* Add integration tests

Signed-off-by: NilashishC <nilashishchakraborty8@gmail.com>

* Fix CI

Signed-off-by: NilashishC <nilashishchakraborty8@gmail.com>

* Fix sanity test failure

Signed-off-by: NilashishC <nilashishchakraborty8@gmail.com>

* Remove unused code

Signed-off-by: NilashishC <nilashishchakraborty8@gmail.com>
This commit is contained in:
Nilashish Chakraborty
2019-03-12 17:31:58 +05:30
committed by GitHub
parent 3bef1dbfd2
commit 9365c0f468
17 changed files with 1657 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
---
testcase: "*"
test_items: []

View File

@@ -0,0 +1,2 @@
dependencies:
- prepare_eos_tests

View File

@@ -0,0 +1,16 @@
---
- name: collect all cli test cases
find:
paths: "{{ role_path }}/tests/cli"
patterns: "{{ testcase }}.yaml"
register: test_cases
delegate_to: localhost
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test cases (connection=network_cli)
include: "{{ test_case_to_run }} ansible_connection=network_cli"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

View File

@@ -0,0 +1,2 @@
---
- { include: cli.yaml, tags: ['cli'] }

View File

@@ -0,0 +1,372 @@
- debug: msg="START eos cli/eos_bgp.yaml on connection={{ ansible_connection }}"
- name: Clear existing BGP config
eos_bgp:
operation: delete
ignore_errors: yes
- name: Configure BGP with AS 64496 and a router-id
eos_bgp: &config
operation: merge
config:
bgp_as: 64496
router_id: 192.0.2.2
register: result
- assert:
that:
- 'result.changed == true'
- "'router bgp 64496' in result.commands"
- "'router-id 192.0.2.2' in result.commands"
- name: Configure BGP with AS 64496 and a router-id (idempotent)
eos_bgp: *config
register: result
- assert:
that:
- 'result.changed == false'
- name: Configure BGP neighbors
eos_bgp: &nbr
operation: merge
config:
bgp_as: 64496
neighbors:
- neighbor: 192.0.2.10
remote_as: 64496
description: IBGP_NBR_1
ebgp_multihop: 100
timers:
keepalive: 300
holdtime: 360
- neighbor: 192.0.2.15
remote_as: 64496
description: IBGP_NBR_2
ebgp_multihop: 150
register: result
- assert:
that:
- 'result.changed == true'
- "'router bgp 64496' in result.commands"
- "'neighbor 192.0.2.10 remote-as 64496' in result.commands"
- "'neighbor 192.0.2.10 description IBGP_NBR_1' in result.commands"
- "'neighbor 192.0.2.10 ebgp-multihop 100' in result.commands"
- "'neighbor 192.0.2.10 timers 300 360' in result.commands"
- "'neighbor 192.0.2.15 remote-as 64496' in result.commands"
- "'neighbor 192.0.2.15 description IBGP_NBR_2' in result.commands"
- "'neighbor 192.0.2.15 ebgp-multihop 150' in result.commands"
- name: Configure BGP neighbors (idempotent)
eos_bgp: *nbr
register: result
- assert:
that:
- 'result.changed == false'
- name: Configure BGP neighbors with operation replace
eos_bgp: &nbr_rplc
operation: replace
config:
bgp_as: 64496
neighbors:
- neighbor: 192.0.2.15
remote_as: 64496
description: IBGP_NBR_2
ebgp_multihop: 150
- neighbor: 203.0.113.10
remote_as: 64511
description: EBGP_NBR_1
register: result
- assert:
that:
- 'result.changed == true'
- "'neighbor 203.0.113.10 remote-as 64511' in result.commands"
- "'neighbor 203.0.113.10 description EBGP_NBR_1' in result.commands"
- "'no neighbor 192.0.2.10' in result.commands"
- name: Configure BGP neighbors with operation replace (idempotent)
eos_bgp: *nbr_rplc
register: result
- assert:
that:
- 'result.changed == false'
- name: Configure root-level networks for BGP
eos_bgp: &net
operation: merge
config:
bgp_as: 64496
networks:
- prefix: 203.0.113.0
masklen: 27
route_map: RMAP_1
- prefix: 203.0.113.32
masklen: 27
route_map: RMAP_2
register: result
- assert:
that:
- 'result.changed == True'
- "'router bgp 64496' in result.commands"
- "'network 203.0.113.0/27 route-map RMAP_1' in result.commands"
- "'network 203.0.113.32/27 route-map RMAP_2' in result.commands"
- name: Configure root-level networks for BGP (idempotent)
eos_bgp: *net
register: result
- assert:
that:
- 'result.changed == false'
- name: Configure root-level networks for BGP with operation replace
eos_bgp: &net_rplc
operation: replace
config:
bgp_as: 64496
networks:
- prefix: 203.0.113.0
masklen: 27
route_map: RMAP_1
- prefix: 198.51.100.16
masklen: 28
register: result
- assert:
that:
- 'result.changed == True'
- "'router bgp 64496' in result.commands"
- "'network 198.51.100.16/28' in result.commands"
- "'no network 203.0.113.32/27' in result.commands"
- name: Configure root-level networks for BGP with operation replace (idempotent)
eos_bgp: *net_rplc
register: result
- assert:
that:
- 'result.changed == false'
- name: Configure BGP route redistribute information
eos_bgp: &rdr
operation: merge
config:
bgp_as: 64496
redistribute:
- protocol: ospf
route_map: RMAP_1
- protocol: rip
register: result
- assert:
that:
- 'result.changed == true'
- "'router bgp 64496' in result.commands"
- "'redistribute ospf route-map RMAP_1' in result.commands"
- "'redistribute rip' in result.commands"
- name: Configure BGP route redistribute information (idempotent)
eos_bgp: *rdr
register: result
- assert:
that:
- 'result.changed == false'
- name: Configure BGP route redistribute information with operation replace
eos_bgp: &rdr_rplc
operation: replace
config:
bgp_as: 64496
redistribute:
- protocol: ospf
route_map: RMAP_1
- protocol: static
route_map: RMAP_2
register: result
- assert:
that:
- 'result.changed == true'
- "'redistribute static route-map RMAP_2' in result.commands"
- "'no redistribute rip' in result.commands"
- name: Configure BGP route redistribute information with operation replace (idempotent)
eos_bgp: *rdr_rplc
register: result
- assert:
that:
- 'result.changed == false'
- name: Configure BGP neighbors under address family mode
eos_bgp: &af_nbr
operation: merge
config:
bgp_as: 64496
address_family:
- afi: ipv4
neighbors:
- neighbor: 203.0.113.10
activate: yes
default_originate: True
- neighbor: 192.0.2.15
activate: yes
graceful_restart: True
register: result
- assert:
that:
- 'result.changed == true'
- "'router bgp 64496' in result.commands"
- "'address-family ipv4' in result.commands"
- "'neighbor 203.0.113.10 activate' in result.commands"
- "'neighbor 203.0.113.10 default-originate' in result.commands"
- "'neighbor 192.0.2.15 activate' in result.commands"
- "'neighbor 192.0.2.15 graceful-restart' in result.commands"
- name: Configure BGP neighbors under address family mode (idempotent)
eos_bgp: *af_nbr
register: result
- assert:
that:
- 'result.changed == false'
- name: Configure networks under address family
eos_bgp: &af_net
operation: merge
config:
bgp_as: 64496
address_family:
- afi: ipv4
networks:
- prefix: 198.51.100.48
masklen: 28
route_map: RMAP_1
- prefix: 192.0.2.64
masklen: 27
- prefix: 203.0.113.160
masklen: 27
route_map: RMAP_2
- afi: ipv6
networks:
- prefix: "2001:db8::"
masklen: 33
register: result
- assert:
that:
- 'result.changed == true'
- "'router bgp 64496' in result.commands"
- "'address-family ipv4' in result.commands"
- "'network 198.51.100.48/28 route-map RMAP_1' in result.commands"
- "'network 192.0.2.64/27' in result.commands"
- "'network 203.0.113.160/27 route-map RMAP_2' in result.commands"
- "'address-family ipv6' in result.commands"
- "'network 2001:db8::/33' in result.commands"
- name: Configure networks under address family (idempotent)
eos_bgp: *af_net
register: result
- assert:
that:
- 'result.changed == false'
- name: Configure networks under address family with operation replace
eos_bgp: &af_net_rplc
operation: replace
config:
bgp_as: 64496
address_family:
- afi: ipv4
networks:
- prefix: 198.51.100.80
masklen: 28
- prefix: 192.0.2.64
masklen: 27
- prefix: 203.0.113.192
masklen: 27
- afi: ipv6
networks:
- prefix: "2001:db8:1000::"
masklen: 37
register: result
- assert:
that:
- 'result.changed == true'
- '"router bgp 64496" in result.commands'
- '"address-family ipv4" in result.commands'
- '"network 198.51.100.80/28" in result.commands'
- '"network 203.0.113.192/27" in result.commands'
- '"no network 198.51.100.48/28" in result.commands'
- '"no network 203.0.113.160/27" in result.commands'
- '"address-family ipv6" in result.commands'
- '"network 2001:db8:1000::/37" in result.commands'
- '"no network 2001:db8::/33" in result.commands'
- name: Configure networks under address family with operation replace (idempotent)
eos_bgp: *af_net_rplc
register: result
- assert:
that:
- 'result.changed == false'
- name: Override all the exisiting BGP config
eos_bgp:
operation: override
config:
bgp_as: 64497
router_id: 192.0.2.10
log_neighbor_changes: True
register: result
- assert:
that:
- 'result.changed == true'
- "'no router bgp 64496' in result.commands"
- "'router bgp 64497' in result.commands"
- "'router-id 192.0.2.10' in result.commands"
- "'bgp log-neighbor-changes' in result.commands"
- name: Teardown
eos_bgp: &rm
operation: delete
register: result
- assert:
that:
- 'result.changed == true'
- "'no router bgp 64497' in result.commands"
- name: Teardown again (idempotent)
eos_bgp: *rm
register: result
- assert:
that:
- 'result.changed == false'
- debug: msg="END eos cli/eos_bgp.yaml on connection={{ ansible_connection }}"

View File

@@ -0,0 +1,24 @@
router bgp 64496
bgp router-id 192.0.2.1
bgp log-neighbor-changes
neighbor 198.51.100.102 remote-as 64498
neighbor 198.51.100.102 timers 300 360
neighbor 192.0.2.111 remote-as 64496
neighbor 192.0.2.111 update-source Ethernet1
neighbor 203.0.113.5 remote-as 64511
neighbor 203.0.113.5 maximum-routes 500
redistribute ospf route-map RMAP_1
address-family ipv4
neighbor 198.51.100.102 activate
neighbor 198.51.100.102 graceful-restart
neighbor 198.51.100.102 default-originate
neighbor 198.51.100.102 weight 25
neighbor 192.0.2.111 activate
neighbor 192.0.2.111 default-originate
network 192.0.2.0/27 route-map RMAP_1
network 198.51.100.0/24 route-map RMAP_2
!
address-family ipv6
network 2001:db8:8000::/34
network 2001:db8:c000::/34

View File

@@ -0,0 +1,197 @@
#
# (c) 2019, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.module_utils.network.eos.providers.cli.config.bgp.process import Provider
from ansible.modules.network.eos import eos_bgp
from .eos_module import TestEosModule, load_fixture
class TestFrrBgpModule(TestEosModule):
module = eos_bgp
def setUp(self):
super(TestFrrBgpModule, self).setUp()
self._bgp_config = load_fixture('eos_bgp_config.cfg')
def test_eos_bgp(self):
obj = Provider(params=dict(config=dict(bgp_as=64496, router_id='192.0.2.2', networks=None,
address_family=None), operation='merge'))
commands = obj.render(self._bgp_config)
self.assertEqual(commands, ['router bgp 64496', 'router-id 192.0.2.2', 'exit'])
def test_eos_bgp_idempotent(self):
obj = Provider(params=dict(config=dict(bgp_as=64496, router_id='192.0.2.1',
networks=None, address_family=None), operation='merge'))
commands = obj.render(self._bgp_config)
self.assertEqual(commands, [])
def test_eos_bgp_remove(self):
obj = Provider(params=dict(config=dict(bgp_as=64496, networks=None, address_family=None), operation='delete'))
commands = obj.render(self._bgp_config)
self.assertEqual(commands, ['no router bgp 64496'])
def test_eos_bgp_neighbor(self):
obj = Provider(params=dict(config=dict(bgp_as=64496, neighbors=[dict(neighbor='198.51.100.12', remote_as=64498)],
networks=None, address_family=None),
operation='merge'))
commands = obj.render(self._bgp_config)
self.assertEqual(commands, ['router bgp 64496', 'neighbor 198.51.100.12 remote-as 64498', 'exit'])
def test_eos_bgp_neighbor_idempotent(self):
neighbors = [dict(neighbor='198.51.100.102', remote_as=64498, timers=dict(keepalive=300, holdtime=360)),
dict(neighbor='203.0.113.5', remote_as=64511, maximum_prefix=500)]
obj = Provider(params=dict(config=dict(bgp_as=64496, neighbors=neighbors, networks=None, address_family=None),
operation='merge'))
commands = obj.render(self._bgp_config)
self.assertEqual(commands, [])
def test_eos_bgp_network(self):
obj = Provider(
params=dict(config=dict(bgp_as=64496, networks=[dict(prefix='203.0.113.0', masklen=24, route_map='RMAP_1')],
address_family=None),
operation='merge'))
commands = obj.render(self._bgp_config)
self.assertEqual(sorted(commands), sorted(['router bgp 64496', 'network 203.0.113.0/24 route-map RMAP_1', 'exit']))
def test_eos_bgp_network_idempotent(self):
obj = Provider(
params=dict(config=dict(bgp_as=64496, networks=[dict(prefix='192.0.2.0', masklen=27, route_map='RMAP_1'),
dict(prefix='198.51.100.0', masklen=24, route_map='RMAP_2')],
address_family=None),
operation='merge'))
commands = obj.render(self._bgp_config)
self.assertEqual(commands, [])
def test_eos_bgp_redistribute(self):
rd_1 = dict(protocol='rip', route_map='RMAP_1')
config = dict(bgp_as=64496, redistribute=[rd_1], networks=None, address_family=None)
obj = Provider(params=dict(config=config, operation='merge'))
commands = obj.render(self._bgp_config)
cmd = ['router bgp 64496', 'redistribute rip route-map RMAP_1', 'exit']
self.assertEqual(sorted(commands), sorted(cmd))
def test_eos_bgp_redistribute_idempotent(self):
rd_1 = dict(protocol='ospf', route_map='RMAP_1')
config = dict(bgp_as=64496, redistribute=[rd_1], networks=None, address_family=None)
obj = Provider(params=dict(config=config, operation='merge'))
commands = obj.render(self._bgp_config)
self.assertEqual(commands, [])
def test_eos_bgp_address_family_neighbors(self):
af_nbr_1 = dict(neighbor='198.51.100.104', default_originate=True, activate=True)
af_nbr_2 = dict(neighbor='198.51.100.105', activate=True, weight=30, graceful_restart=True)
config = dict(bgp_as=64496, address_family=[dict(afi='ipv4', neighbors=[af_nbr_1, af_nbr_2])],
networks=None)
obj = Provider(params=dict(config=config, operation='merge'))
commands = obj.render(self._bgp_config)
cmd = ['router bgp 64496', 'address-family ipv4', 'neighbor 198.51.100.104 activate',
'neighbor 198.51.100.104 default-originate', 'neighbor 198.51.100.105 weight 30',
'neighbor 198.51.100.105 activate', 'neighbor 198.51.100.105 graceful-restart', 'exit', 'exit']
self.assertEqual(sorted(commands), sorted(cmd))
def test_eos_bgp_address_family_neighbors_idempotent(self):
af_nbr_1 = dict(neighbor='198.51.100.102', activate=True, graceful_restart=True, default_originate=True, weight=25)
af_nbr_2 = dict(neighbor='192.0.2.111', activate=True, default_originate=True)
config = dict(bgp_as=64496, address_family=[dict(afi='ipv4', neighbors=[af_nbr_1, af_nbr_2])],
networks=None)
obj = Provider(params=dict(config=config, operation='merge'))
commands = obj.render(self._bgp_config)
self.assertEqual(commands, [])
def test_eos_bgp_address_family_networks(self):
net = dict(prefix='203.0.113.128', masklen=26, route_map='RMAP_1')
net2 = dict(prefix='203.0.113.192', masklen=26, route_map='RMAP_2')
config = dict(bgp_as=64496, address_family=[dict(afi='ipv4', networks=[net, net2])],
networks=None)
obj = Provider(params=dict(config=config, operation='merge'))
commands = obj.render(self._bgp_config)
cmd = ['router bgp 64496', 'address-family ipv4', 'network 203.0.113.128/26 route-map RMAP_1',
'network 203.0.113.192/26 route-map RMAP_2', 'exit', 'exit']
self.assertEqual(sorted(commands), sorted(cmd))
def test_eos_bgp_address_family_networks_idempotent(self):
net = dict(prefix='2001:db8:8000::', masklen=34, route_map=None)
net2 = dict(prefix='2001:db8:c000::', masklen=34, route_map=None)
config = dict(bgp_as=64496, address_family=[dict(afi='ipv6', networks=[net, net2])],
networks=None)
obj = Provider(params=dict(config=config, operation='merge'))
commands = obj.render(self._bgp_config)
self.assertEqual(commands, [])
def test_eos_bgp_operation_override(self):
net_1 = dict(prefix='2001:0db8:0800::', masklen=38, route_map='RMAP_1')
net_2 = dict(prefix='2001:0db8:1c00::', masklen=38, route_map='RMAP_2')
nbr_1 = dict(neighbor='203.0.113.111', remote_as=64511, update_source='Ethernet2')
nbr_2 = dict(neighbor='203.0.113.120', remote_as=64511, timers=dict(keepalive=300, holdtime=360))
af_nbr_1 = dict(neighbor='203.0.113.111', activate=True)
af_nbr_2 = dict(neighbor='203.0.113.120', activate=True, default_originate=True)
af_1 = dict(afi='ipv4', neighbors=[af_nbr_1, af_nbr_2])
af_2 = dict(afi='ipv6', networks=[net_1, net_2])
config = dict(bgp_as=64496, neighbors=[nbr_1, nbr_2], address_family=[af_1, af_2],
networks=None)
obj = Provider(params=dict(config=config, operation='override'))
commands = obj.render(self._bgp_config)
cmd = ['no router bgp 64496', 'router bgp 64496', 'neighbor 203.0.113.111 remote-as 64511',
'neighbor 203.0.113.111 update-source Ethernet2', 'neighbor 203.0.113.120 remote-as 64511',
'neighbor 203.0.113.120 timers 300 360', 'address-family ipv4',
'neighbor 203.0.113.111 activate', 'neighbor 203.0.113.120 default-originate', 'neighbor 203.0.113.120 activate',
'exit', 'address-family ipv6', 'network 2001:0db8:0800::/38 route-map RMAP_1',
'network 2001:0db8:1c00::/38 route-map RMAP_2',
'exit', 'exit']
self.assertEqual(sorted(commands), sorted(cmd))
def test_eos_bgp_operation_replace(self):
net = dict(prefix='203.0.113.0', masklen=27, route_map='RMAP_1')
net2 = dict(prefix='192.0.2.32', masklen=29, route_map='RMAP_2')
net_3 = dict(prefix='2001:db8:8000::', masklen=34, route_map=None)
net_4 = dict(prefix='2001:db8:c000::', masklen=34, route_map=None)
af_1 = dict(afi='ipv4', networks=[net, net2])
af_2 = dict(afi='ipv6', networks=[net_3, net_4])
config = dict(bgp_as=64496, address_family=[af_1, af_2], networks=None)
obj = Provider(params=dict(config=config, operation='replace'))
commands = obj.render(self._bgp_config)
cmd = ['router bgp 64496', 'address-family ipv4', 'network 203.0.113.0/27 route-map RMAP_1',
'network 192.0.2.32/29 route-map RMAP_2', 'no network 192.0.2.0/27', 'no network 198.51.100.0/24',
'exit', 'exit']
self.assertEqual(sorted(commands), sorted(cmd))
def test_eos_bgp_operation_replace_with_new_as(self):
nbr = dict(neighbor='203.0.113.124', remote_as=64496, update_source='Ethernet3')
config = dict(bgp_as=64497, neighbors=[nbr], networks=None, address_family=None)
obj = Provider(params=dict(config=config, operation='replace'))
commands = obj.render(self._bgp_config)
cmd = ['no router bgp 64496', 'router bgp 64497', 'neighbor 203.0.113.124 remote-as 64496',
'neighbor 203.0.113.124 update-source Ethernet3', 'exit']
self.assertEqual(sorted(commands), sorted(cmd))