Inhaltsverzeichnis

Ansible

Ansible ist ein Open-Source Automatisierungs-Werkzeug zur Orchestrierung und allgemeinen Konfiguration und Administration von Computern. Es kombiniert Softwareverteilung, Ad-hoc-Kommando-Ausführung und Konfigurationsmanagement. Es verwaltet Netzwerkcomputer unter anderem über SSH und erfordert keinerlei zusätzliche Software auf dem zu verwaltenden System. Module nutzen zur Ausgabe JSON und können in jeder beliebigen Programmiersprache geschrieben sein. Das System nutzt YAML zur Formulierung wiederverwendbarer Beschreibungen von Systemen. Quelle: Wikipedia

Ansible ist in Python implementiert und führt Befehle über SSH aus.

Begriffe

Playbook-läufe auswerten

Am Ende jedes Laufes wird ein „Play Recap“ angezeigt:

PLAY RECAP **********************************************************************************************
Host1      : ok=6    changed=1    unreachable=0    failed=0    skipped=3    rescued=0    ignored=0

Bedeutung:

Ausgaben mit callback plugins verändern

Wiederholbarkeit (Idempotenz)

Definition von Idempotenz (engl. „idempotence“): „the property of certain operations in mathematics and computer science that can be applied multiple times without changing the result beyond the initial application“ (Quelle)

Generell geht darum bestimmte Aufgaben wiederholbar zu machen, d.h. eine Aufgabe sollte nicht bei jedem Lauf neu ausgeführt werden (was weitere Aktionen wie Server-restarts bedeuten kann) sondern nur wenn sich etwas ändert. Das Ergebnis sollte aber auch jedes mal die gleiche sein.

Installation

Grundsätzlich ist es möglich die Paketquelle der Distribution zu benutzen und auch Python und Jinja2 darüber zu installieren. Ich rate allerdings davon ab weil die Entwicklung bei Ansible und Python (incl. jinja2) schneller geht als man den ausführenden Rechner aktuell halten kann (und der ist entscheidend weil dort der Code geparst wird!).

Mit pip können die installierte Version schnell und unabhängig vom System verändert werden.

pip kommt mit dem Paket python3-pip oder über andere Methoden.

Systemweit

nur für den aktuellen Benutzer (nach /.local/bin):

:!: Nach der Installation sollte verifiziert werden das ansible auch wirklich python3 benutzt (mit Version 2 gibt es zunehmend Problem aktuelle Module nachzuinstallieren):

ansible --version | grep "python version"

Der Ablauf der Interpreter discovery wird hier erklärt, auf den Zielhost wird oft noch python2 benutzt wenn der Stand-Python-Interpreter auf python2 steht.

Überschreiben lässt sich dies z.B. mit group_vars/all:

ansible_python_interpreter: /usr/bin/python3

Ansible 2.9.x issues

ansible versionsupgrade auf 2.10.x

# direkt auf ansible 2.10 geht nicht:
# pip3 install --upgrade ansible
 
pip3 uninstall ansible
 
pip3 install ansible
# ansible-base ist dependency!

Neuer Begriff: fcdn (fully qualified community module)→ module clash wenn Name gleich in unterschiedlichen collections. Siehe Ausgaben von „-vv“ Text ähnlich „redirecting (type: modules)“.

ansible-galaxy collection install community.general

upgrades allgemein

Portin guides

upgrade auf ansible 2.10

Integrierte module sollten mit dem fully-qualified collection name (FQCN) angesprochen werden, siehe auch: Liste aller Module.

https://docs.ansible.com/ansible/devel/porting_guides/porting_guide_2.10.html

upgrade auf ansible 3.0/4.0

Statt 2.11 wurde Version 3.x veröffentlicht, 2.12 ist dann 4.x. minor releases sind dann 3.1, 3.2, … bzw 4.1, 4.2 … usw. Neben der Migration von Rollen in Community-Roles wurde eine gemeinsame requirements-Datei für roles und collections eingeführt:

---
# ansible-galaxy install -r requirements.yml

roles:
  - src: geerlingguy.git
collections:
  - name: community.zabbix

:!: ansible-lint kann aber weiterhin nur automatisch roles/requirements.yml bzw. collections/requirements.yml benutzen. Und ansible-semaphore hat dafür auch keinen support und nur einen teilweise fix.

Eine saubere Installation via pip: pip3 uninstall ansible ansible-base ansible-core && pip3 install 'ansible<4.4'

upgrade von modulen

Mittlerweile sind die meisten module in die comunity (oder andere) collection gewandert. Diese lassen sich einzeln upgraden: ansible-galaxy collection install community.general –upgrade eine spezielle Version wird so installiert: ansible-galaxy collection install community.general:==X.Y.Z

Diese liegen dann in ~/.ansible/collections/ansible_collections.

git Struktur

ansible.cfg
.ansible-lint
collections/requirements.yml
group_vars/all
host_vars/.gitkeep
hosts
playbook1.yml
README.md
roles/requirements.yml
templates/.gitkeep
vault.yml

Einen Ordner „playbooks“ anzulegen, würde ich nicht unbedingt empfehlen, dann müssen die Rollen und Collections unterhalb dieses Ordner legen (u.a. ansible semaphore, ansible-lint suchen dann immer unterhalb des Ausführungsordners nach roles/requirements.yml bzw. collections/requirements.yml, da müsste man mit u.U. symlinks arbeiten was die Sache evtl. nicht wert ist).

Beispielsetup ansible-master

Anforderung: Login via eigenem Systembenutzer, gemeinsames Repo und Vault 3). gemeinsame Gruppe: admins

Setup des Editors

Yaml verträgt keine Tabs, die müssen vom Editor in Leerzeichen umgewandelt werden. Jeder Editor hat hier seine eigenes Einstellungsformat.

Beispiel für globale Einstellungen:

vim 4) ~/.vimrc oder ~/.vim/vimrc:

set tabstop=2
set shiftwidth=2
set expandtab
# autocmd Filetype yml setlocal tabstop=2

nano (~/.nanorc):

set tabsize 2
set tabstospaces

Playbook sudo mit passwort

