gather_facts Ansible Tutorial Teil 7

Ich hatte schon erwähnt, dass ich gather_facts meistens abschalte, um Playbooks zu beschleunigen. Für diesen Tutorialteil schalte ich es ein, um zu zeigen, was es macht.

Ansible Logo (Quelle: Von Ansible/Red Hat - Wikipedia) gather_facts
Ansible Logo (Quelle: Von Ansible/Red Hat – Wikipedia)
1Einführung
2Das Inventory
3Über Rollen und Tasks
4Die Module
5Playbooks
6Konfiguration
7gather_facts
8eigene Module

gather_facts

Mit Hilfe der Variable gather_facts an einem Task sammelt Ansible so viel Informationen über den Managed Node wie möglich. Auf diese kann ein Task dann reagieren. Beispielsweise kann ein Task abhängig vom eingesetzten Betriebssystem auf dem Managed Node gestartet werden.

Task

Zunächst bauen wir uns einen Task roles/gather_facts/task/main.yml, um die Facts des Managed Hosts zu sammeln und auszugeben. Für die Ausgabe benutzen wir das eingebaute Debug Modul ansible.builtin.debug

- name: Informationen sammeln
  ansible.builtin.debug:
    var: ansible_facts

Der Task ist sehr übersichtlich, er sammelt lediglich alle Informationen und gibt das Dictionary in der Shell aus. Das Dictionary ist ziemlich umfangreich, so dass ich nicht komplett hier aufliste. Im Repository habe ich die Files facts_brandine und facts_quimby abgelegt.

Playbook

Das Playbook gather_facts.yml hat nur die Aufgabe, den oben stehenden Task abzuarbeiten.

- hosts: "{{ target }}"
  gather_facts: true
  remote_user: pi
  roles:
    - gather-facts

nützliche Informationen

In dem Dictionary gibt viele interessante Informationen , aber auch einige, deren Sinn mir nicht ganz erschließen.

lsb

lsb ist die Linux Standard Base, die verschiedene standardisierte Informationen zu einem Linux System fest schreibt. In dem Sub-Dictionary finde ich folgende Keys:

"lsb": {
            "codename": "bookworm",
            "description": "Raspbian GNU/Linux 12 (bookworm)",
            "id": "Raspbian",
            "major_release": "12",
            "release": "12"
        },
  • codename ist der informelle Name des Betriebssystems hier bookworm für ein Debian 12 System
  • description enthält genauere Informationen zur Distribution. es ist ein Raspberry Pi OS (raspian), dass ich auf Debian 12 geupgraded habe.
  • id ist einfach nur der Name der Distribution
  • major_release enthält die Versionsnummer der Distribution (hier 12 für bookworm)
  • release ist hier mit major_release identisch.

Diese Schlüssel kannst du in einem Play abfragen und so gezielt reagieren. Wie das geht, zeige ich die später. Bei meinem DietPi Raspi ist das lsb Dictionary übrigens leer, da DietPi die Linux Standard Base nicht unterstützt.

iP-Adressen

Interessant finde ich diese Informationen:

"all_ipv4_addresses": [
            "172.17.0.1",
            "169.254.175.171",
            "169.254.6.113",
            "192.168.178.30",
            "169.254.119.46",
            "169.254.182.8",
            "10.42.0.0",
            "169.254.34.128",
            "169.254.73.186",
            "10.42.0.1"
        ],

Hier sind alle IP-Adressen aufgelistet, die der Raspi aktuell benutzt. Normalerweise würde hier nur eine IP stehen, da aber Docker virtuelle Netzwerke aufbaut, haben diese auch eigene Schnittstellen mit eigenen IP-Adressen.Die Namen der Netzwerk-Schnitstellen können wir auch abfragen:

"interfaces": [
            "vethb296f487",
            "veth2f4e591d",
            "eth0",
            "lo",
            "veth752b092e",
            "flannel.1",
            "vethe0bacd3f",
            "veth2d169caf",
            "docker0",
            "wlan0",
            "cni0"
        ],

env

