mirror of
				https://github.com/ansible-collections/community.general.git
				synced 2025-10-24 21:14:00 -07:00 
			
		
		
		
	nxos_vrf_af fix and unit test (#24399)
* nxos_vrf_af fix and unit test Signed-off-by: Trishna Guha <trishnaguha17@gmail.com> * ansibot told me to do this * use sorted() as the test list elements differ in order for python2.x and 3.x
This commit is contained in:
		
					parent
					
						
							
								62eafa8837
							
						
					
				
			
			
				commit
				
					
						b2a2f69a6e
					
				
			
		
					 3 changed files with 156 additions and 127 deletions
				
			
		|  | @ -16,10 +16,11 @@ | |||
| # along with Ansible.  If not, see <http://www.gnu.org/licenses/>. | ||||
| # | ||||
| 
 | ||||
| ANSIBLE_METADATA = {'metadata_version': '1.0', | ||||
|                     'status': ['preview'], | ||||
|                     'supported_by': 'community'} | ||||
| 
 | ||||
| ANSIBLE_METADATA = { | ||||
|     'metadata_version': '1.0', | ||||
|     'status': ['preview'], | ||||
|     'supported_by': 'community' | ||||
| } | ||||
| 
 | ||||
| DOCUMENTATION = ''' | ||||
| --- | ||||
|  | @ -28,81 +29,60 @@ extends_documentation_fragment: nxos | |||
| version_added: "2.2" | ||||
| short_description: Manages VRF AF. | ||||
| description: | ||||
|     - Manages VRF AF | ||||
|   - Manages VRF AF | ||||
| author: Gabriele Gerbino (@GGabriele) | ||||
| notes: | ||||
|     - Default, where supported, restores params default value. | ||||
|   - Default, where supported, restores params default value. | ||||
| options: | ||||
|     vrf: | ||||
|         description: | ||||
|             - Name of the VRF. | ||||
|         required: true | ||||
|     afi: | ||||
|         description: | ||||
|             - Address-Family Identifier (AFI). | ||||
|         required: true | ||||
|         choices: ['ipv4', 'ipv6'] | ||||
|         default: null | ||||
|     safi: | ||||
|         description: | ||||
|             - Sub Address-Family Identifier (SAFI). | ||||
|         required: true | ||||
|         choices: ['unicast', 'multicast'] | ||||
|         default: null | ||||
|     route_target_both_auto_evpn: | ||||
|         description: | ||||
|             - Enable/Disable the EVPN route-target 'auto' setting for both | ||||
|               import and export target communities. | ||||
|         required: false | ||||
|         choices: ['true', 'false'] | ||||
|         default: null | ||||
|     state: | ||||
|         description: | ||||
|             - Determines whether the config should be present or | ||||
|               not on the device. | ||||
|         required: false | ||||
|         default: present | ||||
|         choices: ['present','absent'] | ||||
|   vrf: | ||||
|     description: | ||||
|       - Name of the VRF. | ||||
|     required: true | ||||
|   afi: | ||||
|     description: | ||||
|       - Address-Family Identifier (AFI). | ||||
|     required: true | ||||
|     choices: ['ipv4', 'ipv6'] | ||||
|     default: null | ||||
|   safi: | ||||
|     description: | ||||
|       - Sub Address-Family Identifier (SAFI). | ||||
|     required: true | ||||
|     choices: ['unicast', 'multicast'] | ||||
|     default: null | ||||
|   route_target_both_auto_evpn: | ||||
|     description: | ||||
|       - Enable/Disable the EVPN route-target 'auto' setting for both | ||||
|         import and export target communities. | ||||
|     required: false | ||||
|     choices: ['true', 'false'] | ||||
|     default: null | ||||
|   state: | ||||
|     description: | ||||
|       - Determines whether the config should be present or | ||||
|         not on the device. | ||||
|     required: false | ||||
|     default: present | ||||
|     choices: ['present','absent'] | ||||
| ''' | ||||
| 
 | ||||
| EXAMPLES = ''' | ||||
| - nxos_vrf_af: | ||||
|     interface: nve1 | ||||
|     vni: 6000 | ||||
|     ingress_replication: true | ||||
|     username: "{{ un }}" | ||||
|     password: "{{ pwd }}" | ||||
|     host: "{{ inventory_hostname }}" | ||||
|     vrf: ntc | ||||
|     afi: ipv4 | ||||
|     safi: unicast | ||||
|     route_target_both_auto_evpn: True | ||||
|     state: present | ||||
| ''' | ||||
| 
 | ||||
| RETURN = ''' | ||||
| proposed: | ||||
|     description: k/v pairs of parameters passed into module | ||||
|     returned: verbose mode | ||||
|     type: dict | ||||
|     sample: {"afi": "ipv4", "route_target_both_auto_evpn": true, | ||||
|             "safi": "unicast", "vrf": "test"} | ||||
| existing: | ||||
|     description: k/v pairs of existing configuration | ||||
|     returned: verbose mode | ||||
|     type: dict | ||||
|     sample: {"afi": "ipv4", "route_target_both_auto_evpn": false, | ||||
|             "safi": "unicast", "vrf": "test"} | ||||
| end_state: | ||||
|     description: k/v pairs of configuration after module execution | ||||
|     returned: verbose mode | ||||
|     type: dict | ||||
|     sample: {"afi": "ipv4", "route_target_both_auto_evpn": true, | ||||
|             "safi": "unicast", "vrf": "test"} | ||||
| updates: | ||||
| commands: | ||||
|     description: commands sent to the device | ||||
|     returned: always | ||||
|     type: list | ||||
|     sample: ["vrf context test", "address-family ipv4 unicast", | ||||
|             "route-target both auto evpn"] | ||||
| changed: | ||||
|     description: check to see if a change was made on the device | ||||
|     returned: always | ||||
|     type: boolean | ||||
|     sample: true | ||||
|     sample: ["vrf context ntc", "address-family ipv4 unicast", | ||||
|             "afi ipv4", "route-target both auto evpn", "vrf ntc", | ||||
|             "safi unicast"] | ||||
| ''' | ||||
| 
 | ||||
| import re | ||||
|  | @ -112,33 +92,32 @@ from ansible.module_utils.nxos import nxos_argument_spec, check_args | |||
| from ansible.module_utils.basic import AnsibleModule | ||||
| from ansible.module_utils.netcfg import CustomNetworkConfig | ||||
| 
 | ||||
| 
 | ||||
| BOOL_PARAMS = ['route_target_both_auto_evpn'] | ||||
| PARAM_TO_COMMAND_KEYMAP = { | ||||
|     'route_target_both_auto_evpn': 'route-target both auto evpn', | ||||
|     'vrf': 'vrf', | ||||
|     'safi': 'safi', | ||||
|     'afi': 'afi', | ||||
|     'route_target_both_auto_evpn': 'route-target both auto evpn' | ||||
| } | ||||
| PARAM_TO_DEFAULT_KEYMAP = {} | ||||
| WARNINGS = [] | ||||
| 
 | ||||
| def invoke(name, *args, **kwargs): | ||||
|     func = globals().get(name) | ||||
|     if func: | ||||
|         return func(*args, **kwargs) | ||||
| 
 | ||||
| 
 | ||||
| def get_value(arg, config, module): | ||||
|     command = PARAM_TO_COMMAND_KEYMAP.get(arg) | ||||
|     if arg in BOOL_PARAMS: | ||||
|         REGEX = re.compile(r'\s+{0}\s*$'.format(PARAM_TO_COMMAND_KEYMAP[arg]), re.M) | ||||
|         command_re = re.compile(r'\s+{0}\s*$'.format(command), re.M) | ||||
|         value = False | ||||
|         try: | ||||
|             if REGEX.search(config): | ||||
|             if command_re.search(config): | ||||
|                 value = True | ||||
|         except TypeError: | ||||
|             value = False | ||||
|     else: | ||||
|         REGEX = re.compile(r'(?:{0}\s)(?P<value>.*)$'.format(PARAM_TO_COMMAND_KEYMAP[arg]), re.M) | ||||
|         command_re = re.compile(r'(?:{0}\s)(?P<value>.*)$'.format(command), re.M) | ||||
|         value = '' | ||||
|         if PARAM_TO_COMMAND_KEYMAP[arg] in config: | ||||
|             value = REGEX.search(config).group('value') | ||||
|         if command in config: | ||||
|             value = command_re.search(config).group('value') | ||||
|     return value | ||||
| 
 | ||||
| 
 | ||||
|  | @ -148,7 +127,7 @@ def get_existing(module, args): | |||
| 
 | ||||
|     parents = ['vrf context {0}'.format(module.params['vrf'])] | ||||
|     parents.append('address-family {0} {1}'.format(module.params['afi'], | ||||
|                                             module.params['safi'])) | ||||
|                                                    module.params['safi'])) | ||||
|     config = netcfg.get_section(parents) | ||||
|     if config: | ||||
|         splitted_config = config.splitlines() | ||||
|  | @ -173,14 +152,10 @@ def get_existing(module, args): | |||
| 
 | ||||
| def apply_key_map(key_map, table): | ||||
|     new_dict = {} | ||||
|     for key, value in table.items(): | ||||
|     for key in table: | ||||
|         new_key = key_map.get(key) | ||||
|         if new_key: | ||||
|             value = table.get(key) | ||||
|             if value: | ||||
|                 new_dict[new_key] = value | ||||
|             else: | ||||
|                 new_dict[new_key] = value | ||||
|             new_dict[new_key] = table.get(key) | ||||
|     return new_dict | ||||
| 
 | ||||
| 
 | ||||
|  | @ -207,7 +182,7 @@ def state_present(module, existing, proposed, candidate): | |||
|     if commands: | ||||
|         parents = ['vrf context {0}'.format(module.params['vrf'])] | ||||
|         parents.append('address-family {0} {1}'.format(module.params['afi'], | ||||
|                                                 module.params['safi'])) | ||||
|                                                        module.params['safi'])) | ||||
|         candidate.add(commands, parents=parents) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -215,19 +190,18 @@ def state_absent(module, existing, proposed, candidate): | |||
|     commands = [] | ||||
|     parents = ['vrf context {0}'.format(module.params['vrf'])] | ||||
|     commands.append('no address-family {0} {1}'.format(module.params['afi'], | ||||
|                                                 module.params['safi'])) | ||||
|                                                        module.params['safi'])) | ||||
|     candidate.add(commands, parents=parents) | ||||
| 
 | ||||
