Ansible-Lint: Die Fusselbürste
Frei übersetzt könnte man Ansible-Lint auch als die Ansible Fusselbürste übersetzen. Das real physikalische Pondon wird ja meist benutzt um z.B. Tierhaare oder Schuppen von angesagter dunkler Kleidung nachhaltig zu bekommen. Gehässige Stimmen meinen nun, mit Ansible-Lint würde es sich ähnlich verhalten, man könne nur geringfügige „Schmutzpartikel“ entfernen. Ansible-Lint kann aber bei richtiger Betrachtung, Verwendung und Bewertung der gemeldeten „Promlemstellungen“ doch mehr.
Beim linting werden mit Hilfe eines statischen Code-Analyse-Tools können stilistische Fehler im Code aufgespürt werden und kommt häufig bei dynamisch typisierte Sprachen wie JavaScript und Python zum Einsatz. Das Kommandozeilen-Tool ansible-lint
richtet sich an alle Ansible-Nutzer die wert darauf legen, ihre Playbooks, Rollen und Code-Sammlungen entsprechend einheitlich, strukturiert und code-technisch sauber zu halten. Das Hauptziel, welches hier verfolgt wird ist, bewährte Praktiken, Muster und Verhaltensweisen zu fördern sowie gleichzeitig häufige Fallstricke zu vermeiden, die leicht zu Fehlern führen und dabei die Wartung des Codes erschweren können.
Natürlich sind dabei die Ergebnisse und Rückmeldungen, die beim ansible-lint
-Aufruf zurückgemeldet werden, nicht der Weisheit letzten Schluss. Diese sollten immer individuell bewerten, entsprechende Fehler im Code korrigiert werden, oder auch Konfigurationsoptionen bei Ansible-Lint gesetzt werden, die spezifische false-positive Meldungen unterdrücken.
Installation
Bevor wir uns nun eingehender mit ansible-lint
beschäftigen installieren wir das Programm-Paket mit Hilfe des Paketverwaltungs-Tools unserer Distribution.
- Arch :
$ pacman -S ansible-lint
- Fedora / RHEL :
# yum install ansible-lint
- Gentoo :
# emerge -av ansible-lint
- openSUSE :
$ sudo zypper in ansible-lint
- Ubuntu / Debian :
$ sudo apt-get install ansible-lint
Dokumentation
Hilfe-Option
Was Ansible-Lint alles an Befehlsoptionen mitbringt, offenbart uns die der Programmaufruf mit der Option help
.
$ ansible-lint --help
usage: ansible-lint [-h] [-L] [-f {rich,plain,rst,codeclimate,quiet,pep8}] [-q] [-p] [--parseable-severity] [--progressive] [--project-dir PROJECT_DIR] [-r RULESDIR] [-R] [--show-relpath] [-t TAGS] [-T] [-v] [-x SKIP_LIST] [-w WARN_LIST] [--enable-list ENABLE_LIST] [--nocolor] [--force-color] [--exclude EXCLUDE_PATHS] [-c CONFIG_FILE] [--offline] [--version] [lintables ...] positional arguments: lintables One or more files or paths. When missing it will enable auto-detection mode. options: -h, --help show this help message and exit -L list all the rules -f {rich,plain,rst,codeclimate,quiet,pep8} Format used rules output, (default: rich) -q quieter, reduce verbosity, can be specified twice. -p parseable output, same as '-f pep8' --parseable-severity parseable output including severity of rule --progressive Return success if it detects a reduction in number of violations compared with previous git commit. This feature works only in git repositories. --project-dir PROJECT_DIR Location of project/repository, autodetected based on location of configuration file. -r RULESDIR Specify custom rule directories. Add -R to keep using embedded rules from /usr/lib/python3/dist-packages/ansiblelint/rules -R Keep default rules when using -r --show-relpath Display path relative to CWD -t TAGS only check rules whose id/tags match these values -T list all the tags -v Increase verbosity level (-vv for more) -x SKIP_LIST only check rules whose id/tags do not match these values -w WARN_LIST only warn about these rules, unless overridden in config file defaults to 'experimental' --enable-list ENABLE_LIST activate optional rules by their tag name --nocolor disable colored output, same as NO_COLOR=1 --force-color Force colored output, same as FORCE_COLOR=1 --exclude EXCLUDE_PATHS path to directories or files to skip. This option is repeatable. -c CONFIG_FILE Specify configuration file to use. Defaults to ".ansible-lint" --offline Disable installation of requirements.yml --version <code> ==== man-page ==== In der Man-Page des Python Scripts finden sich noch ein paar weitere Optionen, die dort beschrieben sind. $ man ansible-lint <code>ANSIBLE-LINT(1) System administration commands ANSIBLE-LINT(1) NAME ansible-lint - lint tool for Ansible playbooks SYNOPSIS ansible-lint [-M module_path] [-l] [-s] [module...] DESCRIPTION ansible-lint checks Ansible playbooks for practices and behaviour that could potentially be improved. OPTIONS --version: show program’s version number and exit -M DIRECTORY, --module-path=DIRECTORY the DIRECTORY search path to load modules from. The default is /usr/share/ansible. This can also be set with the ANSIBLE_LIBRARY environment variable. -s, --snippet= Produce a snippet which can be copied into a playbook for modification, like a kind of task template. -l, --list= Produce a terse listing of modules and a short description of each. -h, --help show this help message and exit -L list all the rules -q quieter, although not silent output -p parseable output in the format of pep8 -r RULESDIR specify one or more rules directories using one or more -r arguments. Any -r flags override the default rules in /usr/lib/python3/dist-packages/ansiblelint/rules, unless -R is also used. -R Use default rules in /usr/lib/python3/dist-packages/ansiblelint/rules in addition to any extra rules directories specified with -r. There is no need to specify this if no -r flags are used -t TAGS only check rules whose id/tags match these values -T list all the tags -v Increase verbosity level -x SKIP_LIST only check rules whose id/tags do not match these values --nocolor disable colored output --force-color Try force colored output (relying on ansible’s code) -M DIRECTORY, --module-path=DIRECTORY the DIRECTORY search path to load modules from. The default is /usr/share/ansible. This can also be set with the ANSIBLE_LIBRARY environment variable. -s, --snippet= Produce a snippet which can be copied into a playbook for modification, like a kind of task template. -l, --list= Produce a terse listing of modules and a short description of each. -h, --help show this help message and exit -L list all the rules -q quieter, although not silent output -p parseable output in the format of pep8 -r RULESDIR specify one or more rules directories using one or more -r arguments. Any -r flags override the default rules in /usr/lib/python3/dist-packages/ansiblelint/rules, unless -R is also used. -R Use default rules in /usr/lib/python3/dist-packages/ansiblelint/rules in addition to any extra rules directories specified with -r. There is no need to specify this if no -r flags are used -t TAGS only check rules whose id/tags match these values -T list all the tags -v Increase verbosity level -x SKIP_LIST only check rules whose id/tags do not match these values --nocolor disable colored output --force-color Try force colored output (relying on ansible’s code) --exclude=EXCLUDE_PATHS path to directories or files to skip. This option is repeatable. AUTHOR ansible-lint was originally written by Will Thames COPYRIGHT Copyright © 2013-2016 Will Thames <will@thames.id.au> ansible-lint is released under the terms of the MIT License. SEE ALSO ansible-playbook(1), ansible(1) ansible-lint 08/12/2017 ANSIBLE-LINT(1)
Online-Dokumentation
Eine weitaus aussagekräftigere Dokumentation zu Ansible-Lint findet sich in der Online-Dokumentation des Projektes!
Verwendung
Aufruf
Die Verwendung der „Fusselbürste“ aka Ansible-Lint ist denkbar einfach. Im einfachsten Fall muss lediglich das Python-Script gefolgt mit dem zu prüfenden Objekt aufgefrufen werden. Beispiele:
- Eine spezifische YML-Datei:
$ ansible-lint ~/ansible/roles/inventory/tasks/harvester.yml
- Eine Rolle:
$ ansible-lint ~/ansible/roles/fetch_exporter/
- Ein einzelnes Playbook:
$ ansible-lint ~/ansible/playbooks/ansible_grundconfig_v2.yml
- Alle Playbooks:
$ ansible-lint ~/ansible/playbooks/
Rückmeldungen
Ist alles O:K: wird UNIX-like keinerlei Rückmeldung gegeben.
Im Fehlerfall hingegen erfolgt eine detaillierte Rückmeldung und auch schon meist ein Hinweis, was denn schief gelaufen sein könnte.
Bsp.:
$ ansible-lint playbooks/linting_demo.yml
WARNING Listing 1 violation(s) that are fatal
literal-compare: Don't compare to literal True/False
playbooks/linting_demo.yml:23 Task/Handler: Fehlerhinweis im Fehlerfall ausgeben
You can skip specific rules or tags by adding them to your configuration file:
# .ansible-lint
warn_list: # or 'skip_list' to silence them completely
- literal-compare # Don't compare to literal True/False
Finished with 1 failure(s), 0 warning(s) on 1 files.
Beim Task Fehlerhinweis im Fehlerfall ausgeben ab Zeile 23 sollte man also nicht gegen True
sondern besser gegen !
oder 0
prüfen. Gesagt getan:
$ vim +23 playbooks/linting_demo.yml
Nach Korrektur des Fehlers und abermaligen ansible-lint
-Aufruf erfolgt keinerlei Fehlermeldung, also ist in diesem Beispiel alles wieder in Butter.
Ein oft gemeldeter Fehler, der sehr leicht korrigiert werden kann, sind Leerzeichen, die am Zeilenende zu viel sind.
WARNING Listing 1 violation(s) that are fatal
yaml: trailing spaces (trailing-spaces)
playbooks/linting_demo.yml:36
You can skip specific rules or tags by adding them to your configuration file:
# .ansible-lint
warn_list: # or 'skip_list' to silence them completely
- yaml # Violations reported by yamllint
Finished with 1 failure(s), 0 warning(s) on 1 files.
Vergißt mann aber z.B. die Dateirechte beim Anlegen richtig zu setzen, bekommt man einen entsprechenden Hinweis präsentiert.
$ ansible-lint playbooks/ssh_client_config.yml
WARNING Listing 1 violation(s) that are fatal
risky-file-permissions: File permissions unset or incorrect
roles/ssh_client/tasks/client_config.yml:4 Task/Handler: Generieren und kopieren der SSH Client Konfiguration ~/.ssh/config.
You can skip specific rules or tags by adding them to your configuration file:
# .ansible-lint
warn_list: # or 'skip_list' to silence them completely
- experimental # Violations reported by yamllint
Finished with 0 failure(s), 1 warning(s) on 7 files.
Beim folgenden Beispiel bekommen wir eine Fehlermeldung präsentiert, deren wir uns aber nicht anschließen wollen und diese Fehlermeldung als „O:K:“ akzeptieren wollen.
$ ansible-lint playbooks/ansible_grundconfig_v2.yml
WARNING Listing 1 violation(s) that are fatal
package-latest: Package installs should not use latest
playbooks/ansible_grundconfig_v2.yml:142 Task/Handler: Passwort-Manager pass installieren
You can skip specific rules or tags by adding them to your configuration file:
# .ansible-lint
warn_list: # or 'skip_list' to silence them completely
- package-latest # Package installs should not use latest
Finished with 1 failure(s), 0 warning(s) on 1 files.
Gesagt, getan - wir werden also dem Vorschlag folgen und einen entsprechenden Eintrag in der .ansible-lint
-Datei in unserem Arbeitsverzeichnis anlegen.
$ vim ~/ansible/.ansible-lint
- .ansible-lint
# .ansible-lint warn_list: # or 'skip_list' to silence them completely - package-latest # Package installs should not use latest
Ein erneuter Ansible-Lint-Aufruf bringt nun:
$ ansible-lint playbooks/ansible_grundconfig_v2.yml
WARNING Listing 1 violation(s) that are fatal
package-latest: Package installs should not use latest
playbooks/ansible_grundconfig_v2.yml:142 Task/Handler: Passwort-Manager pass installieren
Finished with 0 failure(s), 1 warning(s) on 1 files.
Will man diese Meldung gar nicht mehr sehen, benutzt man statt warn_list
entsprechend skip_list
in der Ansible-lint Konfigurationsdatei.
$ vim ~/ansible/.ansible-lint
- .ansible-lint
# .ansible-lint skip_list: # to silence them completely - package-latest # Package installs should not use latest
Ein erneuter Ansible.Lint-Aufruf bringt nun:
$ ansible-lint playbooks/ansible_grundconfig_v2.yml
Schon ist die Fehler-/Warmeldung auch verschwunden.
Fazit und Ausblick
Man darf von ansible-lint
keine Wunder erwarten, aber man hat mit diesem Python-Script ein Werkzeug an der Hand, mit dem man durchaus seinen Code einheitlich, strukturiert und code-technisch sauber zu halten vermag. Somit kann man guten Gewissens bestätigen, dass das Hauptziel sein kann, bewährte Praktiken, Muster und Verhaltensweisen zu fördern sowie gleichzeitig häufige Fallstricke zu vermeiden, die leicht zu Fehlern führen und dabei die Wartung des Codes erschweren können. Vor allem bei gemeinschaftlich genutzten und gepflegten Code kann sich das durchaus als sehr hilfreich heraus kristallisieren.