From 160fd0126f675f42f8a95c5de431511db4219b63 Mon Sep 17 00:00:00 2001 From: Jason Edelman Date: Wed, 17 Aug 2016 19:11:50 -0400 Subject: [PATCH 1/7] improve functionality for vlan trunks based on #4082 --- network/nxos/nxos_switchport.py | 96 +++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 39 deletions(-) diff --git a/network/nxos/nxos_switchport.py b/network/nxos/nxos_switchport.py index c4a0dacd9f6..684b287c6ff 100644 --- a/network/nxos/nxos_switchport.py +++ b/network/nxos/nxos_switchport.py @@ -27,40 +27,47 @@ description: - Manages Layer 2 interfaces author: Jason Edelman (@jedelman8) notes: - - When C(state=absent), VLANs can be added/removed from trunk links and - the existing access VLAN can be 'unconfigured' to just having VLAN 1 + - When state=absent, vlans can be added/removed from trunk links and + the existing access vlan can be 'unconfigured' to just having VLAN 1 on that interface - When working with trunks VLANs the keywords add/remove are always sent in the `switchport trunk allowed vlan` command. Use verbose mode to see commands sent. - - When C(state=unconfigured), the interface will result with having a default + - When state=unconfigured, the interface will result with having a default Layer 2 interface, i.e. vlan 1 in access mode options: interface: description: - - Full name of the interface, i.e. Ethernet1/1. + - Full name of the interface, i.e. Ethernet1/1 required: true default: null mode: description: - - Mode for the Layer 2 port. + - Mode for the Layer 2 port required: false default: null choices: ['access','trunk'] access_vlan: description: - - If C(mode=access), used as the access VLAN ID. + - if mode=access, used as the access vlan id required: false default: null native_vlan: description: - - If C(mode=trunk), used as the trunk native VLAN ID. + - if mode=trunk, used as the trunk native vlan id required: false default: null trunk_vlans: description: - - If C(mode=trunk), used as the VLAN range to ADD or REMOVE - from the trunk. + - if mode=trunk, used as the vlan range to ADD or REMOVE + from the trunk + required: false + aliases: trunk_add_vlans + default: null + trunk_allowed_vlans: + description: + - if mode=trunk, these are the only VLANs that should be + configured on the trunk required: false default: null state: @@ -78,6 +85,9 @@ EXAMPLES = ''' # ENSURE Eth1/5 is configured for access vlan 20 - nxos_switchport: interface=eth1/5 mode=access access_vlan=20 host={{ inventory_hostname }} +# ENSURE Eth1/5 only has vlans 5-10 as trunk vlans +- nxos_switchport: interface=eth1/5 mode=trunk native_vlan=10 trunk_vlans=5-10 host={{ inventory_hostname }} + # Ensure eth1/5 is a trunk port and ensure 2-50 are being tagged (doesn't mean others aren't also being tagged) - nxos_switchport: interface=eth1/5 mode=trunk native_vlan=10 trunk_vlans=2-50 host={{ inventory_hostname }} @@ -264,7 +274,7 @@ def get_switchport(port, module): return {} -def remove_switchport_config_commands(interface, existing, proposed): +def remove_switchport_config_commands(interface, existing, proposed, module): mode = proposed.get('mode') commands = [] command = None @@ -277,14 +287,13 @@ def remove_switchport_config_commands(interface, existing, proposed): elif mode == 'trunk': tv_check = existing.get('trunk_vlans_list') == proposed.get('trunk_vlans_list') if not tv_check: - vlans_to_remove = False - for vlan in proposed.get('trunk_vlans_list'): - if vlan in existing.get('trunk_vlans_list'): - vlans_to_remove = True - break + existing_vlans = existing.get('trunk_vlans_list') + proposed_vlans = proposed.get('trunk_vlans_list') + vlans_to_remove = set(proposed_vlans).intersection(existing_vlans) + # module.exit_json(ex=existing, pr=proposed, vlans_to_remove=list(vlans_to_remove)) if vlans_to_remove: command = 'switchport trunk allowed vlan remove {0}'.format( - proposed.get('trunk_vlans')) + proposed.get('trunk_vlans', proposed.get('trunk_allowed_vlans'))) commands.append(command) native_check = existing.get( 'native_vlan') == proposed.get('native_vlan') @@ -297,7 +306,7 @@ def remove_switchport_config_commands(interface, existing, proposed): return commands -def get_switchport_config_commands(interface, existing, proposed): +def get_switchport_config_commands(interface, existing, proposed, module): """Gets commands required to config a given switchport interface """ @@ -323,14 +332,17 @@ def get_switchport_config_commands(interface, existing, proposed): elif proposed_mode == 'trunk': tv_check = existing.get('trunk_vlans_list') == proposed.get('trunk_vlans_list') if not tv_check: - vlans_to_add = False - for vlan in proposed.get('trunk_vlans_list'): - if vlan not in existing.get('trunk_vlans_list'): - vlans_to_add = True - break - if vlans_to_add: - command = 'switchport trunk allowed vlan add {0}'.format(proposed.get('trunk_vlans')) + # module.exit_json(aaaa=existing, tvtv=tv_check, pr=proposed) + if proposed.get('allowed'): + command = 'switchport trunk allowed vlan {0}'.format(proposed.get('trunk_allowed_vlans')) commands.append(command) + else: + existing_vlans = existing.get('trunk_vlans_list') + proposed_vlans = proposed.get('trunk_vlans_list') + vlans_to_add = set(proposed_vlans).difference(existing_vlans) + if vlans_to_add: + command = 'switchport trunk allowed vlan add {0}'.format(proposed.get('trunk_vlans')) + commands.append(command) native_check = existing.get( 'native_vlan') == proposed.get('native_vlan') @@ -440,8 +452,7 @@ def apply_value_map(value_map, resource): def execute_config_command(commands, module): try: module.configure(commands) - except ShellError: - clie = get_exception() + except ShellError, clie: module.fail_json(msg='Error sending CLI commands', error=str(clie), commands=commands) @@ -470,8 +481,7 @@ def execute_show(cmds, module, command_type=None): response = module.execute(cmds, command_type=command_type) else: response = module.execute(cmds) - except ShellError: - clie = get_exception() + except ShellError, clie: module.fail_json(msg='Error sending {0}'.format(command), error=str(clie)) return response @@ -508,13 +518,15 @@ def main(): mode=dict(choices=['access', 'trunk'], required=False), access_vlan=dict(type='str', required=False), native_vlan=dict(type='str', required=False), - trunk_vlans=dict(type='str', required=False), + trunk_vlans=dict(type='str', aliases=['trunk_add_vlans'], required=False), + trunk_allowed_vlans=dict(type='str', required=False), state=dict(choices=['absent', 'present', 'unconfigured'], default='present') ) module = get_module(argument_spec=argument_spec, mutually_exclusive=[['access_vlan', 'trunk_vlans'], - ['access_vlan', 'native_vlan']], + ['access_vlan', 'native_vlan'], + ['access_vlan', 'trunk_allowed_vlans']], supports_check_mode=True) interface = module.params['interface'] @@ -523,9 +535,11 @@ def main(): state = module.params['state'] trunk_vlans = module.params['trunk_vlans'] native_vlan = module.params['native_vlan'] + trunk_allowed_vlans = module.params['trunk_allowed_vlans'] args = dict(interface=interface, mode=mode, access_vlan=access_vlan, - native_vlan=native_vlan, trunk_vlans=trunk_vlans) + native_vlan=native_vlan, trunk_vlans=trunk_vlans, + trunk_allowed_vlans=trunk_allowed_vlans) proposed = dict((k, v) for k, v in args.iteritems() if v is not None) @@ -572,8 +586,12 @@ def main(): ' on an interface that\ndoes not exist on the ' ' switch yet!', vlan=native_vlan) - if trunk_vlans: - trunk_vlans_list = vlan_range_to_list(trunk_vlans) + if trunk_vlans or trunk_allowed_vlans: + if trunk_vlans: + trunk_vlans_list = vlan_range_to_list(trunk_vlans) + elif trunk_allowed_vlans: + trunk_vlans_list = vlan_range_to_list(trunk_allowed_vlans) + proposed['allowed'] = True existing_trunks_list = vlan_range_to_list( (existing['trunk_vlans']) @@ -585,9 +603,9 @@ def main(): changed = False commands = [] - if state == 'present': - command = get_switchport_config_commands(interface, existing, proposed) + # module.exit_json(ex=existing, pr=proposed) + command = get_switchport_config_commands(interface, existing, proposed, module) commands.append(command) elif state == 'unconfigured': is_default = is_switchport_default(existing) @@ -595,11 +613,11 @@ def main(): command = default_switchport_config(interface) commands.append(command) elif state == 'absent': - command = remove_switchport_config_commands(interface, - existing, proposed) + command = remove_switchport_config_commands(interface, existing, + proposed, module) commands.append(command) - if trunk_vlans: + if trunk_vlans or trunk_allowed_vlans: existing.pop('trunk_vlans_list') proposed.pop('trunk_vlans_list') @@ -632,4 +650,4 @@ from ansible.module_utils.netcfg import * from ansible.module_utils.nxos import * if __name__ == '__main__': - main() + main() \ No newline at end of file From b8f6e130ed2d15370a26ea947726634692890ac2 Mon Sep 17 00:00:00 2001 From: Jason Edelman Date: Wed, 17 Aug 2016 19:15:25 -0400 Subject: [PATCH 2/7] fixed docs --- network/nxos/nxos_switchport.py | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/network/nxos/nxos_switchport.py b/network/nxos/nxos_switchport.py index 684b287c6ff..b4204ea3209 100644 --- a/network/nxos/nxos_switchport.py +++ b/network/nxos/nxos_switchport.py @@ -18,7 +18,6 @@ DOCUMENTATION = ''' --- - module: nxos_switchport version_added: "2.1" short_description: Manages Layer 2 switchport interfaces @@ -27,47 +26,40 @@ description: - Manages Layer 2 interfaces author: Jason Edelman (@jedelman8) notes: - - When state=absent, vlans can be added/removed from trunk links and - the existing access vlan can be 'unconfigured' to just having VLAN 1 + - When C(state=absent), VLANs can be added/removed from trunk links and + the existing access VLAN can be 'unconfigured' to just having VLAN 1 on that interface - When working with trunks VLANs the keywords add/remove are always sent in the `switchport trunk allowed vlan` command. Use verbose mode to see commands sent. - - When state=unconfigured, the interface will result with having a default + - When C(state=unconfigured), the interface will result with having a default Layer 2 interface, i.e. vlan 1 in access mode options: interface: description: - - Full name of the interface, i.e. Ethernet1/1 + - Full name of the interface, i.e. Ethernet1/1. required: true default: null mode: description: - - Mode for the Layer 2 port + - Mode for the Layer 2 port. required: false default: null choices: ['access','trunk'] access_vlan: description: - - if mode=access, used as the access vlan id + - If C(mode=access), used as the access VLAN ID. required: false default: null native_vlan: description: - - if mode=trunk, used as the trunk native vlan id + - If C(mode=trunk), used as the trunk native VLAN ID. required: false default: null trunk_vlans: description: - - if mode=trunk, used as the vlan range to ADD or REMOVE - from the trunk - required: false - aliases: trunk_add_vlans - default: null - trunk_allowed_vlans: - description: - - if mode=trunk, these are the only VLANs that should be - configured on the trunk + - If C(mode=trunk), used as the VLAN range to ADD or REMOVE + from the trunk. required: false default: null state: @@ -76,6 +68,12 @@ options: required: false default: present choices: ['present','absent', 'unconfigured'] + trunk_allowed_vlans: + description: + - if mode=trunk, these are the only VLANs that should be + configured on the trunk + required: false + default: null ''' EXAMPLES = ''' From 996a34fbf7901930f3aa83adbcd4d19a6e728736 Mon Sep 17 00:00:00 2001 From: Jason Edelman Date: Wed, 17 Aug 2016 19:19:07 -0400 Subject: [PATCH 3/7] fixed error handling --- network/nxos/nxos_switchport.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/network/nxos/nxos_switchport.py b/network/nxos/nxos_switchport.py index b4204ea3209..e8292260d2b 100644 --- a/network/nxos/nxos_switchport.py +++ b/network/nxos/nxos_switchport.py @@ -450,7 +450,8 @@ def apply_value_map(value_map, resource): def execute_config_command(commands, module): try: module.configure(commands) - except ShellError, clie: + except ShellError: + clie = get_exception() module.fail_json(msg='Error sending CLI commands', error=str(clie), commands=commands) @@ -479,7 +480,8 @@ def execute_show(cmds, module, command_type=None): response = module.execute(cmds, command_type=command_type) else: response = module.execute(cmds) - except ShellError, clie: + except ShellError: + clie = get_exception() module.fail_json(msg='Error sending {0}'.format(command), error=str(clie)) return response From c009fe7e6618a5d90bd3c24ff952027e1228e80f Mon Sep 17 00:00:00 2001 From: Jason Edelman Date: Wed, 17 Aug 2016 19:43:32 -0400 Subject: [PATCH 4/7] updated version_added for new param --- network/nxos/nxos_switchport.py | 1 + 1 file changed, 1 insertion(+) diff --git a/network/nxos/nxos_switchport.py b/network/nxos/nxos_switchport.py index e8292260d2b..558d1c22ae7 100644 --- a/network/nxos/nxos_switchport.py +++ b/network/nxos/nxos_switchport.py @@ -73,6 +73,7 @@ options: - if mode=trunk, these are the only VLANs that should be configured on the trunk required: false + version_added: 2.2 default: null ''' From 164021a6a828aeb540ad35b83f2b1c952c82078c Mon Sep 17 00:00:00 2001 From: Jason Edelman Date: Thu, 18 Aug 2016 06:53:04 -0400 Subject: [PATCH 5/7] remove commented out code, add alias, and doc --- network/nxos/nxos_switchport.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/network/nxos/nxos_switchport.py b/network/nxos/nxos_switchport.py index 558d1c22ae7..f9561021b5e 100644 --- a/network/nxos/nxos_switchport.py +++ b/network/nxos/nxos_switchport.py @@ -60,6 +60,7 @@ options: description: - If C(mode=trunk), used as the VLAN range to ADD or REMOVE from the trunk. + aliases: trunk_add_vlans required: false default: null state: @@ -70,8 +71,8 @@ options: choices: ['present','absent', 'unconfigured'] trunk_allowed_vlans: description: - - if mode=trunk, these are the only VLANs that should be - configured on the trunk + - if C(mode=trunk), these are the only VLANs that will be + configured on the trunk, i.e. "2-10,15" required: false version_added: 2.2 default: null @@ -289,7 +290,6 @@ def remove_switchport_config_commands(interface, existing, proposed, module): existing_vlans = existing.get('trunk_vlans_list') proposed_vlans = proposed.get('trunk_vlans_list') vlans_to_remove = set(proposed_vlans).intersection(existing_vlans) - # module.exit_json(ex=existing, pr=proposed, vlans_to_remove=list(vlans_to_remove)) if vlans_to_remove: command = 'switchport trunk allowed vlan remove {0}'.format( proposed.get('trunk_vlans', proposed.get('trunk_allowed_vlans'))) @@ -331,7 +331,6 @@ def get_switchport_config_commands(interface, existing, proposed, module): elif proposed_mode == 'trunk': tv_check = existing.get('trunk_vlans_list') == proposed.get('trunk_vlans_list') if not tv_check: - # module.exit_json(aaaa=existing, tvtv=tv_check, pr=proposed) if proposed.get('allowed'): command = 'switchport trunk allowed vlan {0}'.format(proposed.get('trunk_allowed_vlans')) commands.append(command) @@ -605,7 +604,6 @@ def main(): commands = [] if state == 'present': - # module.exit_json(ex=existing, pr=proposed) command = get_switchport_config_commands(interface, existing, proposed, module) commands.append(command) elif state == 'unconfigured': From d49d61784f8963f54c5ec54f8dcc6554a6a475e8 Mon Sep 17 00:00:00 2001 From: Jason Edelman Date: Thu, 18 Aug 2016 07:00:19 -0400 Subject: [PATCH 6/7] make aliases a list in the docstring --- network/nxos/nxos_switchport.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/network/nxos/nxos_switchport.py b/network/nxos/nxos_switchport.py index f9561021b5e..dba6ac19a73 100644 --- a/network/nxos/nxos_switchport.py +++ b/network/nxos/nxos_switchport.py @@ -60,7 +60,8 @@ options: description: - If C(mode=trunk), used as the VLAN range to ADD or REMOVE from the trunk. - aliases: trunk_add_vlans + aliases: + - trunk_add_vlans required: false default: null state: From 5dc29dbc8b6f038eb9c31d962cb398107c208966 Mon Sep 17 00:00:00 2001 From: Jason Edelman Date: Thu, 18 Aug 2016 07:21:32 -0400 Subject: [PATCH 7/7] added a period --- network/nxos/nxos_switchport.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network/nxos/nxos_switchport.py b/network/nxos/nxos_switchport.py index dba6ac19a73..1f7f730a0d7 100644 --- a/network/nxos/nxos_switchport.py +++ b/network/nxos/nxos_switchport.py @@ -73,7 +73,7 @@ options: trunk_allowed_vlans: description: - if C(mode=trunk), these are the only VLANs that will be - configured on the trunk, i.e. "2-10,15" + configured on the trunk, i.e. "2-10,15". required: false version_added: 2.2 default: null