Repository: ansible/ansible

Issue:
jenkins_script only returns output when the script succeeds
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
jenkins_script

##### ANSIBLE VERSION
```
ansible 2.4.3.0
  config file = /home/ja.hogarth/workspace/ynap/ansible/ansible_role_jenkins/ansible.cfg
  configured module search path = [u'/home/ja.hogarth/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.14 (default, Feb 17 2018, 10:42:17) [GCC 7.3.1 20180130 (Red Hat 7.3.1-2)]

```

##### CONFIGURATION
No changes

##### OS / ENVIRONMENT
N/A

##### SUMMARY
The output key is only populated if there were no problems running the script:

https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/web_infrastructure/jenkins_script.py#L183

This results in a lot of boilerplate conditional logic to check if it exists, and additional conditional code to view msg if it fails.

It makes way more sense to always populate output, so that it's easier to debug when there is a failure by having the stacktrace clearly visible in the stuff returned.

##### STEPS TO REPRODUCE
Anything that results in a stacktrace from jenkins

##### EXPECTED RESULTS
To be able to rely on output existing so that it can be tested regardless without conditionals.

##### ACTUAL RESULTS
The ansible task complains that output doesn't exist when checking it for content.



Discussion:
Files identified in the description:
* [lib/ansible/modules/web_infrastructure/jenkins_script.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/web_infrastructure/jenkins_script.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 --->

Resolving patch:
diff --git a/lib/ansible/modules/web_infrastructure/jenkins_script.py b/lib/ansible/modules/web_infrastructure/jenkins_script.py
--- a/lib/ansible/modules/web_infrastructure/jenkins_script.py
+++ b/lib/ansible/modules/web_infrastructure/jenkins_script.py
@@ -124,7 +124,7 @@ def is_csrf_protection_enabled(module):
                            module.params['url'] + '/api/json',
                            method='GET')
     if info["status"] != 200:
-        module.fail_json(msg="HTTP error " + str(info["status"]) + " " + info["msg"])
+        module.fail_json(msg="HTTP error " + str(info["status"]) + " " + info["msg"], output='')
 
     content = to_native(resp.read())
     return json.loads(content).get('useCrumbs', False)
@@ -135,7 +135,7 @@ def get_crumb(module):
                            module.params['url'] + '/crumbIssuer/api/json',
                            method='GET')
     if info["status"] != 200:
-        module.fail_json(msg="HTTP error " + str(info["status"]) + " " + info["msg"])
+        module.fail_json(msg="HTTP error " + str(info["status"]) + " " + info["msg"], output='')
 
     content = to_native(resp.read())
     return json.loads(content)
@@ -157,14 +157,17 @@ def main():
 
     if module.params['user'] is not None:
         if module.params['password'] is None:
-            module.fail_json(msg="password required when user provided")
+            module.fail_json(msg="password required when user provided", output='')
         module.params['url_username'] = module.params['user']
         module.params['url_password'] = module.params['password']
         module.params['force_basic_auth'] = True
 
     if module.params['args'] is not None:
         from string import Template
-        script_contents = Template(module.params['script']).substitute(module.params['args'])
+        try:
+            script_contents = Template(module.params['script']).substitute(module.params['args'])
+        except KeyError as err:
+            module.fail_json(msg="Error with templating variable: %s" % err, output='')
     else:
         script_contents = module.params['script']
 
@@ -181,12 +184,12 @@ def main():
                            timeout=module.params['timeout'])
 
     if info["status"] != 200:
-        module.fail_json(msg="HTTP error " + str(info["status"]) + " " + info["msg"])
+        module.fail_json(msg="HTTP error " + str(info["status"]) + " " + info["msg"], output='')
 
     result = to_native(resp.read())
 
     if 'Exception:' in result and 'at java.lang.Thread' in result:
-        module.fail_json(msg="script failed with stacktrace:\n " + result)
+        module.fail_json(msg="script failed with stacktrace:\n " + result, output='')
 
     module.exit_json(
         output=result,


Test patch: