Repository: ansible/ansible

Issue:
eos_interface intent fails on eapi
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and devel branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest -->
 - Bug Report

##### COMPONENT NAME
<!---
Name of the module, plugin, task or feature
Do not include extra details here, e.g. "vyos_command" not "the network module vyos_command" or the full path
-->
eos_interface

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.6.0 (devel b12e90311f) last updated 2018/03/01 12:39:16 (GMT -400)
  config file = None
  configured module search path = [u'/Users/david/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/david/code/ansible/lib/ansible
  executable location = /Users/david/code/ansible/bin/ansible
  python version = 2.7.10 (default, Jul 15 2017, 17:16:57) [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)]
```

##### CONFIGURATION
<!---
If using Ansible 2.4 or above, paste the results of "ansible-config dump --only-changed"
Otherwise, mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say "N/A" for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->

##### SUMMARY
<!--- Explain the problem briefly -->
eos_interface produces a stack track when run using eapi

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->
`ansible-playbook -i eos.inv eos.yaml -vvvv`

<!--- Paste example playbooks or commands between quotes below -->
```yaml
---
- hosts: eos
  tasks:
  - name: Set test interface
    set_fact:
      test_interface_1: ethernet1

  - name: Check intent arguments
    eos_interface:
      name: "{{ test_interface_1 }}"
      state: up
      tx_rate: ge(0)
      rx_rate: ge(0)
      authorize: yes
      provider: "{{ eapi }}"
    register: result

```

group_vars/eos.yaml:
```yaml
ansible_connection: local
ansible_network_os: eos
ansible_user: PASSWORD
ansible_ssh_pass: USER
eapi:
  host: "{{ inventory_hostname }}"
  transport: eapi
  authorize: yes
  validate_certs: false
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
task should pass

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
```
TASK [Check intent arguments] **********************************************************************************
task path: /Users/david/code/test/eos.yaml:8
<eos02> connection transport is eapi
Using module file /Users/david/code/ansible/lib/ansible/modules/network/eos/eos_interface.py
<eos02> ESTABLISH LOCAL CONNECTION FOR USER: david
<eos02> EXEC /bin/sh -c 'echo ~ && sleep 0'
<eos02> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /Users/david/.ansible/tmp/ansible-tmp-1519930473.54-89724812253350 `" && echo ansible-tmp-1519930473.54-89724812253350="` echo /Users/david/.ansible/tmp/ansible-tmp-1519930473.54-89724812253350 `" ) && sleep 0'
<eos02> PUT /Users/david/.ansible/tmp/ansible-local-199917TML_E/tmpgccdUR TO /Users/david/.ansible/tmp/ansible-tmp-1519930473.54-89724812253350/eos_interface.py
<eos02> EXEC /bin/sh -c 'chmod u+x /Users/david/.ansible/tmp/ansible-tmp-1519930473.54-89724812253350/ /Users/david/.ansible/tmp/ansible-tmp-1519930473.54-89724812253350/eos_interface.py && sleep 0'
<eos02> EXEC /bin/sh -c '/usr/bin/python /Users/david/.ansible/tmp/ansible-tmp-1519930473.54-89724812253350/eos_interface.py && sleep 0'
<eos02> EXEC /bin/sh -c 'rm -f -r /Users/david/.ansible/tmp/ansible-tmp-1519930473.54-89724812253350/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
Traceback (most recent call last):
  File "/var/folders/x6/l9cfl1bs7x9_h9_v5sn94z640000gn/T/ansible_Glr2s3/ansible_module_eos_interface.py", line 466, in <module>
    main()
  File "/var/folders/x6/l9cfl1bs7x9_h9_v5sn94z640000gn/T/ansible_Glr2s3/ansible_module_eos_interface.py", line 456, in main
    failed_conditions = check_declarative_intent_params(module, want, result)
  File "/var/folders/x6/l9cfl1bs7x9_h9_v5sn94z640000gn/T/ansible_Glr2s3/ansible_module_eos_interface.py", line 337, in check_declarative_intent_params
    match = re.search(r'%s (\w+)' % 'line protocol is', output[0], re.M)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/re.py", line 146, in search
    return _compile(pattern, flags).search(string)
TypeError: expected string or buffer

fatal: [eos02]: FAILED! => {
    "changed": false,
    "module_stderr": "Traceback (most recent call last):\n  File \"/var/folders/x6/l9cfl1bs7x9_h9_v5sn94z640000gn/T/ansible_Glr2s3/ansible_module_eos_interface.py\", line 466, in <module>\n    main()\n  File \"/var/folders/x6/l9cfl1bs7x9_h9_v5sn94z640000gn/T/ansible_Glr2s3/ansible_module_eos_interface.py\", line 456, in main\n    failed_conditions = check_declarative_intent_params(module, want, result)\n  File \"/var/folders/x6/l9cfl1bs7x9_h9_v5sn94z640000gn/T/ansible_Glr2s3/ansible_module_eos_interface.py\", line 337, in check_declarative_intent_params\n    match = re.search(r'%s (\\w+)' % 'line protocol is', output[0], re.M)\n  File \"/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/re.py\", line 146, in search\n    return _compile(pattern, flags).search(string)\nTypeError: expected string or buffer\n",
    "module_stdout": "",
    "msg": "MODULE FAILURE",
    "rc": 1
}

```
<!--- Paste verbatim command output between quotes below -->



Discussion:
Files identified in the description:
* [lib/ansible/modules/network/eos/eos_interface.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/network/eos/eos_interface.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @ganeshrn @privateip @trishnaguha
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/network/eos/eos_interface.py b/lib/ansible/modules/network/eos/eos_interface.py
--- a/lib/ansible/modules/network/eos/eos_interface.py
+++ b/lib/ansible/modules/network/eos/eos_interface.py
@@ -330,7 +330,7 @@ def check_declarative_intent_params(module, want, result):
         if result['changed']:
             sleep(w['delay'])
 
-        command = 'show interfaces %s' % w['name']
+        command = {'command': 'show interfaces %s' % w['name'], 'output': 'text'}
         output = run_commands(module, [command])
 
         if want_state in ('up', 'down'):
@@ -363,7 +363,8 @@ def check_declarative_intent_params(module, want, result):
             have_host = []
             have_port = []
             if have_neighbors is None:
-                have_neighbors = run_commands(module, ['show lldp neighbors {}'.format(w['name'])])
+                command = {'command': 'show lldp neighbors {}'.format(w['name']), 'output': 'text'}
+                have_neighbors = run_commands(module, [command])
 
             if have_neighbors[0]:
                 lines = have_neighbors[0].strip().split('\n')
diff --git a/lib/ansible/modules/network/eos/eos_lldp.py b/lib/ansible/modules/network/eos/eos_lldp.py
--- a/lib/ansible/modules/network/eos/eos_lldp.py
+++ b/lib/ansible/modules/network/eos/eos_lldp.py
@@ -58,10 +58,10 @@
 
 
 def has_lldp(module):
-    output = run_commands(module, ['show lldp'])
+    config = get_config(module, flags=['| section lldp'])
 
     is_lldp_enable = False
-    if len(output) > 0 and "LLDP is not enabled" not in output[0]:
+    if "no lldp run" not in config:
         is_lldp_enable = True
 
     return is_lldp_enable


Test patch:
diff --git a/test/integration/targets/eos_facts/tests/eapi/all_facts.yaml b/test/integration/targets/eos_facts/tests/eapi/all_facts.yaml
--- a/test/integration/targets/eos_facts/tests/eapi/all_facts.yaml
+++ b/test/integration/targets/eos_facts/tests/eapi/all_facts.yaml
@@ -1,6 +1,11 @@
 ---
 - debug: msg="START eapi/all_facts.yaml"
 
+- name: Make sure LLDP is running (setup)
+  eos_config:
+    lines: lldp run
+    authorize: yes
+    provider: "{{ eapi }}"
 
 - name: test getting all facts
   eos_facts:
@@ -9,8 +14,6 @@
       - all
   register: result
 
-
-
 - assert:
     that:
       # _facts modules should never report a change
@@ -28,4 +31,10 @@
       - "result.ansible_facts.ansible_net_memfree_mb > 1"
       - "result.ansible_facts.ansible_net_memtotal_mb > 1"
 
+- name: Make sure LLDP is running (teardown)
+  eos_config:
+    lines: no lldp run
+    authorize: yes
+    provider: "{{ eapi }}"
+
 - debug: msg="END eapi/all_facts.yaml"
diff --git a/test/integration/targets/eos_interface/tests/eapi/intent.yaml b/test/integration/targets/eos_interface/tests/eapi/intent.yaml
--- a/test/integration/targets/eos_interface/tests/eapi/intent.yaml
+++ b/test/integration/targets/eos_interface/tests/eapi/intent.yaml
@@ -6,6 +6,13 @@
     test_interface_1: ethernet1
     test_interface_2: ethernet2
 
+- name: Make sure LLDP is running
+  eos_config:
+    lines: lldp run
+    authorize: yes
+    provider: "{{ eapi }}"
+  become: yes
+
 - name: Check intent arguments
   eos_interface:
     name: "{{ test_interface_1 }}"
@@ -159,3 +166,9 @@
           - "'host dummy_host' in result.failed_conditions"
           - "'port dummy_port' in result.failed_conditions"
   when: "'an-vyos-02' in show_lldp_neighbors_result.stdout[0]"
+
+- name: Make sure LLDP is running (teardown)
+  eos_config:
+    lines: no lldp run
+    authorize: yes
+    provider: "{{ eapi }}"
diff --git a/test/integration/targets/eos_l3_interface/tests/cli/basic.yaml b/test/integration/targets/eos_l3_interface/tests/cli/basic.yaml
--- a/test/integration/targets/eos_l3_interface/tests/cli/basic.yaml
+++ b/test/integration/targets/eos_l3_interface/tests/cli/basic.yaml
@@ -18,7 +18,7 @@
 - name: Configure interface ipv4 address
   eos_l3_interface:
     name: "{{ test_interface_1 }}"
-    ipv4: 192.108.0.1/24
+    ipv4: 192.108.1.1/24
     state: present
     authorize: yes
     provider: "{{ cli }}"
@@ -29,12 +29,12 @@
     that:
       - 'result.changed == true'
       - '"interface {{ test_interface_1 }}" in result.commands'
-      - '"ip address 192.108.0.1/24" in result.commands'
+      - '"ip address 192.108.1.1/24" in result.commands'
 
 - name: Configure interface ipv4 address (idempotent)
   eos_l3_interface:
     name: "{{ test_interface_1 }}"
-    ipv4: 192.108.0.1/24
+    ipv4: 192.108.1.1/24
     state: present
     authorize: yes
     provider: "{{ cli }}"
@@ -144,8 +144,8 @@
 - name: Configure ipv4 and ipv6 address using aggregate
   eos_l3_interface:
     aggregate:
-    - { name: "{{ test_interface_1 }}", ipv4: 192.108.0.1/24, ipv6: "fd5d:12c9:2201:2::2/64" }
-    - { name: "{{ test_interface_2 }}", ipv4: 192.109.0.2/16, ipv6: "fd5e:12c9:2201:3::3/32" }
+    - { name: "{{ test_interface_1 }}", ipv4: 192.108.1.1/24, ipv6: "fd5d:12c9:2201:2::2/64" }
+    - { name: "{{ test_interface_2 }}", ipv4: 192.109.1.2/16, ipv6: "fd5e:12c9:2201:3::3/32" }
     authorize: yes
     provider: "{{ cli }}"
   become: yes
@@ -155,17 +155,17 @@
     that:
       - 'result.changed == true'
       - '"interface {{ test_interface_1 }}" in result.commands'
-      - '"ip address 192.108.0.1/24" in result.commands'
+      - '"ip address 192.108.1.1/24" in result.commands'
       - '"ipv6 address fd5d:12c9:2201:2::2/64" in result.commands'
       - '"interface {{ test_interface_2 }}" in result.commands'
-      - '"ip address 192.109.0.2/16" in result.commands'
+      - '"ip address 192.109.1.2/16" in result.commands'
       - '"ipv6 address fd5e:12c9:2201:3::3/32" in result.commands'
 
 - name:  Configure ipv4 and ipv6 address using aggregate (idempotent)
   eos_l3_interface:
     aggregate:
-    - { name: "{{ test_interface_1 }}", ipv4: 192.108.0.1/24, ipv6: "fd5d:12c9:2201:2::2/64" }
-    - { name: "{{ test_interface_2 }}", ipv4: 192.109.0.2/16, ipv6: "fd5e:12c9:2201:3::3/32" }
+    - { name: "{{ test_interface_1 }}", ipv4: 192.108.1.1/24, ipv6: "fd5d:12c9:2201:2::2/64" }
+    - { name: "{{ test_interface_2 }}", ipv4: 192.109.1.2/16, ipv6: "fd5e:12c9:2201:3::3/32" }
     authorize: yes
     provider: "{{ cli }}"
   become: yes
diff --git a/test/integration/targets/eos_l3_interface/tests/eapi/basic.yaml b/test/integration/targets/eos_l3_interface/tests/eapi/basic.yaml
--- a/test/integration/targets/eos_l3_interface/tests/eapi/basic.yaml
+++ b/test/integration/targets/eos_l3_interface/tests/eapi/basic.yaml
@@ -17,7 +17,7 @@
 - name: Configure interface ipv4 address
   eos_l3_interface:
     name: "{{ test_interface_1 }}"
-    ipv4: 192.168.0.1/24
+    ipv4: 192.168.1.1/24
     state: present
     authorize: yes
     provider: "{{ eapi }}"
@@ -27,12 +27,12 @@
     that:
       - 'result.changed == true'
       - '"interface {{ test_interface_1 }}" in result.commands'
-      - '"ip address 192.168.0.1/24" in result.commands'
+      - '"ip address 192.168.1.1/24" in result.commands'
 
 - name: Configure interface ipv4 address (idempotent)
   eos_l3_interface:
     name: "{{ test_interface_1 }}"
-    ipv4: 192.168.0.1/24
+    ipv4: 192.168.1.1/24
     state: present
     authorize: yes
     provider: "{{ eapi }}"