Repository: ansible/ansible

Issue:
check_mode breaks on junos_banner
<!---
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
-->
junos_banner

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes below -->
```
ansible 2.6.0 (junos_smoke 155adb1631) last updated 2018/03/08 09:16:06 (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 -->
`check_mode: yes` causes junos_banner tasks to fail

##### 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.
-->
Run the following task

```
- name: check mode
  junos_banner:
    banner: login
    text: this is not the banner you're looking for
    state: present
    provider: "{{ netconf }}"
  register: result
  check_mode: yes

- assert:
    that:
      - result.changed == false
```

<!--- Paste example playbooks or commands between quotes below -->
```yaml

```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
Module should run and not change the login banner

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
TASK [junos_smoke : check mode] *******************************************************************************************
task path: /Users/david/code/ansible/test/integration/targets/junos_smoke/tests/netconf/module_utils_junos.yaml:46
<junos01> attempting to start connection
<junos01> using connection plugin netconf
<junos01> found existing local domain socket, using it!
<junos01>
<junos01> local domain socket path is /Users/david/.ansible/pc/0319a6a111
 [WARNING]: provider is unnecessary when using connection=netconf and will be ignored

Using module file /Users/david/code/ansible/lib/ansible/modules/network/junos/junos_banner.py
<junos01> ESTABLISH LOCAL CONNECTION FOR USER: david
<junos01> EXEC /bin/sh -c 'echo ~ && sleep 0'
<junos01> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /Users/david/.ansible/tmp/ansible-tmp-1520531921.38-75952063324716 `" && echo ansible-tmp-1520531921.38-75952063324716="` echo /Users/david/.ansible/tmp/ansible-tmp-1520531921.38-75952063324716 `" ) && sleep 0'
<junos01> PUT /Users/david/.ansible/tmp/ansible-local-65800g9taGD/tmpXZT5uE TO /Users/david/.ansible/tmp/ansible-tmp-1520531921.38-75952063324716/junos_banner.py
<junos01> EXEC /bin/sh -c 'chmod u+x /Users/david/.ansible/tmp/ansible-tmp-1520531921.38-75952063324716/ /Users/david/.ansible/tmp/ansible-tmp-1520531921.38-75952063324716/junos_banner.py && sleep 0'
<junos01> EXEC /bin/sh -c '/tmp/ansible-test-coverage-V8NjOc/coverage/injector.py /Users/david/.ansible/tmp/ansible-tmp-1520531921.38-75952063324716/junos_banner.py && sleep 0'
<junos01> EXEC /bin/sh -c 'rm -f -r /Users/david/.ansible/tmp/ansible-tmp-1520531921.38-75952063324716/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
Traceback (most recent call last):
  File "/tmp/ansible_TzxF82/ansible_module_junos_banner.py", line 180, in <module>
    main()
  File "/tmp/ansible_TzxF82/ansible_module_junos_banner.py", line 171, in main
    discard_changes(module)
  File "/tmp/ansible_TzxF82/ansible_modlib.zip/ansible/module_utils/network/junos/junos.py", line 185, in discard_changes
  File "/tmp/ansible_TzxF82/ansible_modlib.zip/ansible/module_utils/network/common/netconf.py", line 70, in __rpc__
  File "/tmp/ansible_TzxF82/ansible_modlib.zip/ansible/module_utils/network/common/netconf.py", line 102, in parse_rpc_error
ansible.module_utils.connection.ConnectionError: request() got an unexpected keyword argument 'exit'

fatal: [junos01]: FAILED! => {
    "changed": false,
    "module_stderr": "Traceback (most recent call last):\n  File \"/tmp/ansible_TzxF82/ansible_module_junos_banner.py\", line 180, in <module>\n    main()\n  File \"/tmp/ansible_TzxF82/ansible_module_junos_banner.py\", line 171, in main\n    discard_changes(module)\n  File \"/tmp/ansible_TzxF82/ansible_modlib.zip/ansible/module_utils/network/junos/junos.py\", line 185, in discard_changes\n  File \"/tmp/ansible_TzxF82/ansible_modlib.zip/ansible/module_utils/network/common/netconf.py\", line 70, in __rpc__\n  File \"/tmp/ansible_TzxF82/ansible_modlib.zip/ansible/module_utils/network/common/netconf.py\", line 102, in parse_rpc_error\nansible.module_utils.connection.ConnectionError: request() got an unexpected keyword argument 'exit'\n",
    "module_stdout": "",
    "msg": "MODULE FAILURE",
    "rc": 1
}
```



Discussion:
Files identified in the description:
* [lib/ansible/modules/network/junos/junos_banner.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/network/junos/junos_banner.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 @Qalthos @ganeshrn
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
I am having the same issue with junos_config in --check mode with Ansible 2.5.0.0 and Python 2.7.14:

```
2018-03-25 16:53:45,047 p=28200 u=matthewr |  network_os is set to junos
2018-03-25 16:53:45,105 p=28200 u=matthewr |  ssh connection done, starting ncclient
2018-03-25 16:53:45,843 ncclient.transport.ssh Connected (version 2.0, client OpenSSH_6.9)
2018-03-25 16:53:47,821 ncclient.transport.ssh Authentication (publickey) failed.
2018-03-25 16:53:48,570 ncclient.transport.ssh Authentication (password) successful!
2018-03-25 16:53:49,853 ncclient.transport.session initialized: session-id=11854 | server_capabilities=<dictionary-keyiterator object at 0x7ff868c683c0>
2018-03-25 16:53:49,853 p=28200 u=matthewr |  ncclient manager object created successfully
2018-03-25 16:53:49,855 p=28200 u=matthewr |  loaded netconf plugin for network_os junos
2018-03-25 16:53:49,980 p=28201 u=matthewr |  network_os is set to junos
2018-03-25 16:53:50,007 p=27962 u=matthewr |  Using module file /home/matthewr/git/cloud-networking/venv/local/lib/python2.7/site-packages/ansible/modules/network/junos/junos_config.py
2018-03-25 16:53:50,044 p=28201 u=matthewr |  ssh connection done, starting ncclient
2018-03-25 16:53:50,091 ncclient.operations.rpc Requesting 'ExecuteRpc'
2018-03-25 16:53:50,782 ncclient.transport.ssh Connected (version 2.0, client OpenSSH_6.9)
2018-03-25 16:53:51,010 ncclient.operations.rpc Requesting 'Lock'
2018-03-25 16:53:51,478 ncclient.operations.rpc Requesting 'LoadConfiguration'
2018-03-25 16:53:51,995 ncclient.operations.rpc Requesting 'Validate'
2018-03-25 16:53:52,754 ncclient.transport.ssh Authentication (publickey) failed.
2018-03-25 16:53:52,963 ncclient.operations.rpc Requesting 'ExecuteRpc'
2018-03-25 16:53:53,429 ncclient.operations.rpc Requesting 'Unlock'
2018-03-25 16:53:53,509 ncclient.transport.ssh Authentication (password) successful!
2018-03-25 16:53:53,972 p=27962 u=matthewr |  The full traceback is:
Traceback (most recent call last):
  File "/tmp/ansible_o6GZT9/ansible_module_junos_config.py", line 394, in <module>
    main()
  File "/tmp/ansible_o6GZT9/ansible_module_junos_config.py", line 377, in main
    discard_changes(module)
  File "/tmp/ansible_o6GZT9/ansible_modlib.zip/ansible/module_utils/network/junos/junos.py", line 185, in discard_changes
  File "/tmp/ansible_o6GZT9/ansible_modlib.zip/ansible/module_utils/network/common/netconf.py", line 70, in __rpc__
  File "/tmp/ansible_o6GZT9/ansible_modlib.zip/ansible/module_utils/network/common/netconf.py", line 102, in parse_rpc_error
ansible.module_utils.connection.ConnectionError: request() got an unexpected keyword argument 'exit'
```

The module works in check mode in 2.4.3.0 and today I updated to 2.5.0.0 and ran the playbook to test the update and this is the result. I will test the commit by @ganeshrn to see if it resolves the issue.
I can confirm that https://github.com/ganeshrn/ansible/commit/9354ba3b0143d64536fed0287e50947a8cbafd08 fixes the issue.
@matthewrees Thank you for verifying the patch. 

Resolving patch:
diff --git a/lib/ansible/module_utils/network/junos/junos.py b/lib/ansible/module_utils/network/junos/junos.py
--- a/lib/ansible/module_utils/network/junos/junos.py
+++ b/lib/ansible/module_utils/network/junos/junos.py
@@ -180,9 +180,9 @@ def locked_config(module):
         unlock_configuration(module)
 
 
-def discard_changes(module, exit=False):
+def discard_changes(module):
     conn = get_connection(module)
-    return conn.discard_changes(exit=exit)
+    return conn.discard_changes()
 
 
 def get_diff(module, rollback='0'):
diff --git a/lib/ansible/plugins/cliconf/junos.py b/lib/ansible/plugins/cliconf/junos.py
--- a/lib/ansible/plugins/cliconf/junos.py
+++ b/lib/ansible/plugins/cliconf/junos.py
@@ -84,10 +84,8 @@ def commit(self, *args, **kwargs):
         command += b' and-quit'
         return self.send_command(command)
 
-    def discard_changes(self, rollback_id=None):
-        command = b'rollback'
-        if rollback_id is not None:
-            command += b' %s' % int(rollback_id)
+    def discard_changes(self):
+        command = b'rollback 0'
         for cmd in chain(to_list(command), b'exit'):
             self.send_command(cmd)
 


Test patch:
diff --git a/test/integration/targets/junos_banner/tests/netconf/basic.yaml b/test/integration/targets/junos_banner/tests/netconf/basic.yaml
--- a/test/integration/targets/junos_banner/tests/netconf/basic.yaml
+++ b/test/integration/targets/junos_banner/tests/netconf/basic.yaml
@@ -78,6 +78,20 @@
       - "result.changed == true"
       - "'<message>this is my login banner</message>' in config.xml"
 
+- name: check mode
+  junos_banner:
+    banner: login
+    text: this is not the login banner you're looking for
+    state: present
+    provider: "{{ netconf }}"
+  register: result
+  check_mode: yes
+
+- assert:
+    that:
+      - "result.changed == true"
+      - "result.failed == false"
+
 - name: delete login banner
   junos_banner:
     banner: login