Repository: ansible/ansible

Issue:
wishlist: be able to hide skipped roles when using conditional roles
##### Issue Type: Feature Idea
##### Ansible Version: 1.7.1
##### Environment: Debian sid
##### Summary: hide print of tasks where the role is conditionally skipped
##### Steps To Reproduce: N/A
##### Expected Results:

All roles where the expression with 'when' is false should not be shown
at all, preferrably by a config var and perhaps a way to reverse
on the command line.
##### Actual Results: task are always shown even if the role is skipped

I think conditional roles is a great idea, it made my plays easier to write.

However, all those skipped tasks are still shown which makes it harder to see the more interesting
output from the tasks that really are used.

Would it be possible to somehow hide them, maybe a config option in ansible.cfg that could
be reversed by a command line option?
(Yes, I realize that it is also very useful to see what actually is there even if it is not used :-)



Discussion:
cf. #3324 

DISPLAY_SKIPPED_HOSTS=0 is a great addition, but it still shows output of things that don't do anything. I see this as "clutter" and makes the readability less on a playbook. I have several roles that show "Redhat" tasks, while i am using debian. No point in showing those.

+1

+1

In our Ansible installation we have about 50 roles. Our primary playbook defines roles conditionally by variables, which are defined per-host, or per-group.

Example playbook:

```
 hosts: "all"
  roles:
    - { role: siteone.apache, when: "enabled_role_siteone_apache == true"}
    - { role: siteone.backup, when: "enabled_role_siteone_backup == true"}
    - ...
```

This concept works very well for us, but it's very confusing, when only 1% of displayed tasks are relevant for my current host and 99% tasks are in "skipping" state.

@janreges  woudl this help
http://docs.ansible.com/intro_configuration.html#display-skipped-hosts we can set in ansible.cfg to not display skipped tasks

+1

+1

This would make a huge difference when using conditionals. Because Ansible pushes conditionals on roles and on includes down into the tasks inside the role or include, something like:

```
- hosts: blah
  roles:
    - { role: my_server, my_server_cleanup_only: true }
```

can quickly produce huge spews of output for everything that the `my_server` role might do, but didn't do this time.

A possible workaround would initially seem to be a heirarchy of roles, where the base `my_server` role exposes the defaults, etc, then dependent roles like `my_server_cleanup` inherit it and perform particular steps. Then a `my_server_all` role that depends on all of them to do everything, so you don't have to enumerate a long list of roles for the common case. The problems with this are that it doesn't make life any easier when you want just a subset, and it repeats the base role execution for each and every time it gets inherited. Which is horrible, and much worse than the original problem.

Note that this is different to the `display_skipped_hosts` option. Without that option set:

```
TASK: [postgres_server | make clean] ****************************************** 
skipped: [nodeA07]
skipped: [nodeB07]
skipped: [nodeC07]

TASK: [postgres_server | make PostgreSQL] ************************************* 
skipped: [nodeA07]
skipped: [nodeB07]
skipped: [nodeC07]
```

With it:

```
TASK: [postgres_server | make clean] ****************************************** 

TASK: [postgres_server | make PostgreSQL] ************************************* 

```

... and what I actually want:

```
(nothing here)
```

 +1

This feature request discussion has been going on since 2 years. 
It would be really useful if we have this implemented in the next version.

+1

+1

+1 Please.

+1
I tried looking into how to fix the code for this, but due to the way the TASK: bit is printed prior to checking (?) if the task should be skipped it was not trivial to create a patch for me with limited python skills.

fixed via a09ce4bd8734421785b1e46f7bb15a15848d59dc, now you can use the 'skippy' callback to ignore all skips

Thanks for this. However, I'm not happy yet. Please see where the issue was continued from: #3324. It contains some examples where this makes sense, e.g. for registering variables with results from a shell command. For example, if I want to hide the output of a "grep" command, I may still want to see other skips. Therefore, skip and hide are not the same.

Besides this, I also think that this should be controllable per task and not just globally.

Question is, should I create a new (3rd) ticket for this, or is someone going to reopen here?

They are different features, this ticket was to avoid displaying skipped tasks, #3324 was to hide tasks selectively. I don't see us implementing this currently, but you should be able to create your own callback plugin that does this.

Thanks for the feedback. Can you reopen #3324 then?

why? I just stated I don't see us adding this feature.

The ticket was closed and even commenting was turned off without giving feedback to the various use cases that were brought up. I don't see why the issue was closed but esp. why the conversation was locked. Do you wish me to create a new issue for it?

a09ce4b doesn't look terribly easy to use. I feel like with the number of +1's on #3324, it probably warrants introducing something that's built-in and easier to use.

so setting `stdout_callback = skippy` in ansible.cfg is not easy enough?

That looks pretty good actually but I didn't know about `stdout_callback` and I guess that's because it's a new thing in 2.0 and I don't see us moving to 2.0 for a long time.

Seems like in 1.9 I'd have to copy that file into my project's `plugins` directory? Or is there an easier way?

no and copying it won't work, 2.0 pushes almost all output to the plugins, 1.x does not.