Das Passwort kann aus einer Umgebungsvariable kommen (hier ansible_become_pass:

ansible-playbook --extra-vars "ansible_sudo_pass=$ansible_become_pass" [...]

oder durch andere methoden (aus einer subshell, keepass etc. siehe https://stackoverflow.com/questions/21870083/specify-sudo-password-for-ansible ).

per playbook:

- hosts: all
  become: yes
  become_user: 'root'
  become_method: 'sudo'

  tasks:
  - name: whoami
    ansible.builtin.command: id
    register: id

  - name: Show whoami
    ansible.builtin.debug: msg="{{ id.stdout_lines }}"

das ganze geht auch per task oder global in der ansible.cfg:

[privilege_escalation]
become = True
become_method=sudo

Siehe auch: https://docs.ansible.com/ansible/latest/user_guide/become.html

Konfiguration

SSH-Fingerprint check

Problem: Bei neue Hosts sind die Fingerprints lokal unbekannt, d.h. Ansible scheitert an der interaktiven Nachfrage von SSH (ob der Fingerprint akzeptiert werden soll).

Das könnte auf zwei Arten gelöst werden:

  1. Entweder man deaktiviert den Check komplett
    1. per Config (es werden alle Fingerprints ignoriert): in ansible.cfg (/etc/ansible/ansible.cfg oder ~/.ansible.cfg)
      [defaults]
      host_key_checking = False
  2. fallweise über Umgebungsvariable (ANSIBLE_HOST_KEY_CHECKING = False), z.B. mit export ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook …
  3. etwas unschöner auch über die SSH-Config (fallweise –ssh-common-args='-o StrictHostKeyChecking=no' bzw. permanent)
  4. oder einen task schreiben um die neuen Fingerprints lokal abzulegen:
      - name: Write the new ec2 instance host key to known hosts
        connection: local
        ansible.builtin.shell: "ssh-keyscan -H {{ inventory_hostname }} >> ~/.ssh/known_hosts"

Quellen: https://stackoverflow.com/questions/32297456/how-to-ignore-ansible-ssh-authenticity-checking

Firewallfreischaltungen

Firewallfreischaltungen für ansible-Rollen:

PIP:

github:

docker

ansible-galaxy

Ablage: .ansible/roles bzw. ~/.ansible/collections/ansible_collections/

ad-hoc Befehle ausführen

Beispiel: das inventory in der Datei hosts enthält ein Gruppe „meine-Server“ auf denen der Befehl „uname -a“ ausgeführt werden soll: ansible -i hosts meine-Server -a 'uname -a'

Ansible vault

Passwort (für den vault) angeben:

Verwaltung des Vault-files:

verschlüsselte Zeichenketten

Statt eines vault-files sind auch einzelne verschlüsselte Zeichenketten (encrypt_string) möglich, beispielweise z.B. um einzelne Variablen zu befüllen.

Beispiel: Hier bekommt die Variable DB_password den Inhalt „test“, was mit Passwort „test“ verschlüsselt wird:

→ diese Ausgabe kann direkt in yaml-Dateien benutzt werden.

Ein Playbook das verschlüsselte vault-strings benutzt muss von nun an bei m Aufruf entschlüsselt werden: ansible-playbook site.yml --ask-vault-pass

In awx/tower muss der credential type=Vault vorhanden sein: https://docs.ansible.com/ansible-tower/latest/html/userguide/credentials.html#id13

Verwendung von vault files in playbooks

Ansible muss wissen das Variablen im vault-file liegen:

  vars_files:
    - myVaultfile.yml

mehrere Benutzer (Vault-IDs)

–vault-id @prompt

https://docs.ansible.com/ansible/latest/user_guide/vault.html#vault-ids-and-multiple-vault-passwords

in awx/tower: https://docs.ansible.com/ansible-tower/3.4.0/html/administration/multi-creds-assignment.html#ag-multi-vault

ansible-pull

ansible-pull kann sich selbst playbooks aus einem entfernten Repo ziehen, für einige Anwendungsfälle (kein Zugriff von Extern) ist das nötig.

ansible-pull -U $url_gitrepo

Verwaltung

Verwaltungoberflächen

ansible automation plattform (AAP) / AWX / Tower

Red Hat Ansible Automation Platform Life Cycle Vergleich

https://github.com/ansible/awx / ansible automation plattform: unterstützt hop und excecution nodes 6) zur Ausführung komplexen Topologien (in anderen Netzen/Umgebungen), siehe https://media.ccc.de/v/clt23-147-konfigurationsmanagement-uber-verschiedene-netze-mit-awx#t=1522 .

AWX: simple Anleitung (Installation ohne k8s!): https://github.com/selfhostx/ansible/blob/main/instructions/awx-manual-install.txt

ansible Semaphore

ansible semaphore ist relativ simpel (aber funktional!), API, zeitgesteuert templates („cron“), interaktive Abfrage („survey“), alles wichtige ist dabei.

playbook: https://github.com/selfhostx/ansible/blob/main/playbooks/semaphore.yml / https://github.com/stefanux/ansible-role-semaphore

Reihenfolge bei der Einrichtung:

  1. Projekt anlegen
  2. deploy key oder access tokens (z.B. gitlab) bei git-Repo authorisieren
  3. Key store
    1. SSH-Zugriff System → Typ: ssh
    2. Repository-Zugriff → Typ: ssh oder access token (→Typ: login_password)
    3. vault password → Typ: login_password
  4. repo+branch hinzufügen
  5. Inventory (plain oder yaml): Achtung: User credentials wird für die Verbindung zum Host benutzt (SSH), also hier nicht den Access zum Repo angeben!
  6. Environment (minimal zwei mal { } )
  7. Template (task) anlegen mit den Details von oben

Zu beachten:

dynamische inventory

dynamische inventories werden nicht direkt unterstützt, können aber über override in templates angelegt werden:

[
  "-i",
  "./library/SKRIPT.py"
]

Inventory

Datei /etc/ansible/hosts umfasst alle Server die durch Ansible angesprochen/verwaltet werden. Es ist möglich die Server sinnvoll in [Gruppen] zu unterteilen. Es können außerdem Gruppen aus anderen Gruppen erstellt werden.

Wichtig ist dabei zu beachten:

Beispiel: „gruppen“ setzt sich zusammen aus gruppe1 und gruppe2:

[gruppen:children]
gruppe1
gruppe2

[gruppe1]
host1
...

[gruppe2]

Anzeige als Graph (inklusive aller Variablen aus host_vars/group_vars und deren Werten!): ansible-inventory -i hosts --graph

@all:
  |--@gruppe1:
  |  |--@host1:
  |  |  |--{ansible_python_interpreter = /usr/bin/python3}
[...]

dynamic inventories

Variablen

Special Variables

Alle Variablen (facts) anzeigen:

ansible -i hosts -m setup all

Gefiltert auf ansible_distribution*:

ansible -i hosts -m setup all -a "filter=ansible_distribution*"

Variable-Präzedenz

Variablen können vielseitig überschrieben werden. Ein paar Auswahlmöglichkeiten:

Siehe auch die vollständige Reihenfolge.

Variablentypen

Variablen können verschiedene Typen haben, die teilweise intern umgewandelt werden könnten:

Den Typ der Variable kann mit dem Filter type_debug bestimmt werden (hier eine Zahl):

- debug:
    msg: "Datentyp der Variable Variablenname ist {{ Variablenname | type_debug }}"

Ergäbe dann bei einer Zahl eine Ausgabe wie:

Datentyp der Variable Variablenname ist int

Links

mehrzeilige Zeichenketten

Understanding multi line strings in YAML and Ansible (Part I - YAML)

Oft benutzt: der „literal style“ (Format bleibt erhalten):

inhalt_bleibt_exakt_so: |+
  inhalt1
  inhalt2

Rollen

Wiederverwendbare tasks/Aufgaben sollten möglichst in wiederverwendbare Rollen ausgelagert werden.

Suchreihenfolge von Ansible ist standardmäßig:

  1. zuerst in ./roles
  2. dann Benutzerverzeichnis ~/.ansible/roles (das wäre mit einem individuellen Login schlecht weil für andere nicht auffindbar)
  3. dann in /etc/ansible/roles

Falls auf dem ansible-master mit mehreren Benutzer gearbeitet werden soll, kann auch der Systempfad /etc/ansible/roles benutzt werden.

Für verwendete Rollen lässt sich eine requirements.yml anlegen.

sudo ansible-galaxy install --roles-path=/etc/ansible/roles -r external-requirements-ansible-host.yaml

neue Rolle erzeugen

ansible-galaxy init role_name

Use the --remove option to disable and remove a Travis integration: ansible-galaxy setup --remove ID

siehe auch: Galaxy Developer Guide.

Beispielrollen

Siehe Liste: https://github.com/selfhostx/ansible/blob/main/ROADMAP.md

Collections

collections sind ein Verbreitungsformat für playbooks, roles, modules, and plugins. Link: Installing content

ansible-galaxy collection install my_namespace.my_collection

aus einem tar-ball:

ansible-galaxy collection install my_namespace-my_collection-1.0.0.tar.gz -p ./collections

Collections werden in ~/.ansible/collections/ansible_collections abgelegt.

Limitationen:

neue collection erzeugen

im collection Verzeichnis: ansible-galaxy collection init my_namespace.my_collection

siehe Creating collections.

Module

Ansible ist modular aufgebaut

Arten der Kommandoausführung

Stichworte:

ansible-playbook --forks=1
any_errors_fatal: true
max_fail_percentage: 30
serial: 11
einzelne tasks: "run_once: true"

auf einem bestimmten host

- name: "run on that_one_host host"
  ansible.builtin.shell: this_command_should_run_on_one_host
  when: ansible_hostname == 'that_one_host'

Datei-handling

weitere Module siehe Files modules.

Modulname (Link zur Doku) Zweck, geeignet für… nicht geeignet für …
copy Dateien kopieren oder erzeugen (entweder aus anderen Dateien oder aus Variablen (mit Option „content“). Kann eine valide Datei-Syntax durch Aufruf eines Programm validieren um z. B. Syntaxfehler bei sudoers-Dateien oder sonstiger inhaltliche Fehler zu vermeiden (mit der Konsequenz das Dienste sterben) → siehe validate wenn der Inhalt verändert werden soll: template oder assemble nehmen.
fetch
file Dateien und Rechte ändern
synchronize rsync
template Dateien erzeugen (wenn der Inhalt der Datei durch Variablen verändert werden muss)
unarchive / archive Archivhandling (bz2, gz, tar, xz, zip)

Achtung bei Dateirechten in octal-Schreibweise

die Angaben in octal (z.B. 600 für owner rw) müssen komplett als mode: 0644 oder in einfachen Anführungszeichen mode: '600' geschrieben werden. Alles andere bringt sonderbare Rechtemasken hervor

Paketmanager-module

Spezialmodule (Auswahl)

Plugins

templates

templates sind via jinja2 implementiert, siehe Dokumentation.

ansible-lint

pip install ansible-lint

bzw. upgrade:

pip install ansible-lint --upgrade

[301] Commands should not change things if nothing needs doing

      changed_when: false
      check_mode: yes

https://docs.ansible.com/ansible/latest/user_guide/playbooks_checkmode.html

[602] Don't compare to empty string

-    changed_when: output.stdout != ""
+    changed_when: output.stdout | length > 0

[403] Package installs should not use latest Vorgeschlagene Lösung: „Package installs should use state=present with or without a version“**

Je nach Situation: Fehlalarm wenn explizit die letzte, aktuell verfügbare, Version installiert werden soll (aber die Version egal ist).

Code-Konventionen

ansible-lint listet die Fehler auf

Warnungen gezielt ausschalten

Beispie: Warnung „no-changed-when“ ausschalten:

- name: 'Task mit unnützer Warnung durch ansible-lint' # noqa no-changed-when

Code-Beispiele

Henne-Ei-Problem: Python nicht installiert

Ansible hat das Henne-Ei-Problem Python zu benötigen aber um das zu Installieren braucht man bereits Python. Bei Debian/Ubuntu in der Minimalinstallation ist Python z.B. nicht installiert.

Aber auch das lässt sich mit Ansible-Mitteln lösen, dazu muss

Hier ein passendes Playbook:

---
- hosts: all
  gather_facts: False
  # become: yes
  pre_tasks:
  - name: Install python for Ansible
    ansible.builtin.raw: test -e /usr/bin/python || (apt-get -y update && apt install -y python)
    register: output
    changed_when: output.stdout != ""
  tasks:
  - name: Gathering Facts now
    ansible.builtin.setup:

https://gist.github.com/gwillem/4ba393dceb55e5ae276a87300f6b8e6f

Ausgaben und Ausgabe eines Befehls sichern

Achtung: Wiederverwendung der Variable myoutput in anderen taks führt auch bei skip des tasks zur Veränderung des Inhaltes, siehe https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#registering-variables .

---
- hosts: all
  tasks:
    - name: uname anzeigen
      ansible.builtin.command: uname -a
      register: myoutput
 
    - name: show output (alle attributes)
      ansible.builtin.debug:
        msg: "{{ myoutput }}"
 
    - name: show standard output (stdout multiline)
      ansible.builtin.debug:
        msg: "{{ myoutput.stdout_lines }}"
      when: myoutput.stdout_lines is defined and myoutput.stdout_lines != '' and myoutput.stdout_lines != none
 
    - name: show error output (stderr multiline)
      ansible.builtin.debug:
        msg: "{{ myoutput.stderr_lines }}"
      when: myoutput.stderr_lines is defined and myoutput.stderr_lines != '' and myoutput.stderr_lines != none

Prüfen ob Variablen gesetzt sind

Die Verwendung undefinierter Variablen führt zu Fehlern (Abbruch), Benutzern kann in einem extra tasks ein Hinweis gegeben werden.

- name: DNS sanity checks
  ansible.builtin.assert:
    that:
      - variable1 is defined
      - variable1|length>0
    msg: "Variable 1 muss definiert sein und einen Wert enthalten"
  run_once: true

Errorhandling

https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html

include / import

handler verwenden

Bestimmte Aufgaben werden nur bei bestimmten Anlässen gestartet. Das lässt sich einerseits über Bedingungen erledigt (when: Bedingung == true) andererseits können sog. handler von beliebigen Aufgaben aus angesteuert werden um eine Aufgabe wie z.B. einen Service-restart zu erledigen (Anlass: Config geändert).

Dies lässt sich mit „notify“ erledigen (Beispiel vmware-tools installieren + Dienst starten incl. autostart):

- name: "Ensure vmware guest tools are installed"
  ansible.builtin.package: name="open-vm-tools" state=present
  when:
    - ansible_virtualization_role == "guest"
    - ansible_virtualization_type == "VMware"
  notify: Start and enable vmtoolsd

ein entsprechender handler wäre dieser:

handlers/main.yml

---
- name: Start and enable vmtoolsd
  ansible.builtin.service:
    name: vmtoolsd
    state: started
    enabled: yes

:!: Der handler wird nur ausgeführt wenn sich etwas ändert (task: „changed“), d.h. ist das Paket installiert ABER der Dienst nicht gestartet oder aktiviert wird der handler nie aufgerufen.

Conditionals

Robuste Abfragen sollten berücksichtigen dass die Variable run_task1 nicht definiert sein könnte und Typumwandlungen beachten (siehe unten):

- include_tasks: Aufgabe1.yml
  when: run_task1 is defined and run_task1|bool

Hintergrund: Umwandlungen in bool

Durch das Zuammenspiel von YAML, Jinja2 und Python ergeben sich mögliche Probleme bei der Verwendung von True, true, False, false und yes, no:

https://chronicler.tech/red-hat-ansible-yes-no-and/

https://github.com/ansible/ansible/issues/11905. Lösung:

a: !!str yes
b: 'yes'

Beispiel und Erklärung: php_display_errors: !!str On (speichert „On“ explizit als string damit php_display_errors: On' erhalten bleibt).

Ein weiteres Beispiel ist javascript: Hier muss in templates explizit „true“ herauskommen (nicht True). Hier kann mit dem Filter $Variable|lower gearbeitet werden (Unwandlung in einen „lowercase string“).

Zusätzlich muss die Auswertung von bool-Variablen in Zukunft (ab Version 2.12) explizit angegeben werden:

[DEPRECATION WARNING]: evaluating ntp_enabled as a bare variable, this behaviour will go away and you might need to add |bool to the expression in the future. Also see 
CONDITIONAL_BARE_VARS configuration toggle.. This feature will be removed in version 2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.

Beispiel:

- name: Ensure NTP is running and enabled as configured.
  ansible.builtin.service:
    name: "{{ ntp_daemon }}"
    state: started
    enabled: yes
  when: ntp_enabled -> when: ntp_enabled|bool

fact dynamisch setzen

Die Bedingung (when: …) ist optional.

- name: Set my_variable to true if undefined
  ansible.builtin.set_fact:
    my_variable: true
  when: my_variable is undefined

gruppe dynamisch setzen

- name: Set machine_is_virtual when virtualization_role is guest
  ansible.builtin.group_by:
    key: machine_is_virtual
  changed_when: false
  when: ansible_facts['virtualization_role'] == "guest"

oder (etwas eleganter mit entweder Gruppe machine_is_virtual oder machine_is_metal in einer Zeile.

- name: Classify hosts (virtual or bare metal)
  ansible.builtin.group_by:
    key: machine_is_{{ "virtual" if ansible_facts['virtualization_role'] == "guest" else "metal" }}
  changed_when: false

Blöcke in config-files managen: blockinfile

statt lineinfile: blockinfile module – Insert/update/remove a text block surrounded by marker lines, Beispiel: https://stackoverflow.com/questions/22844905/how-to-create-a-directory-using-ansible

Passwörter erzeugen

Dynamische passwort-Lookups würden jedes mal ein neues Passwort erzeugen, oft will man pro Host ein Passwort erzeugen und dies in einer Variable speichern.

Statt „/dev/null“ kann das Passwort auch (auf dem wo es läuft) in eine Datei geschrieben werden.

- name: Demo
  hosts: all
  gather_facts: False
  tasks:
    - set_fact:
        host_individual_password: "{{ lookup('password', '/dev/null length=16 chars=ascii_letters') }}"
      no_log: True
    - debug:
        msg: "{{ host_individual_password }}"

Es kann aber auch ein Passwort aus dem environment des masters geholt werden (das gilt dann aber für alle Hosts gleichermaßen!):

- name: Demo2
  hosts: all
  gather_facts: False
  vars:
    password_from_master: "{{ lookup('env', 'password_from_master') }}"
  tasks:
    - set_fact:
        password_from_master: "{{ lookup('env', 'env_password') }}"
      no_log: True
    - debug:
        msg: "{{ password_from_master }}"
1)
die tags sind in dem fact ansible_run_tags
2)
verfügbare Versionen mit diesem „Trick“ anzeigen: pip3 install ansible==
4)
vim kann auto-Erkennung der Dateitypen siehe https://github.com/chase/vim-ansible-yaml
5)
es wird der Standard-Editor aus der Umgebungsvariablen $EDITOR benutzt
6)
standardmäßig über receptor Port 27199