From c5fb4bbcc0db5a937204b3c471481b4e3f70e8cb Mon Sep 17 00:00:00 2001 From: Trishna Guha Date: Thu, 6 Jul 2017 18:58:36 +0530 Subject: [PATCH] Fix nxos_switchport and unit test (#26131) * fix nxos_switchport Signed-off-by: Trishna Guha * nxos_switchport unit test Signed-off-by: Trishna Guha * legacy file * update unit test * handle exception --- .../modules/network/nxos/nxos_switchport.py | 293 ++++++++---------- test/sanity/pep8/legacy-files.txt | 1 - .../nxos_switchport/show_interface_ethernet | 97 ++++++ .../show_interface_ethernet_switchport | 14 + .../nxos/fixtures/nxos_switchport/show_vlan | 18 ++ .../network/nxos/test_nxos_switchport.py | 74 +++++ 6 files changed, 327 insertions(+), 170 deletions(-) create mode 100644 test/units/modules/network/nxos/fixtures/nxos_switchport/show_interface_ethernet create mode 100644 test/units/modules/network/nxos/fixtures/nxos_switchport/show_interface_ethernet_switchport create mode 100644 test/units/modules/network/nxos/fixtures/nxos_switchport/show_vlan create mode 100644 test/units/modules/network/nxos/test_nxos_switchport.py diff --git a/lib/ansible/modules/network/nxos/nxos_switchport.py b/lib/ansible/modules/network/nxos/nxos_switchport.py index 3fc3837394..a629370d58 100644 --- a/lib/ansible/modules/network/nxos/nxos_switchport.py +++ b/lib/ansible/modules/network/nxos/nxos_switchport.py @@ -16,10 +16,10 @@ # along with Ansible. If not, see . # -ANSIBLE_METADATA = {'metadata_version': '1.0', - 'status': ['preview'], - 'supported_by': 'community'} - +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'status': ['preview'], + 'supported_by': 'community'} DOCUMENTATION = ''' --- @@ -28,74 +28,73 @@ extends_documentation_fragment: nxos version_added: "2.1" short_description: Manages Layer 2 switchport interfaces. description: - - Manages Layer 2 interfaces + - 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 - 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 - Layer 2 interface, i.e. vlan 1 in access mode. + - 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 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. - required: true - default: null - mode: - description: - - 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. - required: false - default: null - native_vlan: - description: - - If C(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. - aliases: - - trunk_add_vlans - required: false - default: null - state: - description: - - Manage the state of the resource. - required: false - default: present - choices: ['present','absent', 'unconfigured'] - 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". - required: false - version_added: 2.2 - default: null + interface: + description: + - Full name of the interface, i.e. Ethernet1/1. + required: true + default: null + mode: + description: + - 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. + required: false + default: null + native_vlan: + description: + - If C(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. + aliases: + - trunk_add_vlans + required: false + default: null + state: + description: + - Manage the state of the resource. + required: false + default: present + choices: ['present','absent', 'unconfigured'] + 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". + required: false + version_added: 2.2 + default: null ''' + EXAMPLES = ''' - name: Ensure Eth1/5 is in its default switchport state nxos_switchport: interface: eth1/5 state: unconfigured - host: "{{ inventory_hostname }}" - name: Ensure Eth1/5 is configured for access vlan 20 nxos_switchport: interface: eth1/5 mode: access access_vlan: 20 - host: "{{ inventory_hostname }}" - name: Ensure Eth1/5 only has vlans 5-10 as trunk vlans nxos_switchport: @@ -103,7 +102,6 @@ EXAMPLES = ''' mode: trunk native_vlan: 10 trunk_vlans: 5-10 - host: "{{ inventory_hostname }}" - name: 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: @@ -111,59 +109,28 @@ EXAMPLES = ''' mode: trunk native_vlan: 10 trunk_vlans: 2-50 - host: "{{ inventory_hostname }}" - name: Ensure these VLANs are not being tagged on the trunk nxos_switchport: interface: eth1/5 mode: trunk trunk_vlans: 51-4094 - host: "{{ inventory_hostname }} " state: absent ''' RETURN = ''' -proposed: - description: k/v pairs of parameters passed into module - returned: always - type: dict - sample: {"access_vlan": "10", "interface": "eth1/5", "mode": "access"} -existing: - description: k/v pairs of existing switchport - returned: always - type: dict - sample: {"access_vlan": "10", "access_vlan_name": "VLAN0010", - "interface": "Ethernet1/5", "mode": "access", - "native_vlan": "1", "native_vlan_name": "default", - "switchport": "Enabled", "trunk_vlans": "1-4094"} -end_state: - description: k/v pairs of switchport after module execution - returned: always - type: dict - sample: {"access_vlan": "10", "access_vlan_name": "VLAN0010", - "interface": "Ethernet1/5", "mode": "access", - "native_vlan": "1", "native_vlan_name": "default", - "switchport": "Enabled", "trunk_vlans": "1-4094"} -updates: +commands: description: command string sent to the device returned: always type: list sample: ["interface eth1/5", "switchport access vlan 20"] -changed: - description: check to see if a change was made on the device - returned: always - type: boolean - sample: true ''' -from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import load_config, run_commands from ansible.module_utils.nxos import nxos_argument_spec, check_args from ansible.module_utils.basic import AnsibleModule -import re -import re - def get_interface_type(interface): """Gets the type of interface Args: @@ -201,12 +168,12 @@ def get_interface_mode(interface, module): """ command = 'show interface ' + interface intf_type = get_interface_type(interface) - body = execute_show_command(command, module) mode = 'unknown' interface_table = {} try: - interface_table = body[0]['TABLE_interface']['ROW_interface'] + body = execute_show_command(command, module)[0] + interface_table = body['TABLE_interface']['ROW_interface'] except (KeyError, AttributeError, IndexError): return mode @@ -231,11 +198,12 @@ def interface_is_portchannel(interface, module): True/False based on if interface is a member of a portchannel bundle """ intf_type = get_interface_type(interface) + if intf_type == 'ethernet': command = 'show interface ' + interface - body = execute_show_command(command, module) try: - interface_table = body[0]['TABLE_interface']['ROW_interface'] + body = execute_show_command(command, module)[0] + interface_table = body['TABLE_interface']['ROW_interface'] except (KeyError, AttributeError, IndexError): interface_table = None @@ -261,14 +229,13 @@ def get_switchport(port, module): command = 'show interface {0} switchport'.format(port) - body = execute_show_command(command, module) - try: body = execute_show_command(command, module)[0] - except IndexError: - body = [] + sp_table = body['TABLE_interface']['ROW_interface'] + except (KeyError, AttributeError, IndexError): + sp_table = None - if body: + if sp_table: key_map = { "interface": "interface", "oper_mode": "mode", @@ -279,12 +246,9 @@ def get_switchport(port, module): "native_vlan_name": "native_vlan_name", "trunk_vlans": "trunk_vlans" } - - sp_table = body['TABLE_interface']['ROW_interface'] - sp = apply_key_map(key_map, sp_table) - return sp + else: return {} @@ -293,28 +257,32 @@ def remove_switchport_config_commands(interface, existing, proposed, module): mode = proposed.get('mode') commands = [] command = None + if mode == 'access': av_check = existing.get('access_vlan') == proposed.get('access_vlan') if av_check: - command = 'no switchport access vlan {0}'.format( - existing.get('access_vlan')) + command = 'no switchport access vlan {0}'.format(existing.get('access_vlan')) commands.append(command) + elif mode == 'trunk': tv_check = existing.get('trunk_vlans_list') == proposed.get('trunk_vlans_list') + if not tv_check: existing_vlans = existing.get('trunk_vlans_list') proposed_vlans = proposed.get('trunk_vlans_list') vlans_to_remove = set(proposed_vlans).intersection(existing_vlans) + if vlans_to_remove: - command = 'switchport trunk allowed vlan remove {0}'.format( - proposed.get('trunk_vlans', proposed.get('trunk_allowed_vlans'))) + proposed_allowed_vlans = proposed.get('trunk_allowed_vlans') + remove_trunk_allowed_vlans = proposed.get('trunk_vlans', proposed_allowed_vlans) + command = 'switchport trunk allowed vlan remove {0}'.format(remove_trunk_allowed_vlans) commands.append(command) - native_check = existing.get( - 'native_vlan') == proposed.get('native_vlan') + + native_check = existing.get('native_vlan') == proposed.get('native_vlan') if native_check and proposed.get('native_vlan'): - command = 'no switchport trunk native vlan {0}'.format( - existing.get('native_vlan')) + command = 'no switchport trunk native vlan {0}'.format(existing.get('native_vlan')) commands.append(command) + if commands: commands.insert(0, 'interface ' + interface) return commands @@ -326,29 +294,32 @@ def get_switchport_config_commands(interface, existing, proposed, module): proposed_mode = proposed.get('mode') existing_mode = existing.get('mode') - commands = [] command = None + if proposed_mode != existing_mode: if proposed_mode == 'trunk': command = 'switchport mode trunk' elif proposed_mode == 'access': command = 'switchport mode access' + if command: commands.append(command) if proposed_mode == 'access': av_check = existing.get('access_vlan') == proposed.get('access_vlan') if not av_check: - command = 'switchport access vlan {0}'.format( - proposed.get('access_vlan')) + command = 'switchport access vlan {0}'.format(proposed.get('access_vlan')) commands.append(command) + elif proposed_mode == 'trunk': tv_check = existing.get('trunk_vlans_list') == proposed.get('trunk_vlans_list') + if not tv_check: 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') @@ -357,12 +328,11 @@ def get_switchport_config_commands(interface, existing, proposed, module): 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') + native_check = existing.get('native_vlan') == proposed.get('native_vlan') if not native_check and proposed.get('native_vlan'): - command = 'switchport trunk native vlan {0}'.format( - proposed.get('native_vlan')) + command = 'switchport trunk native vlan {0}'.format(proposed.get('native_vlan')) commands.append(command) + if commands: commands.insert(0, 'interface ' + interface) return commands @@ -417,9 +387,13 @@ def vlan_range_to_list(vlans): def get_list_of_vlans(module): command = 'show vlan' - body = execute_show_command(command, module) vlan_list = [] - vlan_table = body[0].get('TABLE_vlanbrief')['ROW_vlanbrief'] + + try: + body = execute_show_command(command, module)[0] + vlan_table = body['TABLE_vlanbrief']['ROW_vlanbrief'] + except (KeyError, AttributeError, IndexError): + return [] if isinstance(vlan_table, list): for vlan in vlan_table: @@ -449,7 +423,7 @@ def apply_key_map(key_map, table): for key, value in table.items(): new_key = key_map.get(key) if new_key: - new_dict[new_key] = str(value) + new_dict[new_key] = value return new_dict @@ -461,8 +435,7 @@ def apply_value_map(value_map, resource): def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': - if 'status' not in command: - command += ' | json' + command += ' | json' cmds = [command] body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': @@ -491,22 +464,22 @@ def main(): native_vlan=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') + state=dict(choices=['absent', 'present', 'unconfigured'], default='present') ) argument_spec.update(nxos_argument_spec) module = AnsibleModule(argument_spec=argument_spec, - mutually_exclusive=[['access_vlan', 'trunk_vlans'], - ['access_vlan', 'native_vlan'], - ['access_vlan', 'trunk_allowed_vlans']], - supports_check_mode=True) + mutually_exclusive=[['access_vlan', 'trunk_vlans'], + ['access_vlan', 'native_vlan'], + ['access_vlan', 'trunk_allowed_vlans']], + supports_check_mode=True) warnings = list() + commands = [] + results = {'changed': False} check_args(module, warnings) - interface = module.params['interface'] mode = module.params['mode'] access_vlan = module.params['access_vlan'] @@ -524,12 +497,10 @@ def main(): interface = interface.lower() if mode == 'access' and state == 'present' and not access_vlan: - module.fail_json(msg='access_vlan param is required when ' - 'mode=access && state=present') + module.fail_json(msg='access_vlan param is required when mode=access && state=present') if mode == 'trunk' and access_vlan: - module.fail_json(msg='access_vlan param not supported when ' - 'using mode=trunk') + module.fail_json(msg='access_vlan param not supported when using mode=trunk') current_mode = get_interface_mode(interface, module) @@ -552,6 +523,18 @@ def main(): if not existing: module.fail_json(msg='Make sure you are using the FULL interface name') + 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'])) + + existing['trunk_vlans_list'] = existing_trunks_list + proposed['trunk_vlans_list'] = trunk_vlans_list + current_vlans = get_list_of_vlans(module) if state == 'present': @@ -563,65 +546,37 @@ def main(): module.fail_json(msg='You are trying to configure a VLAN' ' on an interface that\ndoes not exist on the ' ' switch yet!', vlan=native_vlan) - - 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']) - ) - - existing['trunk_vlans_list'] = existing_trunks_list - proposed['trunk_vlans_list'] = trunk_vlans_list - - changed = False - - commands = [] - if state == 'present': - command = get_switchport_config_commands(interface, existing, proposed, module) - commands.append(command) + else: + command = get_switchport_config_commands(interface, existing, proposed, module) + commands.append(command) elif state == 'unconfigured': is_default = is_switchport_default(existing) if not is_default: command = default_switchport_config(interface) commands.append(command) elif state == 'absent': - command = remove_switchport_config_commands(interface, existing, - proposed, module) + command = remove_switchport_config_commands(interface, existing, proposed, module) commands.append(command) if trunk_vlans or trunk_allowed_vlans: existing.pop('trunk_vlans_list') proposed.pop('trunk_vlans_list') - end_state = existing - cmds = flatten_list(commands) if cmds: if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - changed = True + results['changed'] = True load_config(module, cmds) - end_state = get_switchport(interface, module) if 'configure' in cmds: cmds.pop(0) - results = {} - results['proposed'] = proposed - results['existing'] = existing - results['end_state'] = end_state - results['updates'] = cmds - results['changed'] = changed + results['commands'] = cmds results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() - diff --git a/test/sanity/pep8/legacy-files.txt b/test/sanity/pep8/legacy-files.txt index 425a976b41..8527486b28 100644 --- a/test/sanity/pep8/legacy-files.txt +++ b/test/sanity/pep8/legacy-files.txt @@ -378,7 +378,6 @@ lib/ansible/modules/network/nxos/nxos_snmp_location.py lib/ansible/modules/network/nxos/nxos_snmp_traps.py lib/ansible/modules/network/nxos/nxos_snmp_user.py lib/ansible/modules/network/nxos/nxos_static_route.py -lib/ansible/modules/network/nxos/nxos_switchport.py lib/ansible/modules/network/nxos/nxos_system.py lib/ansible/modules/network/nxos/nxos_udld.py lib/ansible/modules/network/nxos/nxos_udld_interface.py diff --git a/test/units/modules/network/nxos/fixtures/nxos_switchport/show_interface_ethernet b/test/units/modules/network/nxos/fixtures/nxos_switchport/show_interface_ethernet new file mode 100644 index 0000000000..60e729b2c3 --- /dev/null +++ b/test/units/modules/network/nxos/fixtures/nxos_switchport/show_interface_ethernet @@ -0,0 +1,97 @@ +{ + "TABLE_interface": { + "ROW_interface": { + "interface": "Ethernet2/1", + "state": "up", + "admin_state": "up", + "share_state": "Dedicated", + "eth_hw_desc": "Ethernet", + "eth_hw_addr": "fa16.3e00.0001", + "eth_bia_addr": "fa16.3e27.f279", + "desc": "to nxos03", + "eth_ip_addr": "10.0.0.45", + "eth_ip_mask": 30, + "eth_ip_prefix": "10.0.0.44", + "eth_mtu": "1500", + "eth_bw": 1000000, + "eth_dly": 10, + "eth_reliability": "255", + "eth_txload": "1", + "eth_rxload": "1", + "medium": "broadcast", + "eth_mode": "access", + "eth_bundle": 0, + "eth_duplex": "full", + "eth_speed": "1000 Mb/s", + "eth_beacon": "off", + "eth_autoneg": "off", + "eth_in_flowctrl": "off", + "eth_out_flowctrl": "off", + "eth_mdix": "off", + "eth_swt_monitor": "off", + "eth_ethertype": "0x8100", + "eth_eee_state": "n/a", + "eth_link_flapped": "13week(s) 0day(s)", + "eth_clear_counters": "never", + "eth_reset_cntr": 1, + "eth_load_interval1_rx": 0, + "eth_inrate1_bits": 0, + "eth_inrate1_pkts": 0, + "eth_load_interval1_tx": 0, + "eth_outrate1_bits": 0, + "eth_outrate1_pkts": 0, + "eth_inrate1_summary_bits": "0 bps", + "eth_inrate1_summary_pkts": "0 pps", + "eth_outrate1_summary_bits": "0 bps", + "eth_outrate1_summary_pkts": "0 pps", + "eth_load_interval2_rx": 0, + "eth_inrate2_bits": 0, + "eth_inrate2_pkts": 0, + "eth_load_interval2_tx": 0, + "eth_outrate2_bits": 0, + "eth_outrate2_pkts": 0, + "eth_inrate2_summary_bits": "0 bps", + "eth_inrate2_summary_pkts": "0 pps", + "eth_outrate2_summary_bits": "0 bps", + "eth_outrate2_summary_pkts": "0 pps", + "eth_inucast": 0, + "eth_inmcast": 0, + "eth_inbcast": 0, + "eth_inpkts": 0, + "eth_inbytes": 0, + "eth_jumbo_inpkts": 0, + "eth_storm_supp": 0, + "eth_runts": 0, + "eth_giants": 0, + "eth_crc": 0, + "eth_nobuf": 0, + "eth_inerr": 0, + "eth_frame": 0, + "eth_overrun": 0, + "eth_underrun": 0, + "eth_ignored": 0, + "eth_watchdog": 0, + "eth_bad_eth": 0, + "eth_bad_proto": 0, + "eth_in_ifdown_drops": 0, + "eth_dribble": 0, + "eth_indiscard": 0, + "eth_inpause": 0, + "eth_outucast": 0, + "eth_outmcast": 0, + "eth_outbcast": 0, + "eth_outpkts": 0, + "eth_outbytes": 0, + "eth_jumbo_outpkts": 0, + "eth_outerr": 0, + "eth_coll": 0, + "eth_deferred": 0, + "eth_latecoll": 0, + "eth_lostcarrier": 0, + "eth_nocarrier": 0, + "eth_babbles": 0, + "eth_outdiscard": 0, + "eth_outpause": 0 + } + } +} diff --git a/test/units/modules/network/nxos/fixtures/nxos_switchport/show_interface_ethernet_switchport b/test/units/modules/network/nxos/fixtures/nxos_switchport/show_interface_ethernet_switchport new file mode 100644 index 0000000000..352da5e7a3 --- /dev/null +++ b/test/units/modules/network/nxos/fixtures/nxos_switchport/show_interface_ethernet_switchport @@ -0,0 +1,14 @@ +{ + "TABLE_interface": { + "ROW_interface": { + "interface": "Ethernet2/1", + "oper_mode": "access", + "switchport": "Enabled", + "access_vlan": 2, + "access_vlan_name": "VLAN2", + "native_vlan": 10, + "native_vlan_name": "VLAN10", + "trunk_vlans": "1-50" + } + } +} diff --git a/test/units/modules/network/nxos/fixtures/nxos_switchport/show_vlan b/test/units/modules/network/nxos/fixtures/nxos_switchport/show_vlan new file mode 100644 index 0000000000..407267bb00 --- /dev/null +++ b/test/units/modules/network/nxos/fixtures/nxos_switchport/show_vlan @@ -0,0 +1,18 @@ +{ + "TABLE_vlanbrief": { + "ROW_vlanbrief": { + "vlanshowbr-vlanid": 1, + "vlanshowbr-vlanid-utf": 1, + "vlanshowbr-vlanname": "VLAN1", + "vlanshowbr-vlanstate": "active", + "vlanshowbr-shutstate": "noshutdown" + } + }, + "TABLE_mtuinfo": { + "ROW_mtuinfo": { + "vlanshowinfo-vlanid": 1, + "vlanshowinfo-media-type": "enet", + "vlanshowinfo-vlanmode": "ce-vlan" + } + } +} diff --git a/test/units/modules/network/nxos/test_nxos_switchport.py b/test/units/modules/network/nxos/test_nxos_switchport.py new file mode 100644 index 0000000000..de302f3ff4 --- /dev/null +++ b/test/units/modules/network/nxos/test_nxos_switchport.py @@ -0,0 +1,74 @@ +# (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 . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os + +from ansible.compat.tests.mock import patch +from ansible.modules.network.nxos import nxos_switchport +from .nxos_module import TestNxosModule, load_fixture, set_module_args + + +class TestNxosSwitchportModule(TestNxosModule): + + module = nxos_switchport + + def setUp(self): + self.mock_run_commands = patch('ansible.modules.network.nxos.nxos_switchport.run_commands') + self.run_commands = self.mock_run_commands.start() + + self.mock_load_config = patch('ansible.modules.network.nxos.nxos_switchport.load_config') + self.load_config = self.mock_load_config.start() + + def tearDown(self): + self.mock_run_commands.stop() + self.mock_load_config.stop() + + def load_fixtures(self, commands=None, device=''): + def load_from_file(*args, **kwargs): + module, commands = args + output = list() + for command in commands: + filename = str(command).split(' | ')[0].replace(' ', '_') + filename = filename.replace('2/1', '') + output.append(load_fixture('nxos_switchport', filename)) + return output + + self.run_commands.side_effect = load_from_file + self.load_config.return_value = None + + def test_nxos_switchport_present(self): + set_module_args(dict(interface='Ethernet2/1', mode='access', access_vlan=1, state='present')) + result = self.execute_module(changed=True) + self.assertEqual(result['commands'], ['interface ethernet2/1', 'switchport access vlan 1']) + + def test_nxos_switchport_unconfigured(self): + set_module_args(dict(interface='Ethernet2/1', state='unconfigured')) + result = self.execute_module(changed=True) + self.assertEqual(result['commands'], ['interface ethernet2/1', + 'switchport mode access', + 'switch access vlan 1', + 'switchport trunk native vlan 1', + 'switchport trunk allowed vlan all']) + + def test_nxos_switchport_absent(self): + set_module_args(dict(interface='Ethernet2/1', mode='access', access_vlan=3, state='absent')) + result = self.execute_module(changed=False) + self.assertEqual(result['commands'], [])