Repository: ansible/ansible

Issue:
Module: nxos_vrf - changed true when shouldn't be when run with --check
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report

##### COMPONENT NAME
<!--- Name of the module/plugin/task/feature -->
nxos_vrf 

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.4.0 (devel 211d0656f8) last updated 2017/05/25 10:30:25 (GMT -400)
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/jseeley/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/jseeley/ansible-git-devel/ansible/lib/ansible
  executable location = /home/jseeley/ansible-git-devel/ansible/bin/ansible
  python version = 2.7.5 (default, Nov  6 2016, 00:28:07) [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]

```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->
Environment variable used: ANSIBLE_NET_PASSWORD

##### 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.
-->
Running Ansible from: CentOS Linux release 7.3.1611 (Core)
Managing: cisco Nexus7700 C7706 system: version 7.3(1)D1(1

##### SUMMARY
<!--- Explain the problem briefly -->
ansible 2.4.0 (devel 211d0656f8) reports a change when run with --check. However, this isn't true with ansible 2.3.0.0. I am not expecting a change and cannot figure out why ansible 2.4.0 (devel 211d0656f8) wants to make a change and what that change is.

##### 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.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
---

vrfs:                                                                                                                                                dated: Thu May 25 09:57:54 2017
  - management

---

  - name: add vrfs
    nxos_vrf:
      provider: "{{ cli }}"
      transport: nxapi
      vrf: "{{ item }}"
      state: present
      admin_state: up
    with_items: "{{ vrfs }}"
    when:
      - vrfs is defined
    tags: add_vrfs

```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
No change reported.

```
ansible 2.3.0.0

 ansible-playbook site.yml --check --skip-tags "backup" -t add_vrfs -l core7k-a -vvv

PLAYBOOK: site.yml *************************************************************
2 plays in site.yml

PLAY [localhost] ***************************************************************
skipping: no hosts matched

PLAY [nxos] ********************************************************************
META: ran handlers

TASK [add vrfs] ****************************************************************
ok: [core7k-a] => (item=management) => {
    "changed": false,
    "end_state": {
        "admin_state": "Up",
        "description": "",
        "rd": "",
        "vni": "",
        "vrf": "management"
    },
    "existing": {
        "admin_state": "Up",
        "description": "",
        "rd": "",
        "vni": "",
        "vrf": "management"
    },
    "invocation": {
        "module_args": {
            "admin_state": "up",
            "config": null,
            "description": null,
            "host": "core7k-a",
            "include_defaults": "False",
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "port": null,
            "provider": {
                "host": "core7k-a",
                "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "port": null,
                "ssh_keyfile": null,
                "timeout": null,
                "transport": "cli",
                "use_ssl": false,
                "username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                "validate_certs": null
            },
            "rd": null,
            "save": false,
            "ssh_keyfile": null,
            "state": "present",
            "timeout": null,
            "transport": "cli",
            "use_ssl": false,
            "username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "validate_certs": null,
            "vni": null,
            "vrf": "management"
        }
    },
    "item": "management",
    "proposed": {
        "admin_state": "Up",
        "vrf": "management"
    },
    "updates": [],
    "warnings": [
        "argument password has been deprecated and will be removed in a future version"
    ]
}
META: ran handlers
META: ran handlers

PLAY RECAP *********************************************************************
core7k-a               : ok=1    changed=0    unreachable=0    failed=0

```

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
A change reported.

```
ansible 2.4.0 (devel 211d0656f8)

 ansible-playbook site.yml --check --skip-tags "backup" -t add_vrfs -l jdc-core7k-a -vvv

PLAYBOOK: site.yml *************************************************************
2 plays in site.yml

PLAY [localhost] ***************************************************************
skipping: no hosts matched

PLAY [nxos] ********************************************************************
META: ran handlers

TASK [add vrfs] ****************************************************************

changed: [core7k-a] => (item=management) => {
    "changed": true,
    "commands": [
        "vrf context management",
        "no shutdown"
    ],
    "invocation": {
        "module_args": {
            "admin_state": "up",
            "config": null,
            "description": null,
            "host": null,
            "include_defaults": "False",
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "port": null,
            "provider": null,
            "rd": null,
            "save": false,
            "ssh_keyfile": null,
            "state": "present",
            "timeout": 10,
            "transport": "cli",
            "use_ssl": null,
            "username": null,
            "validate_certs": null,
            "vni": null,
            "vrf": "management"
        }
    },
    "item": "management"
}
META: ran handlers
META: ran handlers

PLAY RECAP *********************************************************************
core7k-a               : ok=1    changed=1    unreachable=0    failed=0

```



Discussion:
cc @jedelman8 @GGabriele @rahushen @privateip @rcarrillocruz @mikewiebe @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.py b/lib/ansible/modules/network/nxos/nxos_vrf.py
--- a/lib/ansible/modules/network/nxos/nxos_vrf.py
+++ b/lib/ansible/modules/network/nxos/nxos_vrf.py
@@ -98,7 +98,7 @@
 '''
 import re
 
-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
 
@@ -190,6 +190,7 @@ def get_vrf(vrf, module):
         return {}
 
     parsed_vrf = apply_key_map(vrf_key, vrf_table)
+    parsed_vrf['admin_state'] = parsed_vrf['admin_state'].lower()
 
     command = 'show run all | section vrf.context.{0}'.format(vrf)
     body = execute_show_command(command, module)[0]
@@ -259,13 +260,13 @@ def main():
         if proposed.get('vni'):
             if existing.get('vni') and existing.get('vni') != '':
                 commands.insert(1, 'no vni {0}'.format(existing['vni']))
-        if module.check_mode:
-            module.exit_json(changed=True, commands=commands)
-        else:
+
+        if not module.check_mode:
             load_config(module, commands)
-            results['changed'] = True
-            if 'configure' in commands:
-                commands.pop(0)
+
+        results['changed'] = True
+        if 'configure' in commands:
+            commands.pop(0)
 
     results['commands'] = commands
 


Test patch:
diff --git a/test/units/modules/network/nxos/fixtures/nxos_vrf/show_run_all b/test/units/modules/network/nxos/fixtures/nxos_vrf/show_run_all
new file mode 100644
--- /dev/null
+++ b/test/units/modules/network/nxos/fixtures/nxos_vrf/show_run_all
@@ -0,0 +1,4 @@
+vrf context coke
+vrf context management
+  ip route 172.26.0.0/16 172.26.4.1
+vrf context test-vrf
diff --git a/test/units/modules/network/nxos/fixtures/nxos_vrf/show_vrf_management b/test/units/modules/network/nxos/fixtures/nxos_vrf/show_vrf_management
new file mode 100644
--- /dev/null
+++ b/test/units/modules/network/nxos/fixtures/nxos_vrf/show_vrf_management
@@ -0,0 +1,10 @@
+{
+  "TABLE_vrf": {
+    "ROW_vrf": {
+      "vrf_name": "management", 
+      "vrf_id": 2, 
+      "vrf_state": "Up", 
+      "vrf_reason": "--"
+    }
+  }
+}
diff --git a/test/units/modules/network/nxos/fixtures/nxos_vrf/show_vrf_ntc b/test/units/modules/network/nxos/fixtures/nxos_vrf/show_vrf_ntc
new file mode 100644
diff --git a/test/units/modules/network/nxos/test_nxos_vrf.py b/test/units/modules/network/nxos/test_nxos_vrf.py
--- a/test/units/modules/network/nxos/test_nxos_vrf.py
+++ b/test/units/modules/network/nxos/test_nxos_vrf.py
@@ -19,7 +19,7 @@
 from __future__ import (absolute_import, division, print_function)
 __metaclass__ = type
 
-import json
+import os
 
 from ansible.compat.tests.mock import patch
 from ansible.modules.network.nxos import nxos_vrf
@@ -31,32 +31,45 @@ class TestNxosVrfModule(TestNxosModule):
     module = nxos_vrf
 
     def setUp(self):
-        self.mock_run_commands = patch('ansible.modules.network.nxos.nxos_vrf.run_commands')
-        self.run_commands = self.mock_run_commands.start()
-
         self.mock_load_config = patch('ansible.modules.network.nxos.nxos_vrf.load_config')
         self.load_config = self.mock_load_config.start()
 
-        self.mock_get_config = patch('ansible.modules.network.nxos.nxos_vrf.get_config')
-        self.get_config = self.mock_get_config.start()
+        self.mock_run_commands = patch('ansible.modules.network.nxos.nxos_vrf.run_commands')
+        self.run_commands = self.mock_run_commands.start()
 
     def tearDown(self):
-        self.mock_run_commands.stop()
         self.mock_load_config.stop()
-        self.mock_get_config.stop()
+        self.mock_run_commands.stop()
 
     def load_fixtures(self, commands=None):
+        def load_from_file(*args, **kwargs):
+            module, commands = args
+            output = list()
+
+            for command in commands:
+                filename = str(command).split(' | ')[0].replace(' ', '_')
+                filename = os.path.join('nxos_vrf', filename)
+                output.append(load_fixture(filename))
+            return output
+
         self.load_config.return_value = None
+        self.run_commands.side_effect = load_from_file
 
     def test_nxos_vrf_present(self):
         set_module_args(dict(vrf='ntc', state='present', admin_state='up'))
-        result = self.execute_module(changed=True)
-        self.assertEqual(result['commands'], ['vrf context ntc', 'no shutdown'])
+        self.execute_module(changed=True, commands=['vrf context ntc', 'no shutdown'])
+
+    def test_nxos_vrf_present_no_change(self):
+        set_module_args(dict(vrf='management', state='present', admin_state='up'))
+        self.execute_module(changed=False, commands=[])
 
     def test_nxos_vrf_absent(self):
+        set_module_args(dict(vrf='management', state='absent'))
+        self.execute_module(changed=True, commands=['no vrf context management'])
+
+    def test_nxos_vrf_absent_no_change(self):
         set_module_args(dict(vrf='ntc', state='absent'))
-        result = self.execute_module(changed=True)
-        self.assertEqual(result['commands'], ['no vrf context ntc'])
+        self.execute_module(changed=False, commands=[])
 
     def test_nxos_vrf_default(self):
         set_module_args(dict(vrf='default'))