Ansible macht genau so das gleiche wie du, wenn du dich mit ssh einloggst und folglich wird dann auch eine Shell mit all ihren Umgebungsvariablen gestartet. Diese sind Sub-Dictionary env vermerkt. Ich habe das ein wenig gekürzt, um es übersichtlich zu halten. Die meisten Variablen wirst du vermutlich eh schon kennen.

       "env": {
            "HOME": "/home/pi",
            "LANG": "C",
            "LC_ALL": "C",
            "LC_NUMERIC": "C",
            "LOGNAME": "pi",
            "MOTD_SHOWN": "pam",
            "PATH": "/usr/local/bin:/usr/bin:/bin:/usr/games",
            "PWD": "/home/pi",
            "SHELL": "/bin/bash",
            "SSH_CLIENT": "192.168.178.104 33962 22",
            "SSH_CONNECTION": "192.168.178.104 33962 192.168.178.30 22",
            "SSH_TTY": "/dev/pts/0",
  • PWD – das aktuelle Arbeitsverzeichnis, nach dem Login immer das Homeverzeichnis des Users.
  • SSH_CLIENT – IP von der aus sich eingeloggt wurde 192.168.178.104, den Port zum Control Node 33962 und ssh-Port auf dem Managed Node 22.
  • SHELL – Der Pfad der aufgerufenen Shell
  • LOGNAME – Username

globale Informationen

Viele Daten sind dem Hauptdictionary zugeordnet. Eine Auswahl davon kopiere ich hier mal zusammen.

"hostname": "brandine",
"kernel": "5.10.103-v8+",
"kernel_version": "#1529 SMP PREEMPT Tue Mar 8 12:26:46 GMT 2022",
"memtotal_mb": 7862,
"uptime_seconds": 1653888,
 "architecture": "aarch64",
  "bios_date": "",
   "bios_vendor": "",
   "bios_version": "",
  • hostname – Der Hostname des Nodes
  • architecure – Die Architektur des Managed Hosts aarch64 ist ein 64bit ARM System
  • kernel – Die Versionsnummer des gestarteten Kernels
  • kernel_version – Die Build-Informationen des Kernels. Wie uname -a
  • memtoal_mb – Der insgesamt verfügbare Hauptspeicher des Raspis. Hier 8GB
  • uptime_seconds – Die Zeit, die der Node läuft in Sekunden
  • bios_* – Informationen zum BIOS des Rechners , hier leer, da der Raspi kein BIOS besitzt.

Einige der gesammelten Fakten sind meiner Meinung nach sicherheitsrelevant. Mit Informationen über BIOS und Kernelversion kann ein Angreifer Schwachstellen gezielt ausnutzen.

Auf Variablen reagieren.

Die Informationen werden nicht zum Selbstzweck für das Ansiblesystem gesammelt, du kannst sie abfragen und damit konditionale Tasks schreiben.

Du erinnerst dich an die Zeile

var: ansible_facts

Damit werden weist gather_facts das Dictionary der Variable gather_facts zu. Schauen wir mal, was mir damit anfangen können.

Ich erweitere die gather_facts Rolle um einen zusätzlichen Task, der mir nur auf brandine und kirk eine leere Datei namens testwhen im Homeverzeichnis anlegen soll:

- name: leeres File anlegen
  file: 
    path: /home/pi/testwhen
    state: touch
  when: (ansible_facts['hostname'] == 'brandine' or ansible_facts['hostname'] == 'kirk')

Mit dem Schlüsselwort when bekommt der Task eine Bedingung, so dass er nur ausgelöst wird, wenn der darin enthaltene Ausdruck wahr ist. Mit ansible_facts['hostname'] greifen wir im Dictionary auf den Wert von hostname zu und vergleichen == mit 'brandine' oder or 'kirk'. Nur, wenn hostname einen der beiden Werte hat, wird der Task überhaupt ausgeführt ansonsten ignoriert. Wichtig ist, dass der zweite Task unter dem gather_facts in der main.yml steht, da das Dictionary natürlich erst gefüllt werden muss, bevor du es benutzen kannst.

Der Lauf des Playbooks liefert jetzt folgende Zusammenfassung:

Zusammenfassung des Laufs, nur brandine und kirk sind changed, quimby und willie wurden übersprungen.
Olli Graf -raspithek.de
whenCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Zusammenfassung des Laufs, nur brandine und kirk sind changed, quimby und willie wurden übersprungen.

Mit den Informationen, die dir gather_facts liefert, bist du in der Lage, Tasks zu schreiben, die z.B. bei verschiedenen Betriebssystemen unterschiedlich reagieren.

Im nächsten Teil wollen wir ein eigenes Modul für Ansible schreiben.

Schreibe einen Kommentar

Creative Commons License
Except where otherwise noted, the content on this site is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
Olli Graf - raspithek.de
WordPress Cookie Hinweis von Real Cookie Banner