| 
 | ||||
| def main(): | ||||
|     argument_spec = dict( | ||||
|         vrf=dict(required=True, type='str'), | ||||
|         safi=dict(required=True, type='str', choices=['unicast','multicast']), | ||||
|         afi=dict(required=True, type='str', choices=['ipv4','ipv6']), | ||||
|         safi=dict(required=True, type='str', choices=['unicast', 'multicast']), | ||||
|         afi=dict(required=True, type='str', choices=['ipv4', 'ipv6']), | ||||
|         route_target_both_auto_evpn=dict(required=False, type='bool'), | ||||
|         m_facts=dict(required=False, default=False, type='bool'), | ||||
|         state=dict(choices=['present', 'absent'], default='present', | ||||
|                        required=False), | ||||
|         state=dict(choices=['present', 'absent'], default='present', required=False), | ||||
|         include_defaults=dict(default=False), | ||||
|         config=dict(), | ||||
|         save=dict(type='bool', default=False) | ||||
|  | @ -235,26 +209,17 @@ def main(): | |||
| 
 | ||||
|     argument_spec.update(nxos_argument_spec) | ||||
| 
 | ||||
|     module = AnsibleModule(argument_spec=argument_spec, | ||||
|                                 supports_check_mode=True) | ||||
|     module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) | ||||
| 
 | ||||
|     warnings = list() | ||||
|     check_args(module, warnings) | ||||
| 
 | ||||
|     result = dict(changed=False, warnings=warnings) | ||||
| 
 | ||||
|     state = module.params['state'] | ||||
| 
 | ||||
|     args =  [ | ||||
|         'vrf', | ||||
|         'safi', | ||||
|         'afi', | ||||
|         'route_target_both_auto_evpn' | ||||
|     ] | ||||
| 
 | ||||
|     existing = invoke('get_existing', module, args) | ||||
|     end_state = existing | ||||
|     args = PARAM_TO_COMMAND_KEYMAP.keys() | ||||
|     existing = get_existing(module, args) | ||||
|     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) | ||||
| 
 | ||||
|     proposed = {} | ||||
|     for key, value in proposed_args.items(): | ||||
|  | @ -263,31 +228,24 @@ def main(): | |||
|                 value = PARAM_TO_DEFAULT_KEYMAP.get(key) | ||||
|                 if value is None: | ||||
|                     value = 'default' | ||||
|             if existing.get(key) or (not existing.get(key) and value): | ||||
|             if existing.get(key) != value: | ||||
|                 proposed[key] = value | ||||
| 
 | ||||
|     result = {} | ||||
|     if state == 'present' or (state == 'absent' and existing): | ||||
|         candidate = CustomNetworkConfig(indent=3) | ||||
|         invoke('state_%s' % state, module, existing, proposed, candidate) | ||||
|         response = load_config(module, candidate) | ||||
|         result.update(response) | ||||
|     candidate = CustomNetworkConfig(indent=3) | ||||
|     if state == 'present': | ||||
|         state_present(module, existing, proposed, candidate) | ||||
|     elif state == 'absent' and existing: | ||||
|         state_absent(module, existing, proposed, candidate) | ||||
| 
 | ||||
|     if candidate: | ||||
|         load_config(module, candidate) | ||||
|         result['changed'] = True | ||||
|         result['commands'] = candidate.items_text() | ||||
| 
 | ||||
|     else: | ||||
|         result['updates'] = [] | ||||
| 
 | ||||
|     if module._verbosity > 0: | ||||
|         end_state = invoke('get_existing', module, args) | ||||
|         result['end_state'] = end_state | ||||
|         result['existing'] = existing | ||||
|         result['proposed'] = proposed_args | ||||
| 
 | ||||
|     if WARNINGS: | ||||
|         result['warnings'] = WARNINGS | ||||
| 
 | ||||
|         result['commands'] = [] | ||||
|     module.exit_json(**result) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
| 
 | ||||
|  |  | |||
|  | @ -536,7 +536,6 @@ lib/ansible/modules/network/nxos/nxos_user.py | |||
| lib/ansible/modules/network/nxos/nxos_vpc.py | ||||
| lib/ansible/modules/network/nxos/nxos_vpc_interface.py | ||||
| lib/ansible/modules/network/nxos/nxos_vrf.py | ||||
| lib/ansible/modules/network/nxos/nxos_vrf_af.py | ||||
| lib/ansible/modules/network/nxos/nxos_vrf_interface.py | ||||
| lib/ansible/modules/network/nxos/nxos_vrrp.py | ||||
| lib/ansible/modules/network/nxos/nxos_vtp_domain.py | ||||
|  |  | |||
							
								
								
									
										72
									
								
								test/units/modules/network/nxos/test_nxos_vrf_af.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								test/units/modules/network/nxos/test_nxos_vrf_af.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | |||
| # (c) 2016 Red Hat Inc. | ||||
| # | ||||
| # 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/>. | ||||
| 
 | ||||
| # Make coding more python3-ish | ||||
| from __future__ import (absolute_import, division, print_function) | ||||
| __metaclass__ = type | ||||
| 
 | ||||
| import json | ||||
| 
 | ||||
| from ansible.compat.tests.mock import patch | ||||
| from ansible.modules.network.nxos import nxos_vrf_af | ||||
| from .nxos_module import TestNxosModule, load_fixture, set_module_args | ||||
| 
 | ||||
| 
 | ||||
| class TestNxosVrfafModule(TestNxosModule): | ||||
| 
 | ||||
|     module = nxos_vrf_af | ||||
| 
 | ||||
|     def setUp(self): | ||||
|         self.mock_run_commands = patch('ansible.modules.network.nxos.nxos_vrf_af.run_commands') | ||||
|         self.run_commands = self.mock_run_commands.start() | ||||
|         self.mock_load_config = patch('ansible.modules.network.nxos.nxos_vrf_af.load_config') | ||||
|         self.load_config = self.mock_load_config.start() | ||||
| 
 | ||||
|         self.mock_get_config = patch('ansible.modules.network.nxos.nxos_vrf_af.get_config') | ||||
|         self.get_config = self.mock_get_config.start() | ||||
| 
 | ||||
|     def tearDown(self): | ||||
|         self.mock_run_commands.stop() | ||||
|         self.mock_load_config.stop() | ||||
|         self.mock_get_config.stop() | ||||
| 
 | ||||
|     def load_fixtures(self, commands=None): | ||||
|         self.load_config.return_value = None | ||||
| 
 | ||||
|     def test_nxos_vrf_af_present(self): | ||||
|         set_module_args(dict(vrf='ntc', afi='ipv4', safi='unicast', state='present')) | ||||
|         result = self.execute_module(changed=True) | ||||
|         self.assertEqual(sorted(result['commands']), sorted(['vrf context ntc', | ||||
|                                                              'address-family ipv4 unicast', | ||||
|                                                              'afi ipv4', | ||||
|                                                              'vrf ntc', | ||||
|                                                              'safi unicast'])) | ||||
| 
 | ||||
|     def test_nxos_vrf_af_absent(self): | ||||
|         set_module_args(dict(vrf='ntc', afi='ipv4', safi='unicast', state='absent')) | ||||
|         result = self.execute_module(changed=False) | ||||
|         self.assertEqual(result['commands'], []) | ||||
| 
 | ||||
|     def test_nxos_vrf_af_route_target(self): | ||||
|         set_module_args(dict(vrf='ntc', afi='ipv4', safi='unicast', route_target_both_auto_evpn=True)) | ||||
|         result = self.execute_module(changed=True) | ||||
|         self.assertEqual(sorted(result['commands']), sorted(['vrf context ntc', | ||||
|                                                              'address-family ipv4 unicast', | ||||
|                                                              'afi ipv4', | ||||
|                                                              'route-target both auto evpn', | ||||
|                                                              'vrf ntc', | ||||
|                                                              'safi unicast'])) | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue