Ansible cowsay: Die sprechende Kuh, oder auch mehr Getier oder doch nur puristisch mit dem Ansible Stdout Compact Logger?

Bild: Ansible Logo

Dass Admins zuweilen einen besonderen Humor haben und sich an doch sonderlichen Dingen erfreuen können, hat auch beim Thema Ansible seinen Platz gefunden: cowsay, die sprechende Kuh.

Der ein oder andere wird sich nun vielleicht fragen: Was? Noch nie davon gehört, noch nie gesehen!

Nun, die Ausgabe bei einem Ansible-Playbook lauf kennen wir ja nun schon zu genüge, die Ausgabe hier ist altbekannt:

 $ ansible-playbook ~/ansible/playbooks/ssh_client_config.yml

PLAY [ssh_client_config.yml] ******************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************
ok: [localhost]

TASK [ssh_client : include_tasks] *************************************************************************************************
included: /home/django/ansible/roles/ssh_client/tasks/client_config.yml for localhost

TASK [ssh_client : Generieren und kopieren der SSH Client Konfiguration ~/.ssh/config.] *******************************************
ok: [localhost]

PLAY RECAP *************************************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Lassen wir es doch mal von der Kuh erklären, dann sieht so was schon anders aus. =)

< PLAY [ssh_client_config.yml] >
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

< TASK [Gathering Facts] >
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ok: [localhost]
< TASK [ssh_client : include_tasks] >
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

included: /home/django/ansible/roles/ssh_client/tasks/client_config.yml for localhost
/ TASK [ssh_client : Generieren und kopieren der SSH Client \
\ Konfiguration ~/.ssh/config.]                             /
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ok: [localhost]
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
PLAY RECAP *************************************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Wie kommt man nun zu dieser netten und spassigen Kuh. Nun ganz einfach, wie installieren einfach das Paket cowsay.

  • Arch :
     $ pacman -S cowsay
  • Fedora / RHEL :
     # yum install cowsay


     # dnf install cowsay
  • Gentoo :
     # emerge -av cowsay
  • openSUSE :
     $ sudo zypper in cowsay
  • Ubuntu / Debian :
     $ sudo apt-get install cowsay

Wie es sich natürlich für jedes richtige Programm gehört, verfügt cowsay selbstverständlich auch über eine entsprechende man-page!

$ man cowsay

COWSAY(6)                                                Games Manual                                                COWSAY(6)

       cowsay/cowthink - configurable speaking/thinking cow (and a bit more)

       cowsay [-e eye_string] [-f cowfile] [-h] [-l] [-n] [-T tongue_string] [-W column] [-bdgpstwy]

       Cowsay generates an ASCII picture of a cow saying something provided by the user.  If run with no arguments, it accepts
       standard input, word-wraps the message given at about 40 columns, and prints the cow saying the given message on  stan‐
       dard output.

       To  aid  in  the use of arbitrary messages with arbitrary whitespace, use the -n option.  If it is specified, the given
       message will not be word-wrapped.  This is possibly useful if you want to make the cow think or speak in figlet(6).  If
       -n is specified, there must not be any command-line arguments left after all the switches have been processed.

       The -W specifies roughly where the message should be wrapped.  The default is equivalent to -W 40 i.e. wrap words at or
       before the 40th column.

       If any command-line arguments are left over after all switches have been processed, they become the cow's message.  The
       program will not accept standard input for a message in this case.

       There  are several provided modes which change the appearance of the cow depending on its particular emotional/physical
       state.  The -b option initiates Borg mode; -d causes the cow to appear dead; -g invokes greedy mode; -p causes a  state
       of  paranoia to come over the cow; -s makes the cow appear thoroughly stoned; -t yields a tired cow; -w is somewhat the
       opposite of -t, and initiates wired mode; -y brings on the cow's youthful appearance.

       The user may specify the -e option to select the appearance of the cow's eyes, in which case the first  two  characters
       of  the  argument  string  eye_string  will  be used.  The default eyes are 'oo'.  The tongue is similarly configurable
       through -T and tongue_string; it must be two characters and does not appear by default.  However, it does appear in the
       'dead' and 'stoned' modes.  Any configuration done by -e and -T will be lost if one of the provided modes is used.

       The  -f  option specifies a particular cow picture file (``cowfile'') to use.  If the cowfile spec contains '/' then it
       will be interpreted as a path relative to the current directory.  Otherwise, cowsay will search the path  specified  in
       the COWPATH environment variable.  To list all cowfiles on the current COWPATH, invoke cowsay with the -l switch.

       If the program is invoked as cowthink then the cow will think its message instead of saying it.

       A  cowfile  is  made  up  of a simple block of perl(1) code, which assigns a picture of a cow to the variable $the_cow.
       Should you wish to customize the eyes or the tongue of the cow, then the variables $eyes and $tongue may be used.   The
       trail  leading  up  to  the cow's message balloon is composed of the character(s) in the $thoughts variable.  Any back‐
       slashes must be reduplicated to prevent interpolation.  The name of a cowfile should end with .cow, otherwise it is as‐
       sumed not to be a cowfile.  Also, at-signs (``@'') must be backslashed because that is what Perl 5 expects.

       What older versions? :-)

       Version  3.x  is fully backward-compatible with 2.x versions.  If you're still using a 1.x version, consider upgrading.
       And tell me where you got the older versions, since I didn't exactly put them up for world-wide access.

       Oh, just so you know, this manual page documents version 3.03 of cowsay.

       The COWPATH environment variable, if present, will be used to search for cowfiles.  It contains a colon-separated  list
       of  directories, much like PATH or MANPATH.  It should always contain the /usr/share/cowsay/cows directory, or at least
       a directory with a file called default.cow in it.

       /usr/share/cowsay/cows holds a sample set of cowfiles.  If your COWPATH is not explicitly set,  it  automatically  con‐
       tains this directory.

       If there are any, please notify the author at the address below.

       Tony  Monroe  (,  with suggestions from Shannon Appel (appel@CSUA.Berkeley.EDU) and contributions from An‐
       thony Polito (aspolito@CSUA.Berkeley.EDU).

       perl(1), wall(1), nwrite(1), figlet(6)

                                                 $Date: 1999/11/04 19:50:40 $                                        COWSAY(6)


Will man keine Kuh mehr sehen, dann kann man diese temporär durch Nutzung der Option ANSIBLE_NOCOWS=1 beim Aufruf eines Playbook unterdrücken.

 $ ANSIBLE_NOCOWS=1 ansible-playbook playbooks/ssh_client_config.yml

Dauerhaft kann man natürlich das Paket wieder deinstallieren bzw. in der Ansible-Konfigurationsdatei den Parameter nocows = True setzen.

 $ vim ~/.ansible.cfg
nocows          = True

Alternative Ausgaben

Ist man der Kuh überdrüssig, kann man sich auch einiges anderes Getier auf den Bildschirm holen. Was es alles gibt findet man mit dem Befehl cowsay -l heraus.

 $ cowsay -l
Cow files in /usr/share/cowsay/cows:
apt bud-frogs bunny calvin cheese cock cower daemon default dragon
dragon-and-cow duck elephant elephant-in-snake eyes flaming-sheep fox
ghostbusters gnu hellokitty kangaroo kiss koala kosh luke-koala
mech-and-cow milk moofasa moose pony pony-smaller ren sheep skeleton
snowman stegosaurus stimpy suse three-eyes turkey turtle tux unipony
unipony-smaller vader vader-koala www

Der SUSE-Enthusiast wird sich vermutlich an der Option suse erfreuen:

< TASK [Gathering Facts] >
  /@    ~-.
  \/ __ .- |
   // //  @

Auch der Kandidat hier, ist sicherlich den allermeisten wohl bekannt…

/ TASK [ssh_client : Generieren und kopieren der SSH Client \
\ Konfiguration ~/.ssh/config.]                             /
    ."'=-,     ,.,.,_
   (_____ )."=`      `"=,
  ./_ _  \`\             `;..
 / (o(o) |\=\              ; `;
(_/|     | \ |             ;`"`
   |     |  `             ;
   \ ..  /`,_          _.'
    `---'   `#"#""'"#'#^
             # #    # #  
             # #    # #
             # #    # #
            /#|#\  /#|#\

ok: [localhost]

… und mein ganz persönlicher Favorit:

< PLAY [ssh_client_config.yml] >
  c , _,{
  /\  @ )                 __
 /  ^~~^\          <=.,__/ '}=
(_/ ,, ,,)          \_ _>_/~

Natürlich gibt es auch etwas für die Puristen und ernsthaft arbeitenden Administratoren. Die Standardausgabe von Ansible kennen wir bereits:

~/ansible [main]
15:26 $ ansible-playbook playbooks/ssh_client_config.yml
PLAY [ssh_client_config.yml] *****************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************
ok: [localhost]

TASK [ssh_client : include_tasks] ************************************************************************************
included: /home/django/ansible/roles/ssh_client/tasks/config.yml for localhost

TASK [ssh_client : Generieren und kopieren der SSH Client Konfiguration ~/.ssh/config.] ******************************
changed: [localhost]

TASK [ssh_client : include_tasks] ************************************************************************************
included: /home/django/ansible/roles/ssh_client/tasks/known_hosts.yml for localhost

TASK [ssh_client : Generieren und kopieren der /etc/ssh/ssh_known_hosts.] ********************************************
ok: [localhost]

PLAY RECAP ***********************************************************************************************************
localhost                  : ok=5    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Besonders bei doch sehr umfangreichen Playbooks wünscht man sich dann doch eine stark gestraffte Ausgabe, wie z.B. die das nachfolgende Beispiel zeigt.

~/ansible [main]
17:43 $ ansible-playbook playbooks/ssh_client_config.yml
[17:43:22] Gathering Facts
↳  localhost | SUCCESS | 1.73s
[17:43:24] ssh_client : include_tasks
↳  localhost | SUCCESS | 6ms
[17:43:24]     ↳ config: Generieren und kopieren der SSH Client Konfiguration ~/.ssh/config.
↳  localhost | CHANGED | 1.64s
[17:43:26] ssh_client : include_tasks
↳  localhost | SUCCESS | 5ms
[17:43:26]     ↳ known_hosts: Generieren und kopieren der /etc/ssh/ssh_known_hosts.
↳  localhost | SUCCESS | 521ms
[17:43:26] system
-- Play recap --
localhost                  : ok=5    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Für dieses kompakte Ausgabeformat nutzt man den Ansible Stdout Compact Logger.

Die Installation ist relativ schnell erledigt, da wir uns hierzu lediglich das Python-Script von der GitHub-Seite herunterladen und im Verzeichnis ~/.ansible/plugins/callback ablegen müssen. Legen wir uns als erstes das betreffende Unterverzeichnis an.

 $ mkdir -p ~/.ansible/plugins/callback

Anschließend holen wir uns das Python-Script und speicher es direkt in gerade angelegten Plugin-Verzeichnis unserer Ansible-Installation.

 $ curl \
        -o ~/.ansible/plugins/callback/

Die Konfiguration für die kompakte Ausgabe des Ansible Stdout Compact Logger nehmen wir in der lokalen Userbezognen AnsibleKonfigurationsdatei ~/.ansible.cfg vor. Hier aktivieren wir die beiden Einträge stdout_callback=anstomlog sowie callback_plugins = ~/.ansible/plugins/callback.

 $ vim  ~/.ansible.cfg
# change the default callback, you can only have one 'stdout' type  enabled at a time.
#stdout_callback = skippy
# set plugin path directories here, separate with colons
#action_plugins     = /usr/share/ansible/plugins/action
#become_plugins     = /usr/share/ansible/plugins/become
#cache_plugins      = /usr/share/ansible/plugins/cache                                                                
#callback_plugins   = /usr/share/ansible/plugins/callback
callback_plugins   = ~/.ansible/plugins/callback
#connection_plugins = /usr/share/ansible/plugins/connection
#lookup_plugins     = /usr/share/ansible/plugins/lookup
#inventory_plugins  = /usr/share/ansible/plugins/inventory
#vars_plugins       = /usr/share/ansible/plugins/vars
#filter_plugins     = /usr/share/ansible/plugins/filter
#test_plugins       = /usr/share/ansible/plugins/test
#terminal_plugins   = /usr/share/ansible/plugins/terminal
#strategy_plugins   = /usr/share/ansible/plugins/strategy

Zum Schluss können wir uns noch vergewissern, ob die Installation und Konfiguration auch erfolgreich war. Hierzu rufen wir das Pythonscript ohne weitere Parameter direkt auf.

 $ python3 ~/.ansible/plugins/callback/
Ran 12 tests in 0.000s


Rufen wir nun ein doch etwas umfangreicheres Playbook auf, haben wir nun eine kompakte Zusammenfassung aller relevanten Vorgänge und kein doch eher aufgeblähtes Ausgabe mit vielen ***- und Leer-Zeilen.

~/ansible [main]
18:23 $ ansible-playbook playbooks/kvm_arch_iso.yml
[18:23:34]   ↳ arch_iso: Keyring orgdnungsgemäß initialisieren.
↳  vml000202 | SUCCESS | 1.12s
[18:23:35]   ↳ arch_iso: Default Schlüssel neu laden.
↳  vml000202 | SUCCESS | 4.44s
[18:23:39]   ↳ arch_iso: System aktualisieren.
↳  vml000202 | SUCCESS | 1.38s
[18:23:41]   ↳ arch_iso: ggf. vorhandene Altlasten beseitigen.
↳  vml000202 | CHANGED | 6.09s
[18:23:47]   ↳ arch_iso: Installation des Paketes archiso.
↳  vml000202 | SUCCESS | 2.24s
[18:23:49]   ↳ arch_iso: Verzeichnis releng kopieren.
↳  vml000202 | SUCCESS | 497ms
[18:23:50]   ↳ arch_iso: Verzeichnis für den systemd autostart des sshd anlegen.
↳  vml000202 | SUCCESS | 484ms
[18:23:50]   ↳ arch_iso: symbolic-link für den Autostart des SSHD setzen.
↳  vml000202 | SUCCESS | 500ms
[18:23:51]   ↳ arch_iso: Tage berechnen die seit dem 01.01.1970 vergangen sind.
↳  vml000202 | SUCCESS | 523ms
[18:23:51]   ↳ arch_iso: Ergebnis in einer Variable zur weiteren Bearbeitung vorhalten.
↳  vml000202 | SUCCESS |  31ms
[18:23:51]   ↳ arch_iso: Root-Passwort in der /etc/shadow Datei ablegen.
↳  vml000202 | CHANGED | 1.10s
[18:23:52]   ↳ arch_iso: Verzeichnis für den ssh-key beim User Root anlegen.
↳  vml000202 | CHANGED | 537ms
[18:23:53]   ↳ arch_iso: SSH-Key für den Zugriff für root hinterlegen.
↳  vml000202 | CHANGED | 917ms
[18:23:54]   ↳ arch_iso: Autologin des Users root deaktivieren.
↳  vml000202 | SUCCESS | 518ms
[18:23:54]   ↳ arch_iso: broadcom-wl aus der zu installierenden Pakete löschen.
↳  vml000202 | CHANGED | 576ms
[18:23:55]   ↳ arch_iso: ISO erstellen.
↳  vml000202 | SUCCESS | 8m12s
[18:32:07]   ↳ arch_iso: Installation des Paketes apache.
↳  vml000202 | SUCCESS | 2.13s
[18:32:09]   ↳ arch_iso: http.conf anpassen.
↳  vml000202 | SUCCESS | 997ms
[18:32:10]   ↳ arch_iso: Sicherstellen, dass der HTTP-Daemon startet.
↳  vml000202 | SUCCESS | 942ms
[18:32:11]   ↳ arch_iso: Datum ermitteln.
↳  vml000202 | SUCCESS | 466ms
[18:32:12]   ↳ arch_iso: Ergebnis in einer Variable zur weiteren Bearbeitung vorhalten.
↳  vml000202 | SUCCESS | 24ms
[18:32:12]   ↳ arch_iso: ISO auf dem KVM-Wirt I holen.
↳  vml000202 -> kvm | CHANGED | 17.35s
[18:32:29]   ↳ arch_iso: ISO auf dem KVM-Wirt II holen.
vml000202 | UNREACHABLE!: Failed to connect to the host via ssh: Permission denied (publickey,password).
[18:32:29] system
-- Play recap --
vml000202                  : ok=22    changed=6    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0

Ohne die kompakte Ausgabe mit Hilfe des Ansible Stdout Compact Logger würde die Ausgabe des obigen Beispiels mehrere Bildschirmseiten füllen!

O.K., cowsay - warum gibt es das überhaupt?

Warum nicht? cowsay ist ein bisschen Spass in einer Umgebung, die normalerweise ziemlich „trocken“ und langweilig ist. Die Option ANSIBLE_COW_SELECTION=random bringt wie der Namen schon sagt, zufällige ASCII-Geschöpfe auf den Bildschirm - Langeweile kommt so nicht auf - O.K. beim Ausmachen eines grossen Mehrwerts wird man sich vermutlich auch schwer tun. Aber ein wenig Spass muss auch ab und an sein, oder? :-P

Natürlich wird man bei grossen und umfangreichen Orchestrierungsaufgaben eher auf die Verwendung des Ansible Stdout Compact Logger zurück greifen. Hat man so doch schneller einen Überblick über den kompletten Anlauf einer Orchestrierungsaufgabe - Spass hin oder her, aber im Zweifels- und Debugging-Fall ist in aller Regel doch eher schnell Schluss mit lustig! :UP:


Diese Website verwendet Cookies. Durch die Nutzung der Website stimmen Sie dem Speichern von Cookies auf Ihrem Computer zu. Außerdem bestätigen Sie, dass Sie unsere Datenschutzbestimmungen gelesen und verstanden haben. Wenn Sie nicht einverstanden sind, verlassen Sie die Website.Weitere Information
  • linux/ansible/playbook_example_12.txt
  • Zuletzt geändert: 17.03.2024 15:00.
  • von django