Repository: ansible/ansible

Issue:
ansible-inventory doesn't pass through stderr for inventory scripts
##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - ~~Bug  Report~~
- Feature Idea

##### COMPONENT NAME
bin/ansible-inventory

##### ANSIBLE VERSION
```
2.4
```
##### SUMMARY

Using `ansible-inventory`, from ansible 2.4, with a dynamic inventory script we don't see stderr from the script unless the script fails. Tower has always mirrored stderr from the output script into the sync results, as useful debugging information. For Tower with ansible 2.4 we no longer have that output.

If the inventory script fails we see the stderr output, we would like to see the output even if the script succeeds.

##### STEPS TO REPRODUCE
Example script:
``` python
#!/usr/bin/env python
from __future__ import print_function
import sys
print('TEST', file=sys.stderr)
print('{}')
```

Invoking with something similar to:
```
ansible-inventory -i inv_script.py --list
```


##### EXPECTED RESULTS
If the inventory script fails we see the stderr output, we would like to see the output even if the script succeeds.


Discussion:
@voidspace Greetings! Thanks for taking the time to open this issue. In order for the community to handle your issue effectively, we need a bit more information. 

Here are the items we could not find in your description:
- issue type
- ansible version
- component name

Please set the description of this issue with this template:
https://raw.githubusercontent.com/ansible/ansible/devel/.github/ISSUE_TEMPLATE.md

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: issue_missing_data --->
pinging @bcoca 
Thanks for reformatting the issue report for me.
I was also expecting this, not just an "issue" on 2.4 but also in previous versions, at least 2.2.1.0
Ansible itself has never dealt with the stderr output unless the script failed, tower used a direct execution of the script to get that.

This is not really a bug, but a feature request, it requires changing the Ansible core engine to report this info on successful inventory.
New related issue https://github.com/ansible/ansible/issues/38047
It looks like the lack of this feature in `ansible-inventory` has caused Tower to regress on certain behavior for inventory syncs (which it relied on prior to our switch to `ansible-inventory`: https://github.com/ansible/tower/issues/1146

Resolving patch:
diff --git a/lib/ansible/plugins/inventory/script.py b/lib/ansible/plugins/inventory/script.py
--- a/lib/ansible/plugins/inventory/script.py
+++ b/lib/ansible/plugins/inventory/script.py
@@ -19,6 +19,16 @@
              key: cache
         env:
            - name: ANSIBLE_INVENTORY_PLUGIN_SCRIPT_CACHE
+      always_show_stderr:
+        description: Toggle display of stderr even when script was successful
+        version_added: "2.5.1"
+        default: True
+        type: boolean
+        ini:
+           - section: inventory_plugin_script
+             key: always_show_stderr
+        env:
+           - name: ANSIBLE_INVENTORY_PLUGIN_SCRIPT_STDERR
     description:
         - The source provided must an executable that returns Ansible inventory JSON
         - The source must accept C(--list) and C(--host <hostname>) as arguments.
@@ -64,7 +74,7 @@ def verify_file(self, path):
                     initial_chars = inv_file.read(2)
                     if initial_chars.startswith(b'#!'):
                         shebang_present = True
-            except:
+            except Exception:
                 pass
 
             if not os.access(path, os.X_OK) and not shebang_present:
@@ -99,8 +109,7 @@ def parse(self, inventory, loader, path, cache=None):
                 if sp.returncode != 0:
                     raise AnsibleError("Inventory script (%s) had an execution error: %s " % (path, err))
 
-                # make sure script output is unicode so that json loader will output
-                # unicode strings itself
+                # make sure script output is unicode so that json loader will output unicode strings itself
                 try:
                     data = to_text(stdout, errors="strict")
                 except Exception as e:
@@ -111,6 +120,10 @@ def parse(self, inventory, loader, path, cache=None):
                 except Exception as e:
                     raise AnsibleError("failed to parse executable inventory script results from {0}: {1}\n{2}".format(path, to_native(e), err))
 
+                # if no other errors happened and you want to force displaying stderr, do so now
+                if err and self.get_option('always_show_stderr'):
+                    self.display.error(msg=to_text(err))
+
             processed = self._cache[cache_key]
             if not isinstance(processed, Mapping):
                 raise AnsibleError("failed to parse executable inventory script results from {0}: needs to be a json dict\n{1}".format(path, err))


Test patch: