32 Playbook Testing und Validierung

32.1 Überblick: Unterschied zwischen Linting, Validierung und Testing

Bevor wir in die Details der einzelnen Tools eintauchen, ist es wichtig, die verschiedenen Arten der Qualitätssicherung zu verstehen:

Kategorie Tool Ziel Zeitpunkt
Linting yamllint YAML-Format prüfen Vor Ausführung
Linting ansible-lint Ansible-Best-Practices Vor Ausführung
Validierung --syntax-check Syntax überprüfen Vor Ausführung
Validierung --check Trockenlauf ohne Änderungen Vor Ausführung
Testing molecule Rollentests mit Umgebung In Testumgebung
Assertion-Tests testinfra Prüfung Zielzustand (Python) Nach Ausführung

32.2 Methoden zur Validierung von Playbooks

32.2.1 Ansible-eigene Validierungsmethoden

32.2.1.1 Syntax-Check

Ansible bietet eingebaute Validierungsmethoden, um die grundlegende Syntax zu überprüfen:

ansible-playbook --syntax-check playbook.yml

32.2.1.2 Check-Modus (Trockenlauf)

Der Check-Modus führt das Playbook aus, ohne tatsächliche Änderungen vorzunehmen:

ansible-playbook --check playbook.yml

Dieser “Trockenlauf” ist besonders nützlich, um vorab zu prüfen, welche Änderungen ein Playbook vornehmen würde, ohne das System tatsächlich zu modifizieren.

32.2.2 ansible-lint

ansible-lint ist ein Werkzeug zur statischen Analyse von Ansible-Playbooks, das überprüft, ob die Playbooks den empfohlenen Best Practices folgen. Es kann häufige Fehler und potenzielle Probleme identifizieren, bevor das Playbook in einer Produktionsumgebung ausgeführt wird.

Installation:

pip install ansible-lint

Beispiel für die Verwendung:

ansible-lint playbook.yml

ansible-lint überprüft das Playbook und gibt Warnungen oder Fehler aus, wenn gegen Ansible-Best-Practices verstoßen wird.

Konfiguration von ansible-lint: Erstellen Sie eine .ansible-lint-Datei im Projektverzeichnis:

exclude_paths:
  - .cache/
  - .github/
  - molecule/
skip_list:
  - yaml[line-length]
  - name[casing]

32.2.3 yamllint

Da Ansible-Playbooks in YAML geschrieben sind, ist die Überprüfung der YAML-Syntax ein wichtiger Schritt, um sicherzustellen, dass die Playbooks korrekt geparst werden können. yamllint ist ein Werkzeug, das die YAML-Syntax überprüft und sicherstellt, dass sie den YAML-Spezifikationen entspricht.

Installation:

pip install yamllint

Beispiel für die Verwendung:

yamllint playbook.yml

yamllint überprüft das Playbook auf Syntaxfehler, inkonsistente Einrückungen und andere potenzielle Probleme in der YAML-Struktur.

Konfiguration von yamllint: Erstellen Sie eine .yamllint.yml-Datei:

extends: default
rules:
  line-length:
    max: 120
  indentation:
    spaces: 2

32.3 Testing-Frameworks und Ansätze

32.3.1 Molecule

Molecule ist ein beliebtes Framework für die Entwicklung und das Testen von Ansible-Rollen und -Playbooks. Es bietet eine einfache Möglichkeit, Testumgebungen zu erstellen, Playbooks auszuführen und die Ergebnisse zu überprüfen.

Installation:

pip install molecule

Grundlegende Verwendung:

molecule init role my_role
molecule test

32.3.1.1 Molecule-Treiber

Molecule unterstützt verschiedene Treiber für unterschiedliche Testumgebungen:

Beispiel einer molecule.yml mit Docker-Treiber:

---
dependency:
  name: galaxy
driver:
  name: docker
platforms:
  - name: instance
    image: ubuntu:20.04
    pre_build_image: true
    privileged: true
    volumes:
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    command: /lib/systemd/systemd
provisioner:
  name: ansible
  inventory:
    host_vars:
      instance:
        ansible_python_interpreter: /usr/bin/python3
verifier:
  name: ansible

32.3.1.2 Molecule-Workflow

Molecule durchläuft mehrere Phasen:

  1. dependency: Installation von Abhängigkeiten
  2. create: Erstellen der Testumgebung
  3. prepare: Vorbereitung der Instanzen
  4. converge: Ausführung des Playbooks
  5. verify: Ausführung der Tests
  6. destroy: Zerstörung der Testumgebung

32.3.2 Testinfra

Testinfra ist ein Werkzeug zur Überprüfung der Zustände von Servern nach der Ausführung von Ansible-Playbooks. Es integriert sich gut mit Molecule und ermöglicht das Schreiben von Tests in Python, um sicherzustellen, dass das Playbook das gewünschte Ergebnis erzielt.

Installation:

pip install testinfra

Beispiel für die Verwendung mit Molecule:

# molecule/default/tests/test_default.py
import os
import testinfra.utils.ansible_runner

testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
    os.environ['MOLECULE_INVENTORY_FILE']
).get_hosts('all')

def test_apache_installed(host):
    apache = host.package("apache2")
    assert apache.is_installed

def test_apache_running_and_enabled(host):
    apache = host.service("apache2")
    assert apache.is_running
    assert apache.is_enabled

def test_apache_config_file(host):
    config = host.file("/etc/apache2/apache2.conf")
    assert config.exists
    assert config.is_file

def test_web_server_responds(host):
    cmd = host.run("curl -f http://localhost")
    assert cmd.succeeded

32.4 Integration in CI/CD-Pipelines

Die Integration von Ansible-Playbook-Tests in CI/CD-Pipelines ist eine Best Practice, um sicherzustellen, dass Änderungen an Playbooks automatisch überprüft und validiert werden.

