Repository: ansible/ansible

Issue:
Junos_config jsonDecoderError after update from 2.4.3 to 2.5.0

##### ISSUE TYPE

 - Bug Report

##### COMPONENT NAME
junos_config

##### ANSIBLE VERSION

```
ansible --version
 15455 1522332143.58683: starting run
ansible 2.5.0
  config file = /home/aurelien/ansible/ansible.cfg
  configured module search path = [u'/homeipa/aurelien/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python2.7/dist-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 2.7.6 (default, Nov 23 2017, 15:49:48) [GCC 4.8.4]

```

##### CONFIGURATION
<!---
DEFAULT_DEBUG(env: ANSIBLE_DEBUG) = True
DEFAULT_HASH_BEHAVIOUR(/home/aurelien/ansible/ansible.cfg) = merge
DEFAULT_LOG_PATH(/home/aurelien/ansible/ansible.cfg) = /home/aurelien/ansible/ansible.log
DEFAULT_REMOTE_PORT(/home/aurelien/ansible/ansible.cfg) = 22
DEFAULT_TIMEOUT(/home/aurelien/ansible/ansible.cfg) = 120
DEFAULT_VAULT_PASSWORD_FILE(/home/aurelien/ansible/ansible.cfg) = /homeipa/aurelien/.vault_pass
HOST_KEY_CHECKING(/home/aurelien/ansible/ansible.cfg) = False
~

-->

##### OS / ENVIRONMENT
<!---
Linux fr-1vm-lab-baballe02.infra.msv 3.13.0-141-generic #190-Ubuntu SMP Fri Jan 19 12:52:38 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

Model: mx240
Junos: 17.3R1.10

-->

##### SUMMARY
since ansible update from 2.4.3 to 2.5.0, tasks calling junos_config fail with an error related to jsonDecoderError attribute, apparently only used in python 3.5+ (we use 2.7.6)

##### STEPS TO REPRODUCE
<!---
connect to junos equipment with junos_config
-->


```yaml

---
- name: push conf file to device
  junos_config:
    backup: no
    src: "builds/{{ batch_sids.id }}/assemble/{{ inventory_hostname }}.cfg"
    update: replace
    provider:
      timeout: 120
      username: '{{ ansible_user }}'
    confirm: '{{ commit_confirm }}'
  tags:
    - deploy
    - config


```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
no errors

##### ACTUAL RESULTS



<!--- Paste verbatim command output between quotes below -->
```
 13389 1522309680.51102: marking mx240-lab as failed
 13389 1522309680.51122: marking host mx240-lab failed, current state: HOST STATE: block=2, task=6, rescue=0, always=0, run_state=ITERATING_TASKS, fail_state=FAILED_NONE, pnding_setup=False, tasks child state? (HOST STATE: block=0, task=1, rescue=0, always=0, run_state=ITERATING_TASKS, fail_state=FAILED_NONE, pending_setup=False, tasks child tate? (None), rescue child state? (None), always child state? (None), did rescue? False, did start at task? False), rescue child state? (None), always child state? (None), id rescue? False, did start at task? False
 13389 1522309680.51145: ^ failed state is now: HOST STATE: block=2, task=6, rescue=0, always=0, run_state=ITERATING_TASKS, fail_state=FAILED_NONE, pending_setup=False, tass child state? (HOST STATE: block=0, task=1, rescue=0, always=0, run_state=ITERATING_COMPLETE, fail_state=FAILED_TASKS, pending_setup=False, tasks child state? (None), resce child state? (None), always child state? (None), did rescue? False, did start at task? False), rescue child state? (None), always child state? (None), did rescue? False, id start at task? False
 13389 1522309680.51161: getting the next task for host mx240-lab
 13389 1522309680.51181: done getting next task for host mx240-lab
 13389 1522309680.51195:  ^ task is: None
 13389 1522309680.51210:  ^ state is: HOST STATE: block=2, task=6, rescue=0, always=0, run_state=ITERATING_COMPLETE, fail_state=FAILED_TASKS, pending_setup=False, tasks chid state? (None), rescue child state? (None), always child state? (None), did rescue? False, did start at task? False
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: AttributeError: 'module' object has no attribute 'JSONDecodeError'
fatal: [mx240-lab]: FAILED! => {"msg": "Unexpected failure during module execution.", "stdout": ""}
 13389 1522309680.51271: no more pending results, returning what we have
```



Discussion:
Files identified in the description:
* [lib/ansible/modules/network/junos/junos_config.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/network/junos/junos_config.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 @privateip
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@bundyboy could you provide the output from running this playbook with the added '-vvv' verbosity options?

Resolving patch:
diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py
--- a/lib/ansible/executor/task_executor.py
+++ b/lib/ansible/executor/task_executor.py
@@ -895,7 +895,8 @@ def find_file_in_path(filename):
         else:
             try:
                 result = json.loads(to_text(stderr, errors='surrogate_then_replace'))
-            except json.decoder.JSONDecodeError:
+            except getattr(json.decoder, 'JSONDecodeError', ValueError):
+                # JSONDecodeError only available on Python 3.5+
                 result = {'error': to_text(stderr, errors='surrogate_then_replace')}
 
         if 'messages' in result:
diff --git a/lib/ansible/plugins/connection/persistent.py b/lib/ansible/plugins/connection/persistent.py
--- a/lib/ansible/plugins/connection/persistent.py
+++ b/lib/ansible/plugins/connection/persistent.py
@@ -115,7 +115,8 @@ def find_file_in_path(filename):
         else:
             try:
                 result = json.loads(to_text(stderr, errors='surrogate_then_replace'))
-            except json.decoder.JSONDecodeError:
+            except getattr(json.decoder, 'JSONDecodeError', ValueError):
+                # JSONDecodeError only available on Python 3.5+
                 result = {'error': to_text(stderr, errors='surrogate_then_replace')}
 
         if 'messages' in result:


Test patch: