Lenovo cnos vrf (#54188)

* Adding module cnos_vrf to manage VRF Configurations.

* Update cnos_vrf.py

* Adding Functional Tests, Unit Tests and Bug Fixes.

* Fixing discrepancy in description against sample

* Review comments incorporated

* Review comments 2 Done

* Update basic.yaml

* Update test_cnos_vrf.py

* Review comments 3
This commit is contained in:
Anil Kumar Muraleedharan 2019-03-28 19:19:37 +05:30 committed by Sumit Jaiswal
commit 82d26c8c93
17 changed files with 889 additions and 7 deletions

View file

@ -10,5 +10,5 @@
# Following you should specify IP Addresses details
# Please change <username> and <password> with appropriate value for your switch.
[cnos_command]
[cnos_command_sample]
10.241.107.39 ansible_network_os=cnos ansible_ssh_user=<username> ansible_ssh_pass=<password> deviceType=g8272_cnos

View file

@ -10,5 +10,5 @@
# Following you should specify IP Addresses details
# Please change <username> and <password> with appropriate value for your switch.
[cnos_config]
[cnos_config_sample]
10.241.107.39 ansible_network_os=cnos ansible_ssh_user=<username> ansible_ssh_pass=<password> deviceType=g8272_cnos

View file

@ -10,5 +10,5 @@
# Following you should specify IP Addresses details
# Please change <username> and <password> with appropriate value for your switch.
[cnos_facts]
[cnos_facts_sample]
10.241.107.39 ansible_network_os=cnos ansible_ssh_user=<username> ansible_ssh_pass=<password> deviceType=g8272_cnos

View file

@ -0,0 +1,14 @@
# You have to paste this dummy information in /etc/ansible/hosts
# Notes:
# - Comments begin with the '#' character
# - Blank lines are ignored
# - Groups of hosts are delimited by [header] elements
# - You can enter hostnames or ip Addresses
# - A hostname/ip can be a member of multiple groups
#
# In the /etc/ansible/hosts file u have to enter [cnos_lldp_sample] tag
# Following you should specify IP Addresses details
# Please change <username> and <password> with appropriate value for your switch.
[cnos_lldp_sample]
10.241.107.39 ansible_network_os=cnos ansible_ssh_user=<username> ansible_ssh_pass=<password> deviceType=g8272_cnos

View file

@ -6,7 +6,7 @@
# - You can enter hostnames or ip Addresses
# - A hostname/ip can be a member of multiple groups
#
# In the /etc/ansible/hosts file u have to enter [cnos_portchannel_sample] tag
# In the /etc/ansible/hosts file u have to enter [cnos_logging_sample] tag
# Following you should specify IP Addresses details
# Please change <username> and <password> with appropriate value for your switch.

View file

@ -6,7 +6,7 @@
# - You can enter hostnames or ip Addresses
# - A hostname/ip can be a member of multiple groups
#
# In the /etc/ansible/hosts file u have to enter [cnos_facts_sample] tag
# In the /etc/ansible/hosts file u have to enter [cnos_showrun_sample] tag
# Following you should specify IP Addresses details
# Please change <username> and <password> with appropriate value for your switch.

View file

@ -10,5 +10,5 @@
# Following you should specify IP Addresses details
# Please change <username> and <password> with appropriate value for your switch.
[cnos_sample_sample]
[cnos_user_sample]
10.241.107.39 ansible_network_os=cnos ansible_ssh_user=admin ansible_ssh_pass=admin

View file

@ -10,5 +10,5 @@
# Following you should specify IP Addresses details
# Please change <username> and <password> with appropriate value for your switch.
[cnos]
[cnos_vlan_sample]
10.241.107.39 ansible_network_os=cnos ansible_ssh_user=<username> ansible_ssh_pass=<password>

View file

@ -0,0 +1,2 @@
# No Lenovo Switch simulator yet, so not enabled
unsupported

View file

@ -0,0 +1,14 @@
# You have to paste this dummy information in /etc/ansible/hosts
# Notes:
# - Comments begin with the '#' character
# - Blank lines are ignored
# - Groups of hosts are delimited by [header] elements
# - You can enter hostnames or ip Addresses
# - A hostname/ip can be a member of multiple groups
#
# In the /etc/ansible/hosts file u have to enter [cnos_vrf_sample] tag
# Following you should specify IP Addresses details
# Please change <username> and <password> with appropriate value for your switch.
[cnos_vrf_sample]
10.241.107.39 ansible_network_os=cnos ansible_ssh_user=<username> ansible_ssh_pass=<password> test_interface=ethernet1/33 test_interface2=ethernet1/44

View file

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

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,250 @@
---
- name: setup - remove vrf
cnos_vrf:
name: "{{ item }}"
state: absent
become: yes
with_items:
- test
- test1
- test2
- test3
- test4
- test5
- name: Create vrf
cnos_vrf:
name: test
rd: 1:200
state: present
become: yes
register: result
- assert:
that:
- "result.changed == true"
- "'vrf context test' in result.commands"
- "'rd 1:200' in result.commands"
- name: Create vrf again (idempotent)
cnos_vrf:
name: test
rd: 1:200
state: present
become: yes
register: result
- assert:
that:
- "result.changed == false"
- "result.commands | length == 0"
- name: Modify rd
cnos_vrf:
name: test
rd: 1:201
state: present
become: yes
register: result
- assert:
that:
- "result.changed == true"
- "'vrf context test' in result.commands"
- "'rd 1:201' in result.commands"
- name: Modify rd again (idempotent)
cnos_vrf:
name: test
rd: 1:201
state: present
become: yes
register: result
- assert:
that:
- "result.changed == false"
- "result.commands | length == 0"
- name: Add Ethernet1/33 to vrf and check interface assigned state
cnos_vrf:
name: test
rd: 1:201
state: present
interfaces:
- Ethernet1/33
associated_interfaces:
- Ethernet1/33
become: yes
register: result
- assert:
that:
- "result.changed == true"
- "'interface ethernet1/33' in result.commands"
- "'vrf member test' in result.commands"
- name: Add Ethernet1/33 to vrf again (idempotent)
cnos_vrf:
name: test
rd: 1:201
state: present
interfaces:
- ethernet 1/33 # interface name modified to test case insensitive and space scenario
become: yes
register: result
- assert:
that:
- "result.changed == false"
- "result.commands | length == 0"
- name: Add multiple interfaces to vrf
cnos_vrf:
name: test1
rd: 1:202
state: present
interfaces:
- loopback 1
- loopback 2
- loopback 3
- loopback 4
- loopback 5
- loopback 6
become: yes
register: result
- assert:
that:
- "result.changed == true"
- "'interface loopback1' in result.commands"
- "'vrf member test1' in result.commands"
- "'interface loopback2' in result.commands"
- "'vrf member test1' in result.commands"
- "'interface loopback3' in result.commands"
- "'vrf member test1' in result.commands"
- "'interface loopback4' in result.commands"
- "'vrf member test1' in result.commands"
- "'interface loopback5' in result.commands"
- "'vrf member test1' in result.commands"
- "'interface loopback6' in result.commands"
- "'vrf member test1' in result.commands"
- name: Add multiple interfaces to vrf (idempotent)
cnos_vrf:
name: test1
rd: 1:202
state: present
interfaces:
- loopback 1
- loopback 2
- loopback 3
- loopback 4
- loopback 5
- loopback 6
become: yes
register: result
- assert:
that:
- "result.changed == false"
- "result.commands | length == 0"
- name: setup - remove vrf
cnos_vrf:
name: "{{ item }}"
state: absent
become: yes
with_items:
- test1
- test2
- test3
- name: Create aggregate of VRFs
cnos_vrf:
aggregate:
- { name: test2, rd: "1:202" }
- { name: test3, rd: "1:203" }
state: present
register: result
- assert:
that:
- "result.changed == true"
- "'vrf context test2' in result.commands"
- "'rd 1:202' in result.commands"
- "'vrf context test3' in result.commands"
- "'rd 1:203' in result.commands"
- name: Create aggregate of VRFs again (idempotent)
cnos_vrf:
aggregate:
- { name: test2, rd: "1:202" }
- { name: test3, rd: "1:203" }
state: present
become: yes
register: result
- assert:
that:
- "result.changed == false"
- "result.commands | length == 0"
- name: Create aggregate of VRFs with purge
cnos_vrf:
aggregate:
- { name: test4, rd: "1:204" }
- { name: test5, rd: "1:205" }
state: present
purge: yes
become: yes
register: result
- assert:
that:
- "result.changed == true"
- "'vrf context test4' in result.commands"
- "'rd 1:204' in result.commands"
- "'vrf context test5' in result.commands"
- "'rd 1:205' in result.commands"
- "'no vrf context test' in result.commands"
- "'no vrf context test2' in result.commands"
- "'no vrf context test3' in result.commands"
- name: Delete VRFs
cnos_vrf:
name: test
state: absent
become: yes
- name: Delete VRFs again (idempotent)
cnos_vrf:
name: test
state: absent
become: yes
- name: Delete aggregate of VRFs
cnos_vrf:
aggregate:
- { name: test1 }
- { name: test2 }
- { name: test3 }
- { name: test4 }
- { name: test5 }
state: absent
become: yes
- name: Delete VRFs again (idempotent)
cnos_vrf:
aggregate:
- { name: test1 }
- { name: test2 }
- { name: test3 }
- { name: test4 }
- { name: test5 }
state: absent
become: yes
- assert:
that:
- "result.changed == true"

View file

@ -0,0 +1,176 @@
Maximum number of vrfs allowed: 65
VRF default, FIB ID 0
Router ID: 20.141.2.1 (automatic)
RD 0:0
Interfaces:
Vlan1
Vlan2
Vlan13
loopback0
Ethernet1/5
Ethernet1/6
Ethernet1/7
Ethernet1/8
Ethernet1/9
Ethernet1/11
Ethernet1/12
Ethernet1/13
Ethernet1/44
po1
po2
po3
po4
po6
po7
po8
po9
po10
po11
po12
po13
po14
po15
po16
po17
po18
po19
po21
po22
po23
po24
po25
po26
po27
po28
po29
po30
po31
po32
po33
po34
po35
po36
po37
po38
po39
po40
po41
po42
po43
po44
po45
po46
po47
po48
po49
po50
po51
po52
po53
po54
po55
po56
po57
po58
po59
po60
po61
po62
po63
po64
po65
po66
po67
po1001
po1002
po1003
po1004
Ethernet1/1
Ethernet1/2
Ethernet1/3
Ethernet1/4
Ethernet1/10
Ethernet1/14
Ethernet1/15
Ethernet1/16
Ethernet1/17
Ethernet1/18
Ethernet1/19
Ethernet1/20
Ethernet1/21
Ethernet1/22
Ethernet1/23
Ethernet1/24
Ethernet1/25
Ethernet1/26
Ethernet1/27
Ethernet1/28
Ethernet1/29
Ethernet1/30
Ethernet1/31
Ethernet1/32
Ethernet1/34
Ethernet1/35
Ethernet1/36
Ethernet1/37
Ethernet1/38
Ethernet1/39
Ethernet1/40
Ethernet1/41
Ethernet1/42
Ethernet1/43
Ethernet1/45
Ethernet1/46
Ethernet1/47
Ethernet1/48
Ethernet1/49
Ethernet1/50
Ethernet1/51
Ethernet1/52
Ethernet1/53
Ethernet1/54
!
VRF management, FIB ID 1
Router ID: 10.241.107.39 (automatic)
RD 0:0
Interfaces:
mgmt0
!
VRF test, FIB ID 2
Router ID is not set
RD 1:201
Interfaces:
Ethernet1/33
!
VRF test1, FIB ID 3
Router ID is not set
RD 1:202
Interfaces:
loopback1
loopback2
loopback3
loopback4
loopback5
loopback6
!
VRF test2, FIB ID 4
Router ID is not set
RD 0:0
Interfaces:
!
VRF test3, FIB ID 5
Router ID is not set
RD 1:203
Interfaces:
!
VRF test4, FIB ID 6
Router ID is not set
RD 1:204
Interfaces:
!
VRF test5, FIB ID 7
Router ID is not set
RD 1:205
Interfaces:
!

View file

@ -0,0 +1,71 @@
#
# (c) 2019 Lenovo.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from units.compat.mock import patch
from ansible.modules.network.cnos import cnos_vrf
from units.modules.utils import set_module_args
from .cnos_module import TestCnosModule, load_fixture
class TestCnosVrfModule(TestCnosModule):
module = cnos_vrf
def setUp(self):
super(TestCnosVrfModule, self).setUp()
self.mock_load_config = patch('ansible.modules.network.cnos.cnos_vrf.load_config')
self.load_config = self.mock_load_config.start()
self.mock_run_commands = patch('ansible.modules.network.cnos.cnos_vrf.run_commands')
self.run_commands = self.mock_run_commands.start()
def tearDown(self):
super(TestCnosVrfModule, self).tearDown()
self.mock_load_config.stop()
self.mock_run_commands.stop()
def load_fixtures(self, commands=None):
config_file = 'cnos_vrf_config.cfg'
self.load_config.return_value = load_fixture(config_file)
self.run_commands.return_value = load_fixture(config_file)
def test_cnos_vrf_present(self):
set_module_args(dict(name='test1', state='present'))
self.execute_module(changed=True, commands=['vrf context test1'])
def test_cnos_vrf_present_management(self):
set_module_args(dict(name='management', state='present'))
self.execute_module(changed=True, commands=['vrf context management'])
def test_cnos_vrf_absent_management(self):
set_module_args(dict(name='management', state='absent'))
result = self.execute_module(failed=True)
self.assertEqual(result['msg'], 'Management VRF context cannot be deleted')
def test_cnos_vrf_absent_no_change(self):
set_module_args(dict(name='test1', state='absent'))
self.execute_module(changed=False, commands=[])
def test_cnos_vrf_default(self):
set_module_args(dict(name='default', state='present'))
result = self.execute_module(failed=True)
self.assertEqual(result['msg'], 'VRF context default is reserved')