32.4.1 GitLab CI

Beispiel für eine GitLab CI-Konfiguration:

stages:
  - lint
  - test

variables:
  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"

cache:
  paths:
    - .cache/pip/
    - venv/

before_script:
  - python -m venv venv
  - source venv/bin/activate
  - pip install --upgrade pip
  - pip install ansible ansible-lint yamllint molecule molecule-plugins[docker] testinfra

lint_playbooks:
  stage: lint
  script:
    - source venv/bin/activate
    - yamllint .
    - ansible-lint .

test_playbooks:
  stage: test
  services:
    - docker:dind
  variables:
    DOCKER_HOST: tcp://docker:2376
    DOCKER_TLS_CERTDIR: "/certs"
  script:
    - source venv/bin/activate
    - molecule test

32.4.2 GitHub Actions

Beispiel für GitHub Actions:

name: Ansible CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.9'
        
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install ansible ansible-lint yamllint
        
    - name: Run yamllint
      run: yamllint .
      
    - name: Run ansible-lint
      run: ansible-lint .

  test:
    runs-on: ubuntu-latest
    needs: lint
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.9'
        
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install molecule molecule-plugins[docker] testinfra
        
    - name: Run Molecule tests
      run: molecule test

32.4.3 Jenkins

Beispiel für Jenkins Pipeline:

pipeline {
    agent any
    
    stages {
        stage('Setup') {
            steps {
                sh 'python -m venv venv'
                sh '. venv/bin/activate && pip install ansible ansible-lint yamllint molecule molecule-plugins[docker] testinfra'
            }
        }
        
        stage('Lint') {
            parallel {
                stage('YAML Lint') {
                    steps {
                        sh '. venv/bin/activate && yamllint .'
                    }
                }
                stage('Ansible Lint') {
                    steps {
                        sh '. venv/bin/activate && ansible-lint .'
                    }
                }
            }
        }
        
        stage('Test') {
            steps {
                sh '. venv/bin/activate && molecule test'
            }
        }
    }
    
    post {
        always {
            cleanWs()
        }
    }
}

32.5 Tipps und Tricks für zuverlässige und robuste Playbooks

32.5.1 Verwendung von Rollen für Modularität

Stellen Sie sicher, dass Ihre Playbooks in wiederverwendbare Rollen unterteilt sind. Dies fördert die Modularität und macht es einfacher, einzelne Komponenten zu testen und zu warten.

32.5.2 Testen in einer isolierten Umgebung

Verwenden Sie Testumgebungen, die isoliert von Ihrer Produktionsumgebung sind, um sicherzustellen, dass Playbooks korrekt funktionieren, bevor sie in der Produktion eingesetzt werden. Tools wie Vagrant, Docker oder Cloud-basierte Testumgebungen können hier hilfreich sein.

32.5.3 Pre-Commit-Hooks

Nutzen Sie Pre-Commit-Hooks, um automatische Überprüfungen vor jedem Commit durchzuführen:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      
  - repo: https://github.com/adrienverge/yamllint.git
    rev: v1.28.0
    hooks:
      - id: yamllint
      
  - repo: https://github.com/ansible/ansible-lint.git
    rev: v6.10.0
    hooks:
      - id: ansible-lint

32.5.4 Versionierung und Dokumentation

Verwenden Sie Versionskontrollsysteme wie Git, um Ihre Playbooks zu verwalten und sicherzustellen, dass Änderungen nachverfolgt und dokumentiert werden. Kommentieren Sie Ihre Playbooks gut, um deren Zweck und Funktionsweise klar zu kommunizieren.

32.5.5 Fokussiertes Debugging

Wenn ein Playbook fehlschlägt, verwenden Sie verschiedene Debug-Parameter:

# Erhöhte Verbosity
ansible-playbook -vvv playbook.yml

# Kombiniert mit Check-Modus
ansible-playbook --check -vv playbook.yml

# Nur bestimmte Tags ausführen
ansible-playbook --tags "configuration" playbook.yml

# Ab einem bestimmten Task starten
ansible-playbook --start-at-task "Install packages" playbook.yml

32.5.6 Regelmäßige Überprüfung und Aktualisierung

Überprüfen Sie regelmäßig Ihre Playbooks und Rollen, um sicherzustellen, dass sie den aktuellen Best Practices entsprechen und auf den neuesten Stand gebracht wurden. Technologien und Anforderungen ändern sich, und Ihre Playbooks sollten sich anpassen können.

32.5.7 Performance-Monitoring

Nutzen Sie Callback-Plugins, um die Performance Ihrer Playbooks zu überwachen:

# Profiling aktivieren
export ANSIBLE_CALLBACKS_ENABLED=profile_tasks
ansible-playbook playbook.yml

32.6 Best Practices für Test-Strategien

32.6.1 Pyramide der Tests

Implementieren Sie eine ausgewogene Test-Pyramide:

  1. Unit-Tests: Testen einzelner Tasks oder Rollen (via Molecule)
  2. Integrationstests: Testen des Zusammenspiels mehrerer Komponenten
  3. End-to-End-Tests: Vollständige Anwendungsszenarien

32.6.2 Continuous Testing

32.6.3 Dokumentation der Tests

Dokumentieren Sie Ihre Test-Szenarien und erwarteten Ergebnisse:

# tests/README.md
## Test-Szenarien

1. **Grundinstallation**: Prüft die initiale Installation aller Komponenten
2. **Konfigurationsupdates**: Testet Änderungen an Konfigurationsdateien
3. **Service-Restart**: Überprüft das korrekte Neustarten von Services
4. **Idempotenz**: Stellt sicher, dass mehrfache Ausführung keine Änderungen bewirkt