It appears that skippy in ansible.cfg does not suppress the output of the skipped roles/tasks, as was the original request. Instead it just suppresses the hosts within each task. 

I ended up here googling "how to hide skipping messages in ansible". stdout_callback is not suppressing output of skipped tasks.  This is a desirable feature and should be supported.

I quickly hacked something to completely hide "skipped tasks" from stdout. It is not complete but it gives an idea on how to get this to work for your usecase. I haven't overridden all the callbacks but it seems to work as expected for the ones I did. 

For anyone who is interested use [this modified skippy plugin](https://github.com/varunkatta/ansible/commit/92d88c1571e4fa1792f7f4112d4ad609f59cace2) instead of the default one.

@varunkatta why don't you just implement this in a new plugin?

+1

+1

+1

I would really like this feature, more than any other new Ansible feature. Currently, if something goes wrong during a provision, I have 160kb of output (42 screensfull in a fullscreen small-font terminal) to visually parse to try and debug. Often, the relevant error, after lots of scrolling, is at the end. But sometimes it is not. This is regularly unnecessarily inconvenient.

I draw attention to the Unix philosophy's useful convention that a task which succeeds should produce no output (other than the data that was requested, if output is meant to be on stdout, which in Ansible's case it is not - we are running it for the side-effects.) Printing extra human-readable 'debug' output while running is almost always less useful than printing nothing except error messages.

I would assert that this is doubly true if the task in question is a no-op, because it is skipped.

https://en.wikipedia.org/wiki/Unix_philosophy (see 'rule of silence')

I tried using @varunkatta's plugin and it fails on Ansible 2.2.  This would be a great feature to have in Ansible and am quite surprised that it's not in there already.

Really, @hanej? I think you'll be up for some nasty surprises when you find out more about priorities and choices of this project…

@madduck I know it's frustrating when it's not just what you want, but unless you're contributing considerable time or money to the project please appreciate what the team _are_ giving you, for free. I've been on the other side of this coin too, and it's incredibly demotivating to have people complaining at you as if they somehow inherently deserve more because what you did doesn't meet their specific use case.

Requests are fine. Suggestions are fine. Demands and complaints, not so much. Also, this is a bug tracker not a forum, so neither of us should really be digressing here, but I feel it's important to call this kind of comment out.

@ringerc I was a (early) contributor to this project before Michael shut me out because I was not 100% in line with his interests. Back then, I raised the issue that the template processing lost all data types in YAML and e.g. integers and booleans became text strings, which I considered a problem, but he didn't, and so that was it for me.

Anyway, this issue here (and the one I filed a long time before, #3324) are so popular that the way the project manager(s) (some of which are not volunteers) are handling this is indicative of something that I feel should not be ignored…


Resolving patch:
diff --git a/lib/ansible/plugins/callback/full_skip.py b/lib/ansible/plugins/callback/full_skip.py
new file mode 100644
--- /dev/null
+++ b/lib/ansible/plugins/callback/full_skip.py
@@ -0,0 +1,72 @@
+# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+from ansible.plugins.callback.default import CallbackModule as CallbackModule_default
+
+
+class CallbackModule(CallbackModule_default):
+
+    '''
+    This is the default callback interface, which simply prints messages
+    to stdout when new callback events are received.
+    '''
+
+    CALLBACK_VERSION = 2.0
+    CALLBACK_TYPE = 'stdout'
+    CALLBACK_NAME = 'full_skip'
+
+    def v2_runner_on_skipped(self, result):
+        self.outlines = []
+
+    def v2_playbook_item_on_skipped(self, result):
+        self.outlines = []
+
+    def v2_runner_item_on_skipped(self, result):
+        self.outlines = []
+
+    def v2_runner_on_failed(self, result, ignore_errors=False):
+        self.display()
+        super(CallbackModule, self).v2_runner_on_failed(result, ignore_errors)
+
+    def v2_playbook_on_task_start(self, task, is_conditional):
+        self.outlines = []
+        self.outlines.append("TASK [%s]" % task.get_name().strip())
+        if self._display.verbosity >= 2:
+            path = task.get_path()
+            if path:
+                self.outlines.append("task path: %s" % path)
+
+    def v2_playbook_item_on_ok(self, result):
+        self.display()
+        super(CallbackModule, self).v2_playbook_item_on_ok(result)
+
+    def v2_runner_on_ok(self, result):
+        self.display()
+        super(CallbackModule, self).v2_runner_on_ok(result)
+
+    def display(self):
+        if len(self.outlines) == 0:
+            return
+        (first, rest) = self.outlines[0], self.outlines[1:]
+        self._display.banner(first)
+        for line in rest:
+            self._display.display(line)
+        self.outlines = []
diff --git a/lib/ansible/plugins/callback/skippy.py b/lib/ansible/plugins/callback/skippy.py
--- a/lib/ansible/plugins/callback/skippy.py
+++ b/lib/ansible/plugins/callback/skippy.py
@@ -21,6 +21,7 @@
 
 from ansible.plugins.callback.default import CallbackModule as CallbackModule_default
 
+
 class CallbackModule(CallbackModule_default):
 
     '''


Test patch: