Repository: ansible/ansible
Pull request: Fixes #28779 eth_mode key error
##### SUMMARY
Fixes https://github.com/ansible/ansible/issues/28779

##### ISSUE TYPE
 - Bugfix Pull Request

##### COMPONENT NAME
nxos_interface

##### ANSIBLE VERSION
```
ansible 2.4.0 (240/fix_nxos_interface 319f685dd8) last updated 2017/08/29 11:45:53 (GMT -400)
  config file = None
  configured module search path = [u'/Users/mwiebe/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/mwiebe/Projects/nxos_ansible/fix_ansible/lib/ansible
  executable location = /Users/mwiebe/Projects/nxos_ansible/fix_ansible/bin/ansible
  python version = 2.7.13 (default, Apr  4 2017, 08:47:57) [GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.38)]
```


##### ADDITIONAL INFORMATION
This fix addresses the following:
  * Uses get to avoid the key error
  * Removes unused library and variable reference

**All tests pass with the fix:**


Problem statement:
nxos_interface errors out with KeyError: 'eth_mode' 
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
 - nxos_interface

##### NXOS VERSION
7.0(3)I2(5)

##### ANSIBLE VERSION
```
ansible 2.4.0 (devel 3251aecd95) last updated 2017/08/29 09:19:59 (GMT -400)
  config file = None
  configured module search path = [u'/Users/mwiebe/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/mwiebe/Projects/nxos_ansible/fix_ansible/lib/ansible
  executable location = /Users/mwiebe/Projects/nxos_ansible/fix_ansible/bin/ansible
  python version = 2.7.13 (default, Apr  4 2017, 08:47:57) [GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.38)]
```

##### OS / ENVIRONMENT
Ubuntu 14.04

##### SUMMARY
A check was added recently to indicate that interfaces with mode fex-fabric are not supported. The field that is checked for the setting may or may not be available depending on the state of the interface.  If it's not the following key error will be generated. 

```shell
TASK [nxos_interface : set state=absent] *******************************************************************************************************************************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: KeyError: 'eth_mode'
fatal: [n9k.example.com]: FAILED! => {"changed": false, "failed": true, "module_stderr": "Traceback (most recent call last):\n  File \"/var/folders/ww/538d42ys18l5tjyz0l1yk1rc0000gn/T/ansible_MBC73S/ansible_module_nxos_interface.py\", line 713, in <module>\n    main()\n  File \"/var/folders/ww/538d42ys18l5tjyz0l1yk1rc0000gn/T/ansible_MBC73S/ansible_module_nxos_interface.py\", line 639, in main\n    existing, is_default = smart_existing(module, intf_type, normalized_interface)\n  File \"/var/folders/ww/538d42ys18l5tjyz0l1yk1rc0000gn/T/ansible_MBC73S/ansible_module_nxos_interface.py\", line 535, in smart_existing\n    existing = get_interface(normalized_interface, module)\n  File \"/var/folders/ww/538d42ys18l5tjyz0l1yk1rc0000gn/T/ansible_MBC73S/ansible_module_nxos_interface.py\", line 283, in get_interface\n    if interface_table['eth_mode'] == 'fex-fabric':\nKeyError: 'eth_mode'\n", "module_stdout": "", "msg": "MODULE FAILURE", "rc": 0}
	to retry, use: --limit @/Users/mwiebe/Projects/nxos_ansible/fix_ansible/test/integration/nxos.retry
```

Hints from issue discussion:

Commit message: Fixes #28779 eth_mode key error

Patch to review:
diff --git a/lib/ansible/modules/network/nxos/nxos_interface.py b/lib/ansible/modules/network/nxos/nxos_interface.py
index c6c94e2d9aa4e1..294bb2d04938b6 100644
--- a/lib/ansible/modules/network/nxos/nxos_interface.py
+++ b/lib/ansible/modules/network/nxos/nxos_interface.py
@@ -141,7 +141,7 @@
     sample: ["interface port-channel101", "shutdown"]
 '''
 
-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
 
@@ -280,7 +280,7 @@ def get_interface(intf, module):
 
     if body:
         interface_table = body['TABLE_interface']['ROW_interface']
-        if interface_table['eth_mode'] == 'fex-fabric':
+        if interface_table.get('eth_mode') == 'fex-fabric':
             module.fail_json(msg='nxos_interface does not support interfaces with mode "fex-fabric"')
         intf_type = get_interface_type(intf)
         if intf_type in ['portchannel', 'ethernet']:
@@ -701,7 +701,7 @@ def main():
                 end_state, is_default = smart_existing(module, intf_type,
                                                        normalized_interface)
             else:
-                end_state = get_interfaces_dict(module)[interface_type]
+                get_interfaces_dict(module)[interface_type]
             cmds = [cmd for cmd in cmds if cmd != 'configure']
 
     results['commands'] = cmds


Code review comments:
diff_hunk: @@ -701,7 +701,7 @@ def main():
                 end_state, is_default = smart_existing(module, intf_type,
                                                        normalized_interface)
             else:
-                end_state = get_interfaces_dict(module)[interface_type]
+                get_interfaces_dict(module)[interface_type]
path: lib/ansible/modules/network/nxos/nxos_interface.py
text: @user1:
This function doesn't have any side effects, you should be able to just kill the whole else block.

@author:
Is this what you mean?
```python
            if module.params['interface']:
                if delta.get('mode'):
                    # if the mode changes from L2 to L3, the admin state
                    # seems to change after the API call, so adding a second API
                    # call to ensure it's in the desired state.
                    admin_state = delta.get('admin_state') or admin_state
                    c1 = 'interface {0}'.format(normalized_interface)
                    c2 = get_admin_state(delta, normalized_interface, admin_state)
                    cmds2 = [c1, c2]
                    load_config(module, cmds2)
                    cmds.extend(cmds2)
                end_state, is_default = smart_existing(module, intf_type,
                                                       normalized_interface)
            get_interfaces_dict(module)[interface_type]
            cmds = [cmd for cmd in cmds if cmd != 'configure']
```