Repository: ansible/ansible

Issue:
(P2) nxos_vrf_interface is not idempotent while removing and throws errors
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
nxos_vrf_interface

##### ANSIBLE VERSION
```
ansible 2.4.0 (devel 54cd641df4) last updated 2017/07/19 18:06:44 (GMT -400)
  config file = None
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /root/p2/Projects/nxos_ansible/p1_ansible/lib/ansible
  executable location = /root/p2/Projects/nxos_ansible/p1_ansible/bin/ansible
  python version = 2.7.6 (default, Oct 26 2016, 20:30:19) [GCC 4.8.4]
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
Ansible Server : Ubuntu 14.04
Device: NX-OSv9K running 7.0(3)I2(5)

##### SUMMARY
While deleting nxos_vrf_interface, it is not idempotent and throws error.

##### STEPS TO REPRODUCE
Playbook:

```
- block:
  - name: put interface in L3
    nxos_config:
      commands:
        - no switchport
      parents:
        - "interface ethernet1/1"
      match: none
      provider: "{{ cli }}"

  - name: Ensure vrf ntc exists on interface
    nxos_vrf_interface: &configure
      vrf: ntc
      interface: ethernet1/1
      state: present
      provider: "{{ cli }}"
    register: result

  - assert: &true
      that:
        - "result.changed == true"

  - name: "Conf Idempotence"
    nxos_vrf_interface: *configure
    register: result

  - assert: &false
      that:
        - "result.changed == false"

  - name: Ensure ntc VRF does not exist on interface
    nxos_vrf_interface: &remove
      vrf: ntc
      interface: ethernet1/1
      state: absent
      provider: "{{ cli }}"
    register: result

  - assert: *true

  - name: "Remove Idempotence"
    nxos_vrf_interface: *remove
    register: result

  - assert: *false

  always:
  - name: put interface in default mode
    nxos_config:
      lines: "default interface ethernet1/1"
      provider: "{{ cli }}"
      match: none
    ignore_errors: yes

```

##### EXPECTED RESULTS
```
PLAY RECAP ********************************************************************************************************************************************
n9k.example.com      : ok=22   changed=4    unreachable=0    failed=0
```
##### ACTUAL RESULTS
```
fatal: [n9k.example.com]: FAILED! => {"changed": false, "existing_vrf": "", "failed": true, "interface": "ethernet1/1", "msg": "The VRF you are trying to remove from the interface does not exist on that interface.", "proposed_vrf": "ntc"}
```



Discussion:
cc @GGabriele @jedelman8 @mikewiebe @privateip @rahushen @rcarrillocruz @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/nxos/nxos_vrf_interface.py b/lib/ansible/modules/network/nxos/nxos_vrf_interface.py
--- a/lib/ansible/modules/network/nxos/nxos_vrf_interface.py
+++ b/lib/ansible/modules/network/nxos/nxos_vrf_interface.py
@@ -222,7 +222,9 @@ def main():
     changed = False
     end_state = existing
 
-    if vrf != existing['vrf'] and state == 'absent':
+    if not existing['vrf']:
+        pass
+    elif vrf != existing['vrf'] and state == 'absent':
         module.fail_json(msg='The VRF you are trying to remove '
                              'from the interface does not exist '
                              'on that interface.',
diff --git a/lib/ansible/modules/network/nxos/nxos_vtp_password.py b/lib/ansible/modules/network/nxos/nxos_vtp_password.py
--- a/lib/ansible/modules/network/nxos/nxos_vtp_password.py
+++ b/lib/ansible/modules/network/nxos/nxos_vtp_password.py
@@ -215,7 +215,10 @@ def main():
 
     commands = []
     if state == 'absent':
-        if vtp_password is not None:
+        # if vtp_password is not set, some devices returns '\\'
+        if not existing['vtp_password'] or existing['vtp_password'] == '\\':
+            pass
+        elif vtp_password is not None:
             if existing['vtp_password'] == proposed['vtp_password']:
                 commands.append(['no vtp password'])
             else:


Test patch:
diff --git a/test/integration/targets/nxos_vrf_interface/tasks/main.yaml b/test/integration/targets/nxos_vrf_interface/tasks/main.yaml
--- a/test/integration/targets/nxos_vrf_interface/tasks/main.yaml
+++ b/test/integration/targets/nxos_vrf_interface/tasks/main.yaml
@@ -1,3 +1,7 @@
 ---
-- { include: cli.yaml, tags: ['cli'] }
-- { include: nxapi.yaml, tags: ['nxapi'] }
+# Use block to ensure that both cli and nxapi tests
+# will run even if there are failures or errors.
+- block:
+  - { include: cli.yaml, tags: ['cli'] }
+  always:
+  - { include: nxapi.yaml, tags: ['nxapi'] }
diff --git a/test/integration/targets/nxos_vrf_interface/tests/cli/sanity.yaml b/test/integration/targets/nxos_vrf_interface/tests/cli/sanity.yaml
--- a/test/integration/targets/nxos_vrf_interface/tests/cli/sanity.yaml
+++ b/test/integration/targets/nxos_vrf_interface/tests/cli/sanity.yaml
@@ -1,39 +1,4 @@
 ---
-- debug: msg="START TRANSPORT:CLI nxos_vrf_interface sanity test"
+- set_fact: connection="{{ cli }}"
 
-# Select interface for test
-- set_fact: intname="{{ nxos_int1 }}"
-
-- block:
-  - name: put interface in L3
-    nxos_config:
-      commands:
-        - no switchport
-      parents:
-        - "interface {{ intname }}"
-      match: none
-      provider: "{{ cli }}"
-
-  - name: Ensure vrf ntc exists on interface
-    nxos_vrf_interface:
-      vrf: ntc
-      interface: "{{ intname }}"
-      state: present
-      provider: "{{ cli }}"
-
-  - name: Ensure ntc VRF does not exist on interface
-    nxos_vrf_interface:
-      vrf: ntc
-      interface: "{{ intname }}"
-      state: absent
-      provider: "{{ cli }}"
-
-  always:
-  - name: put interface in default mode
-    nxos_config:
-      lines: "default interface {{ intname }}"
-      provider: "{{ cli }}"
-      match: none
-    ignore_errors: yes
-
-- debug: msg="END TRANSPORT:CLI nxos_vrf_interface sanity test"
+- import_tasks: targets/nxos_vrf_interface/tests/common/sanity.yaml
diff --git a/test/integration/targets/nxos_vrf_interface/tests/common/sanity.yaml b/test/integration/targets/nxos_vrf_interface/tests/common/sanity.yaml
new file mode 100644
--- /dev/null
+++ b/test/integration/targets/nxos_vrf_interface/tests/common/sanity.yaml
@@ -0,0 +1,61 @@
+---
+- debug: msg="START TRANSPORT:{{ connection.transport }} nxos_vrf_interface sanity test"
+
+# Select interface for test
+- set_fact: intname="{{ nxos_int1 }}"
+
+- block:
+  - name: put interface in L3
+    nxos_config:
+      commands:
+        - no switchport
+      parents:
+        - "interface {{ intname }}"
+      match: none
+      provider: "{{ connection }}"
+
+  - name: Ensure vrf ntc exists on interface
+    nxos_vrf_interface: &configure
+      vrf: ntc
+      interface: "{{ intname }}"
+      state: present
+      provider: "{{ connection }}"
+    register: result
+
+  - assert: &true
+      that:
+        - "result.changed == true"
+
+  - name: "Conf Idempotence"
+    nxos_vrf_interface: *configure
+    register: result
+
+  - assert: &false
+      that:
+        - "result.changed == false"
+
+  - name: Ensure ntc VRF does not exist on interface
+    nxos_vrf_interface: &remove
+      vrf: ntc
+      interface: "{{ intname }}"
+      state: absent
+      provider: "{{ connection }}"
+    register: result
+
+  - assert: *true
+
+  - name: "Remove Idempotence"
+    nxos_vrf_interface: *remove
+    register: result
+
+  - assert: *false
+
+  always:
+  - name: put interface in default mode
+    nxos_config:
+      lines: "default interface {{ intname }}"
+      provider: "{{ connection }}"
+      match: none
+    ignore_errors: yes
+
+- debug: msg="END TRANSPORT:{{ connection.transport }} nxos_vrf_interface sanity test"
diff --git a/test/integration/targets/nxos_vrf_interface/tests/nxapi/sanity.yaml b/test/integration/targets/nxos_vrf_interface/tests/nxapi/sanity.yaml
--- a/test/integration/targets/nxos_vrf_interface/tests/nxapi/sanity.yaml
+++ b/test/integration/targets/nxos_vrf_interface/tests/nxapi/sanity.yaml
@@ -1,39 +1,4 @@
 ---
-- debug: msg="START TRANSPORT:NXAPI nxos_vrf_interface sanity test"
+- set_fact: connection="{{ nxapi }}"
 
-# Select interface for test
-- set_fact: intname="{{ nxos_int1 }}"
-
-- block:
-  - name: put interface in L3
-    nxos_config:
-      commands:
-        - no switchport
-      parents:
-        - "interface {{ intname }}"
-      match: none
-      provider: "{{ nxapi }}"
-
-  - name: Ensure vrf ntc exists on interface
-    nxos_vrf_interface:
-      vrf: ntc
-      interface: "{{ intname }}"
-      state: present
-      provider: "{{ nxapi }}"
-
-  - name: Ensure ntc VRF does not exist on interface
-    nxos_vrf_interface:
-      vrf: ntc
-      interface: "{{ intname }}"
-      state: absent
-      provider: "{{ nxapi }}"
-
-  always:
-  - name: put interface in default mode
-    nxos_config:
-      lines: "default interface {{ intname }}"
-      provider: "{{ nxapi }}"
-      match: none
-    ignore_errors: yes
-
-- debug: msg="END TRANSPORT:NXAPI nxos_vrf_interface sanity test"
+- import_tasks: targets/nxos_vrf_interface/tests/common/sanity.yaml
diff --git a/test/integration/targets/nxos_vtp_password/tasks/main.yaml b/test/integration/targets/nxos_vtp_password/tasks/main.yaml
--- a/test/integration/targets/nxos_vtp_password/tasks/main.yaml
+++ b/test/integration/targets/nxos_vtp_password/tasks/main.yaml
@@ -1,3 +1,7 @@
 ---
-- { include: cli.yaml, tags: ['cli'] }
-- { include: nxapi.yaml, tags: ['nxapi'] }
+# Use block to ensure that both cli and nxapi tests
+# will run even if there are failures or errors.
+- block:
+  - { include: cli.yaml, tags: ['cli'] }
+  always:
+  - { include: nxapi.yaml, tags: ['nxapi'] }
diff --git a/test/integration/targets/nxos_vtp_password/tests/cli/sanity.yaml b/test/integration/targets/nxos_vtp_password/tests/cli/sanity.yaml
--- a/test/integration/targets/nxos_vtp_password/tests/cli/sanity.yaml
+++ b/test/integration/targets/nxos_vtp_password/tests/cli/sanity.yaml
@@ -1,30 +1,4 @@
 ---
-- debug: msg="START TRANSPORT:CLI nxos_vtp_password sanity test"
+- set_fact: connection="{{ cli }}"
 
-- block:
-  - name: enable feature vtp
-    nxos_feature:
-      feature: vtp
-      state: enabled
-      provider: "{{ cli }}"
-
-  - name: configure vtp password
-    nxos_vtp_password:
-      password: ntc
-      state: present
-      provider: "{{ cli }}"
-
-  - name: remove vtp password
-    nxos_vtp_password:
-      password: ntc
-      state: absent
-      provider: "{{ cli }}"
-
-  always:
-  - name: disable feature vtp
-    nxos_feature:
-      feature: vtp
-      state: disabled
-      provider: "{{ cli }}"
-
-- debug: msg="END TRANSPORT:CLI nxos_vtp_password sanity test"
+- import_tasks: targets/nxos_vtp_password/tests/common/sanity.yaml
diff --git a/test/integration/targets/nxos_vtp_password/tests/common/sanity.yaml b/test/integration/targets/nxos_vtp_password/tests/common/sanity.yaml
new file mode 100644
--- /dev/null
+++ b/test/integration/targets/nxos_vtp_password/tests/common/sanity.yaml
@@ -0,0 +1,57 @@
+---
+- debug: msg="START TRANSPORT:{{ connection.transport }} nxos_vtp_password sanity test"
+
+- block:
+  - name: enable feature vtp
+    nxos_feature:
+      feature: vtp
+      state: enabled
+      provider: "{{ connection }}"
+
+  - name: configure vtp domain
+    nxos_vtp_domain:
+      domain: testing
+      provider: "{{ connection }}"
+
+  - name: configure vtp password
+    nxos_vtp_password: &configure
+      vtp_password: ntc
+      state: present
+      provider: "{{ connection }}"
+    register: result
+
+  - assert: &true
+      that:
+        - "result.changed == true"
+  
+  - name: "Conf Idempotence"
+    nxos_vtp_password: *configure
+    register: result
+
+  - assert: &false
+      that:
+        - "result.changed == false"
+
+  - name: remove vtp password
+    nxos_vtp_password: &remove
+      vtp_password: ntc
+      state: absent
+      provider: "{{ connection }}"
+    register: result
+
+  - assert: *true
+
+  - name: "Remove Idempotence"
+    nxos_vtp_password: *remove
+    register: result
+
+  - assert: *false
+
+  always:
+  - name: disable feature vtp
+    nxos_feature:
+      feature: vtp
+      state: disabled
+      provider: "{{ connection }}"
+
+- debug: msg="END TRANSPORT:{{ connection.transport }} nxos_vtp_password sanity test"
diff --git a/test/integration/targets/nxos_vtp_password/tests/nxapi/sanity.yaml b/test/integration/targets/nxos_vtp_password/tests/nxapi/sanity.yaml
--- a/test/integration/targets/nxos_vtp_password/tests/nxapi/sanity.yaml
+++ b/test/integration/targets/nxos_vtp_password/tests/nxapi/sanity.yaml
@@ -1,30 +1,4 @@
 ---
-- debug: msg="START TRANSPORT:NXAPI nxos_vtp_password sanity test"
+- set_fact: connection="{{ nxapi }}"
 
-- block:
-  - name: enable feature vtp
-    nxos_feature:
-      feature: vtp
-      state: enabled
-      provider: "{{ nxapi }}"
-
-  - name: configure vtp password
-    nxos_vtp_password:
-      password: ntc
-      state: present
-      provider: "{{ nxapi }}"
-
-  - name: remove vtp password
-    nxos_vtp_password:
-      password: ntc
-      state: absent
-      provider: "{{ nxapi }}"
-
-  always:
-  - name: disable feature vtp
-    nxos_feature:
-      feature: vtp
-      state: disabled
-      provider: "{{ nxapi }}"
-
-- debug: msg="END TRANSPORT:NXAPI nxos_vtp_password sanity test"
+- import_tasks: targets/nxos_vtp_password/tests/common/sanity.yaml