first
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# Ansible-Beispiel: Rolle, Variablen & Templating (localhost)
|
||||
|
||||
Ein vollständiges Beispiel-Projekt, das alle Konzepte aus der Präsentation
|
||||
demonstriert:
|
||||
|
||||
- **Rollen-Struktur** (`roles/webserver/`)
|
||||
- **Variablen-Vergabe** mit Präzedenz (defaults → vars → group_vars → host_vars)
|
||||
- **Templating** mit Jinja2 (`.j2`-Dateien, Schleifen, Filter)
|
||||
- **FQCN** (`ansible.builtin.*`)
|
||||
- **Facts** (`ansible_distribution`, `ansible_hostname`, …)
|
||||
- **Handler** (`notify` → Dienst neu starten)
|
||||
|
||||
---
|
||||
|
||||
## Verzeichnisstruktur
|
||||
|
||||
```
|
||||
Beispiel/
|
||||
├── ansible.cfg # Ansible-Konfiguration
|
||||
├── inventory.yml # Ziel-Hosts (localhost)
|
||||
├── site.yml # Haupt-Playbook
|
||||
├── group_vars/
|
||||
│ └── all.yml # Variablen für ALLE Hosts
|
||||
├── host_vars/
|
||||
│ └── localhost.yml # Host-spezifische Variablen
|
||||
└── roles/
|
||||
└── webserver/
|
||||
├── tasks/main.yml # Aufgaben
|
||||
├── handlers/main.yml # Neustart-Aktionen (notify)
|
||||
├── templates/
|
||||
│ ├── nginx.conf.j2 # Jinja2-Template
|
||||
│ └── index.html.j2 # Template mit Schleife + Filter
|
||||
├── defaults/main.yml # Standard-Variablen (niedrigste Priorität)
|
||||
├── vars/main.yml # Rollen-Variablen (höhere Priorität)
|
||||
└── meta/main.yml # Rollen-Metadaten
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ausführen
|
||||
|
||||
```bash
|
||||
# Trockenlauf — zeigt nur, was passieren würde
|
||||
ansible-playbook site.yml --check
|
||||
|
||||
# Echt ausführen (benötigt sudo wegen Paket-Installation)
|
||||
ansible-playbook site.yml
|
||||
|
||||
# Variable per CLI überschreiben (HÖCHSTE Priorität!)
|
||||
ansible-playbook site.yml -e "nginx_port=9090"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Variablen-Präzedenz im Beispiel
|
||||
|
||||
Dieselbe Variable (`nginx_port`) ist an mehreren Stellen definiert — wer gewinnt?
|
||||
|
||||
| Priorität | Ort | Wert |
|
||||
|-----------|------------------------------|-----------------|
|
||||
| 1 (höchste) | Extra-Variablen `-e` | `9090` (wenn gesetzt) |
|
||||
| 2 | `host_vars/localhost.yml` | `8080` |
|
||||
| 3 | `group_vars/all.yml` | — |
|
||||
| 4 | `roles/.../vars/main.yml` | `nginx_user` |
|
||||
| 5 (niedrigste) | `roles/.../defaults/main.yml` | `80` (Default) |
|
||||
|
||||
→ Ergebnis: `nginx_port` wird **8080**, weil `host_vars` Vorrang vor `defaults`
|
||||
hat (die Default `80` wird überschrieben).
|
||||
|
||||
---
|
||||
|
||||
## Für Manjaro / Arch Linux anpassen
|
||||
|
||||
Das Beispiel nutzt `apt` (Debian/Ubuntu). Auf Manjaro ersetzt Du in
|
||||
`roles/webserver/tasks/main.yml` das Modul:
|
||||
|
||||
```yaml
|
||||
- name: Pakete installieren
|
||||
community.general.pacman:
|
||||
name: "{{ packages }}"
|
||||
state: present
|
||||
update_cache: true
|
||||
```
|
||||
|
||||
und passt die Paketnamen (`nginx`, `git`, `curl` bleiben gleich) sowie
|
||||
`nginx_user` ggf. an.
|
||||
@@ -0,0 +1,12 @@
|
||||
[defaults]
|
||||
# Inventory-Datei (relativ zum Projektordner)
|
||||
inventory = inventory.yml
|
||||
|
||||
# Kein SSH-Host-Key-Check (praktisch für lokale Tests)
|
||||
host_key_checking = False
|
||||
|
||||
# Python-Interpreter automatisch erkennen
|
||||
interpreter_python = auto_silent
|
||||
|
||||
# Retry-Dateien nicht anlegen
|
||||
retry_files_enabled = False
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
# group_vars/all.yml
|
||||
# Variablen für ALLE Hosts in der Gruppe "all" (mittlere Priorität).
|
||||
|
||||
app_name: "Meine Ansible-Demo"
|
||||
admin_email: admin@example.com
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
# host_vars/localhost.yml
|
||||
# Host-spezifische Variablen — überschreiben group_vars und Rollen-Defaults.
|
||||
|
||||
nginx_port: 8080 # überschreibt die Default 80 aus defaults/main.yml
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
# Inventory — definiert die Ziel-Hosts
|
||||
# Format: YAML (alternativ auch INI möglich)
|
||||
|
||||
all:
|
||||
hosts:
|
||||
localhost:
|
||||
ansible_connection: local # läuft direkt auf diesem Rechner (kein SSH)
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
# roles/webserver/defaults/main.yml
|
||||
# Standard-Variablen — NIEDRIGSTE Priorität, leicht überschreibbar.
|
||||
|
||||
nginx_port: 80
|
||||
domain: example.com
|
||||
web_root: /var/www/html
|
||||
|
||||
packages:
|
||||
- nginx
|
||||
- git
|
||||
- curl
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
# roles/webserver/handlers/main.yml
|
||||
# Handler — laufen NUR, wenn eine Task sie per "notify" auslöst.
|
||||
# (Bsp.: erst nach einer Änderung an der Konfiguration neu starten.)
|
||||
|
||||
- name: nginx neu starten
|
||||
ansible.builtin.service:
|
||||
name: nginx
|
||||
state: restarted
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
# roles/webserver/meta/main.yml
|
||||
# Rollen-Metadaten: Name, Beschreibung, Lizenz, Abhängigkeiten.
|
||||
|
||||
galaxy_info:
|
||||
role_name: webserver
|
||||
author: Dein Name
|
||||
description: "Beispiel-Rolle: installiert & konfiguriert nginx (mit Templating)"
|
||||
license: MIT
|
||||
min_ansible_version: "2.10"
|
||||
|
||||
# Abhängigkeiten zu anderen Rollen (hier: keine)
|
||||
dependencies: []
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
# roles/webserver/tasks/main.yml
|
||||
# Die Aufgaben der Rolle. Jede Task ruft genau ein Modul auf (per FQCN).
|
||||
|
||||
- name: Betriebssystem ausgeben (Facts nutzen)
|
||||
ansible.builtin.debug:
|
||||
msg: "Läuft auf {{ ansible_distribution }} {{ ansible_distribution_version }}"
|
||||
|
||||
- name: Pakete installieren
|
||||
ansible.builtin.apt:
|
||||
name: "{{ packages }}"
|
||||
state: present
|
||||
update_cache: true
|
||||
notify: nginx neu starten
|
||||
|
||||
- name: Webverzeichnis anlegen
|
||||
ansible.builtin.file:
|
||||
path: "{{ web_root }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Konfiguration aus Template rendern
|
||||
ansible.builtin.template:
|
||||
src: nginx.conf.j2
|
||||
dest: /etc/nginx/nginx.conf
|
||||
mode: '0644'
|
||||
notify: nginx neu starten
|
||||
|
||||
- name: Startseite aus Template rendern (mit Schleife & Filter)
|
||||
ansible.builtin.template:
|
||||
src: index.html.j2
|
||||
dest: "{{ web_root }}/index.html"
|
||||
mode: '0644'
|
||||
|
||||
- name: Dienst aktivieren und starten
|
||||
ansible.builtin.service:
|
||||
name: nginx
|
||||
state: started
|
||||
enabled: true
|
||||
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ app_name }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{{ app_name }}</h1>
|
||||
<p>Betriebssystem: {{ ansible_distribution }} {{ ansible_distribution_version }}</p>
|
||||
|
||||
<p>Installierte Pakete:</p>
|
||||
<ul>
|
||||
{% for pkg in packages %}
|
||||
<li>{{ pkg | upper }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<p>Port: {{ nginx_port }}</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,21 @@
|
||||
# {{ ansible_managed }} <- von Ansible erzeugt, nicht manuell ändern!
|
||||
|
||||
user {{ nginx_user }};
|
||||
worker_processes auto;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen {{ nginx_port }};
|
||||
server_name {{ domain }};
|
||||
|
||||
root {{ web_root }};
|
||||
index index.html;
|
||||
|
||||
# Fact des Zielsystems wird hier aufgelöst:
|
||||
access_log /var/log/nginx/{{ ansible_hostname }}.access.log;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
# roles/webserver/vars/main.yml
|
||||
# Rollen-Variablen — HÖHERE Priorität als defaults, nicht leicht überschreibbar.
|
||||
# Eignet sich für Werte, die fest zur Rolle gehören.
|
||||
|
||||
nginx_user: www-data
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
# site.yml — Haupt-Playbook
|
||||
# Ruft die Rolle "webserver" für localhost auf.
|
||||
|
||||
- name: Webserver auf localhost konfigurieren
|
||||
hosts: localhost
|
||||
gather_facts: true # Facts sammeln (OS, IP, Hostname, …)
|
||||
become: true # mit sudo ausführen (für Paket-Installation)
|
||||
|
||||
roles:
|
||||
- role: webserver
|
||||
vars: # Playbook-Variablen (überschreibt Defaults)
|
||||
domain: localhost
|
||||
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg height="315" preserveAspectRatio="xMidYMid" viewBox="0 0 256 315" width="256" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#1a1918" transform="translate(0 281.86)">
|
||||
<path d="m67.5168 32.0035c-.54152 0-1.12617-.13685-1.53212-.68583l-17.3835-22.8612v23.3187h-3.96431v-28.7142c0-1.14253.94592-2.0571 2.0278-2.0571.62971 0 1.17084.1826 1.57485.73158l17.3396 22.8159v-23.2276h3.96392v28.6681c0 1.18907-.94592 2.01175-2.02625 2.01175"/>
|
||||
<path d="m100.306 32.278c-3.96276 0-8.10693-.82347-11.9803-2.28584l.94631-3.2927c3.55797 1.14332 7.43099 1.96639 11.034 1.96639 4.99958 0 7.61163-1.7834 7.61163-4.29759 0-2.28663-2.02741-3.42956-9.00817-6.72187-6.98076-3.29192-9.72722-5.39477-9.72722-9.51055 0-5.16563 3.96276-7.27006 11.4384-7.27006 3.10813 0 7.88162.64087 10.63 1.46395l-.63087 3.38302c-3.01839-.73119-6.80051-1.23402-9.90864-1.23402-5.26839 0-7.4306 1.00528-7.4306 3.52066 0 2.46844 1.57562 3.52026 8.96194 6.94982 7.79188 3.61216 9.77345 5.4413 9.77345 9.18992 0 5.4417-5.13515 8.13888-11.71 8.13888"/>
|
||||
<path d="m130.798 1.32367h4.09833v30.4511h-4.09833z"/>
|
||||
<path d="m169.758 17.9669h-10.1798v10.334h10.1798c3.46746 0 5.58422-2.19514 5.58422-5.2591 0-2.88057-2.2065-5.07492-5.58422-5.07492m-1.98274-13.1685h-8.19705v9.73929h8.19705c3.28838 0 5.67512-2.10364 5.67512-5.02957 0-2.88057-2.07208-4.70972-5.67512-4.70972m2.02741 26.9766h-12.2499c-1.17162 0-2.07247-.91497-2.07247-2.0575v-26.3361c0-1.09796.90086-2.0575 2.07247-2.0575h10.1332c6.21509 0 9.90786 3.06317 9.90786 7.86439 0 2.60569-1.53134 5.02917-3.8738 6.44659 3.4694 1.05182 5.80992 3.932 5.80992 7.40691 0 4.84657-4.00743 8.73322-9.72722 8.73322"/>
|
||||
<path d="m199.212 31.7751c-1.12422 0-2.02547-.96032-2.02547-2.0575v-28.3936h4.09755v26.7479h16.304v3.70326h-18.3761z"/>
|
||||
<path d="m245.526 32.278c-8.3773 0-13.4215-3.10892-13.4215-9.37291 0-2.97207 1.66691-5.8069 4.90984-7.13281-2.61244-1.64616-3.96314-3.97814-3.96314-6.53848 0-5.66926 4.36987-8.36802 12.5658-8.36802 2.74763 0 6.62026.32063 9.86358 1.05261l-.45101 3.38302c-3.42201-.54898-6.62104-.86804-9.72839-.86804-5.31462 0-8.15238 1.46237-8.15238 4.98343 0 2.78947 2.61283 4.98382 6.08146 4.98382h7.02504c.99098 0 1.75626.77733 1.75626 1.73726 0 1.00568-.76528 1.78301-1.75626 1.78301h-7.56501c-3.9647 0-6.48546 1.96561-6.48546 4.98421 0 4.43484 4.09833 5.76075 9.23232 5.76075 2.79269 0 6.57442-.3648 9.63671-1.09678l.58697 3.33727c-2.92827.82347-6.757 1.37166-10.1347 1.37166"/>
|
||||
<path d="m14.138 7.0347 7.17771 17.9843-10.8406-8.66933 3.66286-9.31493zm12.7514 22.1277-11.0399-26.9746c-.31505-.77733-.94592-1.18907-1.71159-1.18907s-1.44121.41174-1.75626 1.18907l-12.1179 29.5874h4.14456l4.79757-12.1983 14.3142 11.7408c.57571.47208.99098.68583 1.53212.68583 1.08033 0 2.02625-.82268 2.02625-2.01135 0-.19285-.06798-.49968-.18918-.82978z"/>
|
||||
</g>
|
||||
<path d="m255.879 127.868c0 70.4551-57.1101 127.565-127.566 127.565-70.4501 0-127.566-57.1096-127.566-127.565 0-70.4501 57.1161-127.566 127.566-127.566 70.4561 0 127.566 57.1161 127.566 127.566" fill="#1a1918"/>
|
||||
<path d="m130.46 78.2289 33.0116 81.4763-49.8635-39.2778 16.8519-42.1984zm58.6445 100.245-50.7786-122.202c-1.44952-3.52436-4.34807-5.38926-7.86591-5.38926-3.52436 0-6.63386 1.86489-8.08339 5.38926l-55.7329 134.04h19.0653l22.0623-55.2653 65.8389 53.1899c2.64792 2.14114 4.55852 3.1095 7.0422 3.1095 4.97389 0 9.32146-3.72878 9.32146-9.11101 0-.87594-.30939-2.2662-.86941-3.76143z" fill="#fff"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
@@ -0,0 +1,969 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Moderne Ansible-Präsentation — vollständiger Generator (v3).
|
||||
|
||||
19 Folien (16:9) mit den Ansible-Brandfarben (Rot #EE0000, Anthrazit #1A1918).
|
||||
Fonts: Carlito (Body) + DejaVu Sans Mono (Code) — auf dem Zielsystem installiert
|
||||
und von OnlyOffice korrekt gerendert (kein Font-Substitution-Bruch).
|
||||
|
||||
Behandelt:
|
||||
- Was ist Ansible? / Aufbau & Architektur
|
||||
- YAML-Syntax, Playbooks, Module, Ad-hoc-Befehle
|
||||
- Jinja2 (Templating) und Gather Facts
|
||||
- Variablen-Auflösung (Präzedenz)
|
||||
- FQCN (Fully Qualified Collection Name)
|
||||
- Collections
|
||||
- Rollen (Roles)
|
||||
- Praxisbeispiel + Quellen
|
||||
|
||||
Benötigt: pip install python-pptx matplotlib Pillow
|
||||
Bilder: Ansible-Logo (assets/ansible_mark_*.png, Quelle: Wikimedia Commons)
|
||||
Architektur-Diagramm wird automatisch erzeugt (assets/architektur.png)
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.patches import FancyBboxPatch
|
||||
|
||||
from pptx import Presentation
|
||||
from pptx.util import Inches, Pt
|
||||
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
|
||||
from pptx.enum.shapes import MSO_SHAPE
|
||||
from pptx.dml.color import RGBColor
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pfade & Farben
|
||||
# ---------------------------------------------------------------------------
|
||||
BASE = os.path.dirname(os.path.abspath(__file__))
|
||||
ASSETS = os.path.join(BASE, "assets")
|
||||
os.makedirs(ASSETS, exist_ok=True)
|
||||
|
||||
LOGO_RED = os.path.join(ASSETS, "ansible_mark_red.png")
|
||||
LOGO_WHITE = os.path.join(ASSETS, "ansible_mark_white.png")
|
||||
ARCH = os.path.join(ASSETS, "architektur.png")
|
||||
|
||||
BLACK = RGBColor(0x1A, 0x19, 0x18)
|
||||
RED = RGBColor(0xEE, 0x00, 0x00)
|
||||
DARKRED = RGBColor(0xB0, 0x00, 0x00)
|
||||
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
|
||||
LIGHT = RGBColor(0xF7, 0xF7, 0xF7)
|
||||
CARD = RGBColor(0xFF, 0xFF, 0xFF)
|
||||
GRAY = RGBColor(0x55, 0x55, 0x55) # dunkler für bessere Lesbarkeit
|
||||
MIDGRAY = RGBColor(0x8A, 0x8A, 0x8A)
|
||||
BORDER = RGBColor(0xDD, 0xDD, 0xDD)
|
||||
CODE_BG = RGBColor(0x1E, 0x1E, 0x1E)
|
||||
CODE_CMT= RGBColor(0x8B, 0xC3, 0x7C) # grün für Kommentare
|
||||
CODE_KEY= RGBColor(0x7E, 0xC8, 0xFF) # hellblau für Schlüssel
|
||||
CODE_MOD= RGBColor(0xFF, 0x6B, 0x6B) # rot für Module/FQCN
|
||||
|
||||
# Fonts: auf dem Zielsystem installiert (OnlyOffice-kompatibel)
|
||||
FONT = "Carlito"
|
||||
FONT_MONO = "DejaVu Sans Mono"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Architektur-Diagramm (matplotlib)
|
||||
# ---------------------------------------------------------------------------
|
||||
def make_architecture_diagram(path):
|
||||
C_RED, C_BLACK, C_GRAY = "#EE0000", "#1A1918", "#6E6E6E"
|
||||
fig, ax = plt.subplots(figsize=(11, 5.0), dpi=170)
|
||||
ax.set_xlim(0, 11); ax.set_ylim(0, 5.0); ax.axis("off")
|
||||
|
||||
def box(x, y, w, h, fc, ec, lw=1.5, r=0.12):
|
||||
p = FancyBboxPatch((x, y), w, h, boxstyle=f"round,pad=0.06,rounding_size={r}",
|
||||
fc=fc, ec=ec, lw=lw)
|
||||
ax.add_patch(p); return p
|
||||
|
||||
box(0.5, 0.7, 4.3, 3.7, "#1A1918", C_RED, lw=2.5)
|
||||
ax.text(2.65, 3.95, "CONTROL NODE", ha="center", va="center",
|
||||
color="white", fontsize=15, fontweight="bold")
|
||||
ax.text(2.65, 3.45, "Ansible installiert", ha="center", va="center",
|
||||
color=C_RED, fontsize=10.5, fontweight="bold")
|
||||
items = ["Playbooks (YAML)", "Inventory", "Module & Plugins", "Rollen & Collections"]
|
||||
for i, it in enumerate(items):
|
||||
y = 2.85 - i * 0.5
|
||||
box(0.95, y - 0.18, 3.4, 0.36, "#2B2B2B", "none")
|
||||
ax.text(2.65, y, it, ha="center", va="center", color="white", fontsize=10.5)
|
||||
|
||||
ax.annotate("", xy=(5.75, 2.6), xytext=(4.9, 2.6),
|
||||
arrowprops=dict(arrowstyle="-|>", color=C_RED, lw=2.6))
|
||||
ax.text(5.32, 3.05, "SSH", ha="center", va="center", color=C_RED,
|
||||
fontsize=12, fontweight="bold")
|
||||
ax.text(5.32, 2.1, "agentenlos", ha="center", va="center", color=C_GRAY, fontsize=8.5)
|
||||
|
||||
box(5.95, 0.7, 4.6, 3.7, "#F7F7F7", C_BLACK, lw=1.5)
|
||||
ax.text(8.25, 3.95, "MANAGED NODES", ha="center", va="center",
|
||||
color=C_BLACK, fontsize=15, fontweight="bold")
|
||||
ax.text(8.25, 3.45, "Ziel-Systeme — kein Agent nötig", ha="center", va="center",
|
||||
color=C_GRAY, fontsize=10)
|
||||
nodes = [("Web-Server", "Linux"), ("Datenbank", "Linux"), ("App-Server", "Windows")]
|
||||
xs = [6.6, 8.25, 9.9]
|
||||
for (name, os_), x in zip(nodes, xs):
|
||||
box(x - 0.62, 1.0, 1.24, 1.5, "white", C_RED, lw=2, r=0.1)
|
||||
ax.text(x, 1.95, name, ha="center", va="center", color=C_BLACK,
|
||||
fontsize=10, fontweight="bold")
|
||||
ax.text(x, 1.4, os_, ha="center", va="center", color=C_GRAY, fontsize=9)
|
||||
|
||||
fig.savefig(path, bbox_inches="tight", facecolor="white", transparent=False)
|
||||
plt.close(fig)
|
||||
return path
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# pptx-Helfer
|
||||
# ---------------------------------------------------------------------------
|
||||
prs = Presentation()
|
||||
prs.slide_width = Inches(13.333)
|
||||
prs.slide_height = Inches(7.5)
|
||||
BLANK = prs.slide_layouts[6]
|
||||
|
||||
|
||||
def new_slide(bg=None):
|
||||
s = prs.slides.add_slide(BLANK)
|
||||
if bg is not None:
|
||||
r = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, prs.slide_width, prs.slide_height)
|
||||
r.fill.solid(); r.fill.fore_color.rgb = bg
|
||||
r.line.fill.background(); r.shadow.inherit = False
|
||||
return s
|
||||
|
||||
|
||||
def rect(slide, x, y, w, h, fill, line=None, line_w=1.0, rounded=False, radius=0.08):
|
||||
shp_type = MSO_SHAPE.ROUNDED_RECTANGLE if rounded else MSO_SHAPE.RECTANGLE
|
||||
shp = slide.shapes.add_shape(shp_type, Inches(x), Inches(y), Inches(w), Inches(h))
|
||||
if fill is None:
|
||||
shp.fill.background()
|
||||
else:
|
||||
shp.fill.solid(); shp.fill.fore_color.rgb = fill
|
||||
if line is None:
|
||||
shp.line.fill.background()
|
||||
else:
|
||||
shp.line.color.rgb = line; shp.line.width = Pt(line_w)
|
||||
shp.shadow.inherit = False
|
||||
if rounded:
|
||||
try:
|
||||
shp.adjustments[0] = radius
|
||||
except Exception:
|
||||
pass
|
||||
return shp
|
||||
|
||||
|
||||
def text(slide, x, y, w, h, runs, size=14, bold=False, color=BLACK,
|
||||
align=PP_ALIGN.LEFT, font=FONT, anchor=MSO_ANCHOR.TOP, leading=1.0,
|
||||
space_after=0):
|
||||
box = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
|
||||
tf = box.text_frame
|
||||
tf.word_wrap = True
|
||||
tf.vertical_anchor = anchor
|
||||
tf.margin_left = 0; tf.margin_right = 0; tf.margin_top = 0; tf.margin_bottom = 0
|
||||
|
||||
if isinstance(runs, str):
|
||||
runs = [runs]
|
||||
|
||||
for i, item in enumerate(runs):
|
||||
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
|
||||
p.alignment = align
|
||||
p.line_spacing = leading
|
||||
if space_after:
|
||||
p.space_after = Pt(space_after)
|
||||
if isinstance(item, str):
|
||||
item = {"t": item}
|
||||
elif isinstance(item, tuple):
|
||||
item = {"t": item[0], **item[1]}
|
||||
r = p.add_run(); r.text = item["t"]
|
||||
r.font.size = Pt(item.get("size", size))
|
||||
r.font.bold = item.get("bold", bold)
|
||||
r.font.italic = item.get("italic", False)
|
||||
r.font.name = item.get("font", font)
|
||||
r.font.color.rgb = item.get("color", color)
|
||||
return box
|
||||
|
||||
|
||||
def header(slide, kicker, title, dark=False):
|
||||
text(slide, 0.55, 0.42, 12.2, 0.3, kicker.upper(),
|
||||
size=11, bold=True, color=RED, font=FONT)
|
||||
text(slide, 0.55, 0.75, 12.2, 0.75, title,
|
||||
size=30, bold=True, color=WHITE if dark else BLACK)
|
||||
logo = LOGO_RED if not dark else LOGO_WHITE
|
||||
if os.path.exists(logo):
|
||||
slide.shapes.add_picture(logo, Inches(12.35), Inches(0.25), Inches(0.62), Inches(0.76))
|
||||
|
||||
|
||||
def footer(slide, num):
|
||||
text(slide, 0.55, 7.08, 9.0, 0.3, "Ansible — moderne Automatisierung",
|
||||
size=8, color=MIDGRAY)
|
||||
text(slide, 12.2, 7.08, 0.6, 0.3, str(num), size=9, color=MIDGRAY, align=PP_ALIGN.RIGHT)
|
||||
|
||||
|
||||
def _set_run(r, text, font_size, color, bold=False):
|
||||
r.text = text
|
||||
r.font.size = Pt(font_size)
|
||||
r.font.name = FONT_MONO
|
||||
r.font.color.rgb = color
|
||||
r.font.bold = bold
|
||||
|
||||
|
||||
def _style_kv(p, text, font_size):
|
||||
if ":" in text:
|
||||
key, colon, rest = text.partition(":")
|
||||
is_mod = ("ansible." in key) or ("community." in key)
|
||||
_set_run(p.add_run(), key, font_size,
|
||||
CODE_MOD if is_mod else CODE_KEY, bold=is_mod)
|
||||
_set_run(p.add_run(), colon + rest, font_size, WHITE)
|
||||
else:
|
||||
_set_run(p.add_run(), text, font_size, WHITE)
|
||||
|
||||
|
||||
def _style_code_line(p, line, font_size):
|
||||
"""Syntax-Einfärbung unter Erhalt der Einrückung."""
|
||||
m = re.match(r'^(\s*)(.*)$', line)
|
||||
lead, rest = m.group(1), m.group(2)
|
||||
if lead:
|
||||
_set_run(p.add_run(), lead, font_size, WHITE)
|
||||
if rest.startswith("#"):
|
||||
_set_run(p.add_run(), rest, font_size, CODE_CMT)
|
||||
return
|
||||
# FQCN (namespace.collection.modul) -> rot, fett
|
||||
if re.match(r'^[A-Za-z0-9_]+\.[A-Za-z0-9_]+\.[A-Za-z0-9_]+$', rest):
|
||||
_set_run(p.add_run(), rest, font_size, CODE_MOD, bold=True)
|
||||
return
|
||||
if rest.startswith("- "):
|
||||
_set_run(p.add_run(), "- ", font_size, CODE_MOD)
|
||||
_style_kv(p, rest[2:], font_size)
|
||||
return
|
||||
_style_kv(p, rest, font_size)
|
||||
|
||||
|
||||
def code_block(slide, x, y, w, lines, font_size=11, title=None, title_color=RED):
|
||||
"""Dunkler Code-Block mit automatischer Höhe (kein Überlauf)."""
|
||||
line_h = font_size * 1.32 / 72.0
|
||||
pad_top = 0.18
|
||||
pad_bot = 0.16
|
||||
title_h = 0.38 if title else 0.0
|
||||
n = len(lines) if lines else 1
|
||||
h = title_h + n * line_h + pad_top + pad_bot
|
||||
|
||||
rect(slide, x, y, w, h, CODE_BG, line=BORDER, line_w=0.75, rounded=True, radius=0.04)
|
||||
if title:
|
||||
rect(slide, x, y, w, 0.32, CODE_BG, line=BORDER, line_w=0.75, rounded=True, radius=0.14)
|
||||
text(slide, x + 0.25, y + 0.035, w - 0.5, 0.25, title,
|
||||
size=9.5, bold=True, color=title_color, font=FONT_MONO)
|
||||
y += title_h
|
||||
tb = slide.shapes.add_textbox(Inches(x + 0.22), Inches(y + pad_top),
|
||||
Inches(w - 0.44), Inches(h - pad_top - pad_bot))
|
||||
tf = tb.text_frame; tf.word_wrap = True
|
||||
tf.margin_left = 0; tf.margin_right = 0; tf.margin_top = 0; tf.margin_bottom = 0
|
||||
for i, line in enumerate(lines):
|
||||
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
|
||||
p.line_spacing = 1.05
|
||||
if line.strip() == "":
|
||||
_set_run(p.add_run(), " ", font_size, WHITE)
|
||||
continue
|
||||
_style_code_line(p, line, font_size)
|
||||
return h
|
||||
|
||||
|
||||
def card(slide, x, y, w, h, icon, title, body, accent=RED):
|
||||
rect(slide, x, y, w, h, CARD, line=BORDER, line_w=1.0, rounded=True, radius=0.06)
|
||||
if icon:
|
||||
circ = slide.shapes.add_shape(MSO_SHAPE.OVAL, Inches(x + 0.2), Inches(y + 0.2),
|
||||
Inches(0.44), Inches(0.44))
|
||||
circ.fill.solid(); circ.fill.fore_color.rgb = accent
|
||||
circ.line.fill.background(); circ.shadow.inherit = False
|
||||
text(slide, x + 0.2, y + 0.2, 0.44, 0.44, icon, size=14, bold=True,
|
||||
color=WHITE, align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
|
||||
text(slide, x + 0.78, y + 0.2, w - 0.95, 0.4, title, size=15, bold=True, color=BLACK)
|
||||
else:
|
||||
text(slide, x + 0.22, y + 0.2, w - 0.44, 0.4, title, size=15, bold=True, color=BLACK)
|
||||
text(slide, x + 0.22, y + 0.72, w - 0.44, h - 0.85, body, size=11, color=GRAY, leading=1.05)
|
||||
|
||||
|
||||
def kv_rows(slide, x, y, w, rows, key_w, name_size=11, desc_size=10.5, gap=0.42):
|
||||
"""Monospace-Schlüssel + Beschreibung in Zeilen. rows = [(key, desc), ...]"""
|
||||
yy = y
|
||||
for key, desc in rows:
|
||||
text(slide, x, yy, key_w, 0.3, key, size=name_size, bold=True,
|
||||
color=DARKRED, font=FONT_MONO)
|
||||
text(slide, x + key_w, yy, w - key_w, 0.4, desc, size=desc_size, color=GRAY, leading=1.0)
|
||||
yy += gap
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Diagramm erzeugen
|
||||
# ---------------------------------------------------------------------------
|
||||
make_architecture_diagram(ARCH)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 1 — Titel (dunkel)
|
||||
# ===========================================================================
|
||||
s = new_slide(BLACK)
|
||||
rect(s, 9.0, 0, 4.333, 7.5, RED, rounded=False)
|
||||
if os.path.exists(LOGO_WHITE):
|
||||
s.shapes.add_picture(LOGO_WHITE, Inches(0.9), Inches(1.35), Inches(2.1), Inches(2.59))
|
||||
text(s, 0.9, 4.15, 7.5, 0.4, "MODERNE IT-AUTOMATISIERUNG", size=14, bold=True, color=RED)
|
||||
text(s, 0.9, 4.55, 8.0, 1.3, "Ansible", size=60, bold=True, color=WHITE)
|
||||
text(s, 0.9, 5.75, 7.5, 0.4, "Agentenlos · Idempotent · Deklarativ · YAML",
|
||||
size=16, color=RGBColor(0xD8, 0xD8, 0xD8))
|
||||
text(s, 0.9, 6.55, 7.5, 0.4,
|
||||
"Was es ist · Aufbau · Syntax · Ad-hoc · Jinja2 · Facts · FQCN · Collections · Rollen",
|
||||
size=12, color=RGBColor(0x9A, 0x9A, 0x9A))
|
||||
text(s, 9.5, 1.6, 3.3, 0.3, "INHALT", size=12, bold=True, color=WHITE)
|
||||
agenda = [
|
||||
"1. Was ist Ansible?",
|
||||
"2. Aufbau & Architektur",
|
||||
"3. YAML, Playbooks & Ad-hoc",
|
||||
"4. Module, Jinja2 & Facts",
|
||||
"5. Variablen & Auflösung",
|
||||
"6. FQCN & Collections",
|
||||
"7. Rollen & Praxis",
|
||||
]
|
||||
text(s, 9.5, 2.15, 3.3, 4.0, agenda, size=14, color=WHITE, leading=1.5)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 2 — Was ist Ansible?
|
||||
# ===========================================================================
|
||||
s = new_slide(LIGHT)
|
||||
header(s, "Grundlagen", "Was ist Ansible?")
|
||||
rect(s, 0.55, 1.55, 8.0, 1.15, BLACK, rounded=True, radius=0.08)
|
||||
text(s, 0.85, 1.75, 7.4, 0.75,
|
||||
"Ansible ist ein Open-Source-Tool zur Automatisierung von IT-Aufgaben — "
|
||||
"Provisionierung, Konfigurationsmanagement und Anwendungs-Deployment.",
|
||||
size=15, color=WHITE, leading=1.15)
|
||||
card(s, 0.55, 3.0, 4.0, 1.8, "A", "Agentenlos",
|
||||
"Kein Agent auf Zielsystemen nötig. Kommunikation über SSH (Linux) bzw. WinRM (Windows).")
|
||||
card(s, 4.75, 3.0, 4.0, 1.8, "P", "Push-basiert",
|
||||
"Der Control Node stößt Änderungen aktiv an. Kein Pull-Mechanismus, kein ständiger Dienst.")
|
||||
card(s, 0.55, 5.0, 4.0, 1.8, "D", "Deklarativ",
|
||||
"Du beschreibst den gewünschten Ziel-Zustand in YAML — nicht die einzelnen Schritte.")
|
||||
card(s, 4.75, 5.0, 4.0, 1.8, "I", "Idempotent",
|
||||
"Mehrfaches Ausführen führt zum selben Ergebnis — keine doppelten Änderungen.")
|
||||
if os.path.exists(LOGO_RED):
|
||||
s.shapes.add_picture(LOGO_RED, Inches(9.4), Inches(1.9), Inches(1.7), Inches(2.09))
|
||||
text(s, 9.15, 4.1, 3.6, 0.3, "KEY FACTS", size=11, bold=True, color=RED)
|
||||
facts = [("Red Hat / IBM", "Open-Source-Projekt"),
|
||||
("Python", "Implementiert in Python"),
|
||||
("4000+", "Module verfügbar"),
|
||||
("2012", "Erstveröffentlichung")]
|
||||
yy = 4.5
|
||||
for big, small in facts:
|
||||
text(s, 9.15, yy, 1.8, 0.5, big, size=22, bold=True, color=BLACK)
|
||||
text(s, 10.95, yy + 0.08, 2.2, 0.5, small, size=11, color=GRAY, leading=1.0)
|
||||
yy += 0.62
|
||||
footer(s, 2)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 3 — Aufbau & Architektur
|
||||
# ===========================================================================
|
||||
s = new_slide(WHITE)
|
||||
header(s, "Architektur", "Wie ist Ansible aufgebaut?")
|
||||
if os.path.exists(ARCH):
|
||||
from PIL import Image as _Img
|
||||
_dw, _dh = _Img.open(ARCH).size
|
||||
_ar = _dw / _dh
|
||||
_w = 8.1
|
||||
_h = _w / _ar
|
||||
s.shapes.add_picture(ARCH, Inches(0.55), Inches(1.55), Inches(_w), Inches(_h))
|
||||
text(s, 8.95, 1.6, 3.9, 0.3, "KOMPONENTEN", size=11, bold=True, color=RED)
|
||||
comp = [
|
||||
("Control Node", "Rechner, auf dem Ansible installiert ist; enthält Playbooks & Inventory."),
|
||||
("Managed Nodes", "Zielsysteme, die über SSH/WinRM erreicht werden."),
|
||||
("Inventory", "Liste aller Hosts und Gruppen (INI oder YAML)."),
|
||||
("Module", "Bausteine, die eine Aufgabe ausführen (z.B. copy, apt)."),
|
||||
]
|
||||
yy = 2.0
|
||||
for t, d in comp:
|
||||
text(s, 8.95, yy, 3.9, 0.3, t, size=13, bold=True, color=BLACK)
|
||||
text(s, 8.95, yy + 0.28, 3.9, 0.9, d, size=10.5, color=GRAY, leading=1.05)
|
||||
yy += 1.22
|
||||
footer(s, 3)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 4 — Kernkonzepte
|
||||
# ===========================================================================
|
||||
s = new_slide(LIGHT)
|
||||
header(s, "Architektur", "Vier Kernkonzepte")
|
||||
card(s, 0.55, 1.6, 6.0, 2.4, "1", "Playbooks",
|
||||
"YAML-Dateien, die beschreiben, was auf welchen Hosts passieren soll. "
|
||||
"Ein Playbook enthält ein oder mehrere Plays mit Tasks (Aufgaben).")
|
||||
card(s, 6.85, 1.6, 6.0, 2.4, "2", "Inventory",
|
||||
"Die Host-Liste. Definiert Server, Gruppen und Variablen. Formate: INI oder YAML. "
|
||||
"Auch dynamisch (Cloud, VMware) möglich.")
|
||||
card(s, 0.55, 4.3, 6.0, 2.4, "3", "Module",
|
||||
"Kleine Programme, die eine konkrete Aktion ausführen: Paket installieren, Datei kopieren, "
|
||||
"Dienst starten. Werden über FQCN referenziert.")
|
||||
card(s, 6.85, 4.3, 6.0, 2.4, "4", "Rollen & Collections",
|
||||
"Rollen bündeln Tasks/Templates/Variablen zu wiederverwendbaren Einheiten. "
|
||||
"Collections verteilen Module, Rollen & Plugins.")
|
||||
footer(s, 4)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 5 — YAML-Syntax
|
||||
# ===========================================================================
|
||||
s = new_slide(WHITE)
|
||||
header(s, "Syntax", "YAML — die Sprache von Ansible")
|
||||
text(s, 0.55, 1.6, 5.6, 0.3, "GRUNDREGELN", size=11, bold=True, color=RED)
|
||||
rules = [
|
||||
("Schlüssel: Wert", "Einfache Zuweisungen, getrennt durch Doppelpunkt."),
|
||||
("Einrückung", "Struktur über Leerzeichen (2 Spaces, KEINE Tabs)."),
|
||||
("Listen", "Aufzählungen mit Bindestrich (-)."),
|
||||
("Lesbar", "YAML ist menschenlesbar, kein Code-Zwang."),
|
||||
]
|
||||
yy = 2.0
|
||||
for t, d in rules:
|
||||
text(s, 0.55, yy, 5.6, 0.3, t, size=13, bold=True, color=BLACK)
|
||||
text(s, 0.55, yy + 0.28, 5.6, 0.7, d, size=11, color=GRAY, leading=1.05)
|
||||
yy += 1.05
|
||||
code_block(s, 6.5, 1.6, 6.3, [
|
||||
"# Inventory (hosts.yml)",
|
||||
"all:",
|
||||
" hosts:",
|
||||
" webserver:",
|
||||
" ansible_host: 192.168.1.10",
|
||||
" database:",
|
||||
" ansible_host: 192.168.1.20",
|
||||
"",
|
||||
"# Schlüssel-Wert",
|
||||
"name: \"Mein Webserver\"",
|
||||
"paket: nginx",
|
||||
"",
|
||||
"# Liste",
|
||||
"pakete:",
|
||||
" - nginx",
|
||||
" - git",
|
||||
" - curl",
|
||||
], font_size=11)
|
||||
footer(s, 5)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 6 — Playbook & Tasks
|
||||
# ===========================================================================
|
||||
s = new_slide(WHITE)
|
||||
header(s, "Syntax", "Ein Playbook in der Praxis")
|
||||
text(s, 0.55, 1.55, 5.6, 1.4,
|
||||
[("Ein Playbook ", {}),
|
||||
("definiert, was passieren soll. ", {}),
|
||||
("plays", {"bold": True, "color": RED}),
|
||||
(" wirken auf ", {}),
|
||||
("hosts", {"bold": True, "color": RED}),
|
||||
(", jede ", {}),
|
||||
("task", {"bold": True, "color": RED}),
|
||||
(" ruft genau ein ", {}),
|
||||
("Modul", {"bold": True, "color": RED}),
|
||||
(" auf.", {})],
|
||||
size=12.5, color=BLACK, leading=1.2)
|
||||
code_block(s, 6.5, 1.55, 6.3, [
|
||||
"---",
|
||||
"- name: Webserver konfigurieren",
|
||||
" hosts: webserver",
|
||||
" become: true",
|
||||
"",
|
||||
" tasks:",
|
||||
" - name: nginx installieren",
|
||||
" ansible.builtin.apt:",
|
||||
" name: nginx",
|
||||
" state: present",
|
||||
"",
|
||||
" - name: Dienst starten",
|
||||
" ansible.builtin.service:",
|
||||
" name: nginx",
|
||||
" state: started",
|
||||
" enabled: true",
|
||||
], font_size=10.5, title="site.yml")
|
||||
footer(s, 6)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 7 — Module
|
||||
# ===========================================================================
|
||||
s = new_slide(LIGHT)
|
||||
header(s, "Syntax", "Module — die Arbeitspferde")
|
||||
text(s, 0.55, 1.6, 12.2, 0.8,
|
||||
"Ein Modul ist ein kleines, eigenständiges Programm, das eine Aufgabe auf dem "
|
||||
"Zielsystem ausführt. Ansible bringt hunderte Module mit — von Paketverwaltung "
|
||||
"über Datei-Operationen bis Cloud-Anbindung.",
|
||||
size=13, color=BLACK, leading=1.2)
|
||||
mods = [
|
||||
("apt / dnf", "Pakete installieren (Debian/RedHat)"),
|
||||
("copy / file", "Dateien kopieren & Rechte setzen"),
|
||||
("service", "Dienste starten / stoppen / aktivieren"),
|
||||
("template", "Jinja2-Templates rendern"),
|
||||
("user / group", "Benutzer & Gruppen verwalten"),
|
||||
("command / shell", "Beliebige Befehle ausführen"),
|
||||
]
|
||||
for i, (t, d) in enumerate(mods):
|
||||
col = i % 3; row = i // 3
|
||||
card(s, 0.55 + col * 4.2, 2.6 + row * 1.75, 3.95, 1.5, "•", t, d)
|
||||
text(s, 0.55, 6.15, 12.2, 0.6,
|
||||
[("Wichtig: Module werden heute über den ", {}),
|
||||
("FQCN", {"bold": True, "color": RED}),
|
||||
(" referenziert (z.B. ", {}),
|
||||
("ansible.builtin.apt", {"font": FONT_MONO, "color": DARKRED}),
|
||||
(").", {})],
|
||||
size=12, color=BLACK)
|
||||
footer(s, 7)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 8 — Ad-hoc-Befehle
|
||||
# ===========================================================================
|
||||
s = new_slide(WHITE)
|
||||
header(s, "Syntax", "Ad-hoc-Befehle — Ansible ohne Playbook")
|
||||
text(s, 0.55, 1.55, 5.7, 1.25,
|
||||
[("Mit dem ", {}),
|
||||
("ansible", {"font": FONT_MONO, "color": DARKRED, "bold": True}),
|
||||
("-CLI lassen sich einzelne Module direkt ausführen — ohne Playbook. Ideal "
|
||||
"für schnelle Checks und einmalige Aktionen.", {})],
|
||||
size=12.5, color=BLACK, leading=1.2)
|
||||
text(s, 0.55, 2.85, 5.7, 0.3, "AUFBAU", size=11, bold=True, color=RED)
|
||||
code_block(s, 0.55, 3.2, 5.7, [
|
||||
"ansible <hosts> -m <modul>",
|
||||
" -a \"<argumente>\"",
|
||||
], font_size=11, title="Kommando")
|
||||
text(s, 0.55, 4.55, 5.7, 0.3, "WICHTIGE OPTIONEN", size=11, bold=True, color=RED)
|
||||
kv_rows(s, 0.55, 4.95, 2.6, [
|
||||
("-m", "Modul"),
|
||||
("-a", "Argumente"),
|
||||
("-i", "Inventory"),
|
||||
], key_w=0.55, gap=0.4)
|
||||
kv_rows(s, 3.4, 4.95, 2.6, [
|
||||
("-b", "become (sudo)"),
|
||||
("-u", "Benutzer"),
|
||||
], key_w=0.55, gap=0.4)
|
||||
code_block(s, 6.6, 1.55, 6.2, [
|
||||
"# Erreichbarkeit testen",
|
||||
"ansible all -m ping",
|
||||
"",
|
||||
"# Facts anzeigen",
|
||||
"ansible webserver -m setup",
|
||||
"",
|
||||
"# Paket installieren",
|
||||
"ansible webserver -m apt",
|
||||
" -a \"name=nginx state=present\"",
|
||||
"",
|
||||
"# Dienst neu starten",
|
||||
"ansible webserver -m service",
|
||||
" -a \"name=nginx state=restarted\"",
|
||||
], font_size=10, title="Beispiele")
|
||||
footer(s, 8)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 9 — Jinja2 (Templating)
|
||||
# ===========================================================================
|
||||
s = new_slide(WHITE)
|
||||
header(s, "Syntax", "Jinja2 — dynamische Inhalte")
|
||||
text(s, 0.55, 1.55, 12.2, 0.7,
|
||||
"Jinja2 ist die Template-Engine von Ansible. Damit werden Variablen aufgelöst "
|
||||
"und Dateien dynamisch erzeugt — in Playbooks, aber vor allem in Templates (.j2).",
|
||||
size=13, color=BLACK, leading=1.15)
|
||||
card(s, 0.55, 2.4, 4.0, 1.7, "1", "Variable auflösen",
|
||||
[("{{ variable }}", {"font": FONT_MONO, "color": DARKRED, "bold": True}),
|
||||
(" setzt den Wert einer Variablen an die Stelle im Text ein.", {})])
|
||||
card(s, 4.75, 2.4, 4.0, 1.7, "2", "Filter anwenden",
|
||||
[("{{ wert | filter }}", {"font": FONT_MONO, "color": DARKRED, "bold": True}),
|
||||
(" transformiert Werte (z.B. ", {}),
|
||||
("upper", {"font": FONT_MONO}),
|
||||
(", ", {}),
|
||||
("default", {"font": FONT_MONO}),
|
||||
(").", {})])
|
||||
card(s, 8.95, 2.4, 3.85, 1.7, "3", "Template-Dateien",
|
||||
[("Dateien mit Endung ", {}),
|
||||
(".j2", {"font": FONT_MONO, "color": DARKRED, "bold": True}),
|
||||
(" werden vom Modul ", {}),
|
||||
("template", {"font": FONT_MONO}),
|
||||
(" gerendert.", {})])
|
||||
code_block(s, 0.55, 4.35, 6.0, [
|
||||
"# Variablen auflösen",
|
||||
"msg: \"Hallo {{ benutzer }}\"",
|
||||
"",
|
||||
"# Filter anwenden",
|
||||
"name: \"{{ name | upper }}\"",
|
||||
"port: \"{{ port | default(80) }}\"",
|
||||
], font_size=10.5, title="Variablen & Filter")
|
||||
code_block(s, 6.85, 4.35, 6.0, [
|
||||
"# nginx.conf.j2",
|
||||
"server {",
|
||||
" listen {{ nginx_port }};",
|
||||
" server_name {{ domain }};",
|
||||
" root {{ web_root }};",
|
||||
"}",
|
||||
], font_size=10.5, title="nginx.conf.j2")
|
||||
footer(s, 9)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 10 — Gather Facts
|
||||
# ===========================================================================
|
||||
s = new_slide(WHITE)
|
||||
header(s, "Facts", "Gather Facts — Systeminformationen")
|
||||
text(s, 0.55, 1.5, 12.2, 0.7,
|
||||
[("Ansible sammelt beim Start automatisch ", {}),
|
||||
("Facts", {"bold": True}),
|
||||
(" (Systeminfos) über jeden Host — über das Modul ", {}),
|
||||
("setup", {"font": FONT_MONO, "color": DARKRED}),
|
||||
(", standardmäßig ", {}),
|
||||
("gather_facts: true", {"font": FONT_MONO, "color": DARKRED}),
|
||||
(".", {})],
|
||||
size=13, color=BLACK, leading=1.15)
|
||||
|
||||
# Links: Facts als 2-Spalten-Raster (Name oben, Beschreibung darunter)
|
||||
text(s, 0.55, 2.4, 6.6, 0.3, "WAS MAN AUSLESEN KANN", size=11, bold=True, color=RED)
|
||||
facts = [
|
||||
("ansible_os_family", "Betriebssystem-Familie"),
|
||||
("ansible_distribution", "z.B. Ubuntu, Debian"),
|
||||
("ansible_hostname", "Hostname des Systems"),
|
||||
("ansible_default_ipv4.address", "IP-Adresse"),
|
||||
("ansible_memtotal_mb", "Arbeitsspeicher (MB)"),
|
||||
("ansible_processor_vcpus", "CPU-Kerne"),
|
||||
]
|
||||
for i, (name, desc) in enumerate(facts):
|
||||
col = i % 2
|
||||
row = i // 2
|
||||
cx = 0.55 + col * 3.3
|
||||
cy = 2.9 + row * 1.3
|
||||
text(s, cx, cy, 3.2, 0.35, name, size=11.5, bold=True,
|
||||
color=DARKRED, font=FONT_MONO)
|
||||
text(s, cx, cy + 0.38, 3.2, 0.5, desc, size=11, color=GRAY, leading=1.0)
|
||||
|
||||
# Rechts: ein einzelner, klarer Code-Block (Zugriff + Custom Facts)
|
||||
code_block(s, 7.25, 2.4, 5.55, [
|
||||
"# Zugriff im Playbook",
|
||||
"- name: OS anzeigen",
|
||||
" ansible.builtin.debug:",
|
||||
" msg: \"{{ ansible_distribution }}\"",
|
||||
"",
|
||||
"# Fakten deaktivieren (schneller)",
|
||||
"gather_facts: false",
|
||||
"",
|
||||
"# Eigene Facts setzen:",
|
||||
"# Datei: /etc/ansible/facts.d/app.fact",
|
||||
"# Abruf: {{ ansible_local.app.version }}",
|
||||
], font_size=11, title="Zugriff & Custom Facts")
|
||||
footer(s, 10)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 11 — Variablen & Auflösung (Präzedenz)
|
||||
# ===========================================================================
|
||||
s = new_slide(LIGHT)
|
||||
header(s, "Variablen", "Variablen definieren & auflösen")
|
||||
text(s, 0.55, 1.55, 5.7, 0.3, "WO KOMMEN SIE HER?", size=11, bold=True, color=RED)
|
||||
sources = [
|
||||
("Inventory", "host_vars / group_vars"),
|
||||
("Playbook", "vars: / vars_files:"),
|
||||
("Rollen", "vars/ & defaults/"),
|
||||
("Facts", "automatisch gesammelt"),
|
||||
("Laufzeit", "register & set_fact"),
|
||||
("CLI", "Extra-Variablen (-e)"),
|
||||
]
|
||||
yy = 2.0
|
||||
for t, d in sources:
|
||||
text(s, 0.55, yy, 2.2, 0.3, t, size=12.5, bold=True, color=BLACK)
|
||||
text(s, 2.9, yy, 3.3, 0.3, d, size=11, color=GRAY, font=FONT_MONO)
|
||||
yy += 0.55
|
||||
text(s, 6.85, 1.55, 6.0, 0.3, "PRÄZEDENZ — WER GEWINNT?", size=11, bold=True, color=RED)
|
||||
text(s, 6.85, 1.9, 6.0, 0.3, "Oben gewinnt — von höchster zu niedrigster Priorität:",
|
||||
size=10, color=GRAY)
|
||||
prec = [
|
||||
("Extra-Variablen", "ansible-playbook ... -e key=wert"),
|
||||
("Task-/Block-Variablen", "vars: direkt an der Aufgabe"),
|
||||
("set_fact / register", "Werte aus der Laufzeit"),
|
||||
("Rollen-Variablen", "roles/.../vars/main.yml"),
|
||||
("Playbook-Variablen", "vars: im Play"),
|
||||
("host_vars / group_vars", "aus dem Inventory"),
|
||||
("Rollen-Defaults", "roles/.../defaults/main.yml"),
|
||||
]
|
||||
yy = 2.25
|
||||
for i, (t, d) in enumerate(prec, 1):
|
||||
rect(s, 6.85, yy, 0.4, 0.4, RED, rounded=True, radius=0.3)
|
||||
text(s, 6.85, yy + 0.03, 0.4, 0.34, str(i), size=13, bold=True,
|
||||
color=WHITE, align=PP_ALIGN.CENTER)
|
||||
text(s, 7.4, yy + 0.02, 3.6, 0.34, t, size=12, bold=True, color=BLACK)
|
||||
text(s, 11.0, yy + 0.02, 1.85, 0.34, d, size=9, color=GRAY, font=FONT_MONO)
|
||||
yy += 0.5
|
||||
text(s, 6.85, yy + 0.1, 6.0, 0.6,
|
||||
[("Faustregel: ", {"bold": True, "color": RED}),
|
||||
("je spezifischer die Quelle, desto höher die Priorität.", {})],
|
||||
size=11, color=GRAY)
|
||||
footer(s, 11)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 12 — FQCN (Definition)
|
||||
# ===========================================================================
|
||||
s = new_slide(WHITE)
|
||||
header(s, "FQCN", "FQCN — Fully Qualified Collection Name")
|
||||
rect(s, 0.55, 1.55, 12.2, 0.95, LIGHT, line=BORDER, line_w=1.0, rounded=True, radius=0.1)
|
||||
text(s, 0.85, 1.77, 11.6, 0.55,
|
||||
[("FQCN = ", {"bold": True, "color": RED}),
|
||||
("eindeutige, vollständige Referenz auf ein Modul oder Plugin.", {})],
|
||||
size=16, color=BLACK)
|
||||
text(s, 0.85, 2.75, 11.6, 0.6, "namespace · collection · modul",
|
||||
size=28, bold=True, color=BLACK)
|
||||
code_block(s, 0.55, 3.6, 12.2, [
|
||||
"# FQCN = namespace.collection.modul",
|
||||
"",
|
||||
"ansible.builtin.copy",
|
||||
"",
|
||||
"# ansible -> namespace (Anbieter)",
|
||||
"# builtin -> collection (Paket)",
|
||||
"# copy -> modul (die Funktion)",
|
||||
], font_size=12, title="Beispiel")
|
||||
text(s, 0.55, 6.15, 12.2, 0.5,
|
||||
[("NICHT verwechseln mit ", {"bold": True}),
|
||||
("FQDN", {"font": FONT_MONO, "color": DARKRED, "bold": True}),
|
||||
(" (Fully Qualified Domain Name = Hostname)! Der FQCN macht eindeutig, "
|
||||
"aus welcher Collection ein Modul stammt.", {})],
|
||||
size=12.5, color=BLACK)
|
||||
footer(s, 12)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 13 — FQCN (Beispiele & Warum)
|
||||
# ===========================================================================
|
||||
s = new_slide(WHITE)
|
||||
header(s, "FQCN", "FQCN in der Praxis")
|
||||
text(s, 0.55, 1.6, 6.5, 0.4, "GÄNGIGE FQCN-BEISPIELE", size=11, bold=True, color=RED)
|
||||
ex = [
|
||||
("ansible.builtin.copy", "Datei kopieren"),
|
||||
("ansible.builtin.apt", "Paket installieren"),
|
||||
("ansible.builtin.service", "Dienst verwalten"),
|
||||
("ansible.builtin.template", "Template rendern"),
|
||||
("ansible.posix.firewalld", "Firewall (Collection)"),
|
||||
("community.general.git_config", "Git (Community)"),
|
||||
]
|
||||
yy = 2.1
|
||||
for fqcn, d in ex:
|
||||
rect(s, 0.55, yy, 3.7, 0.5, LIGHT, line=BORDER, line_w=0.75, rounded=True, radius=0.14)
|
||||
text(s, 0.8, yy + 0.1, 3.4, 0.3, fqcn, size=11, bold=True,
|
||||
color=DARKRED, font=FONT_MONO)
|
||||
text(s, 4.45, yy + 0.1, 2.6, 0.3, d, size=11.5, color=BLACK)
|
||||
yy += 0.62
|
||||
text(s, 7.35, 1.6, 5.4, 0.4, "WARUM FQCN?", size=11, bold=True, color=RED)
|
||||
rect(s, 7.35, 2.1, 5.45, 4.35, LIGHT, line=BORDER, line_w=1.0, rounded=True, radius=0.05)
|
||||
text(s, 7.65, 2.35, 4.9, 3.9, [
|
||||
("Seit Ansible 2.10 sind Module in ", {}),
|
||||
("Collections", {"bold": True}),
|
||||
(" gebündelt.\n\n", {}),
|
||||
("Der FQCN macht eindeutig, ", {}),
|
||||
("welches Modul", {"bold": True}),
|
||||
(" gemeint ist.\n\n", {}),
|
||||
("Er vermeidet ", {}),
|
||||
("Namenskollisionen", {"bold": True}),
|
||||
(" — mehrere Collections können ein gleichnamiges Modul anbieten.\n\n", {}),
|
||||
("Faustregel: ", {"bold": True, "color": RED}),
|
||||
("immer den FQCN verwenden, nie die Kurzform.", {}),
|
||||
], size=12.5, color=BLACK, leading=1.25)
|
||||
footer(s, 13)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 14 — Collections (Definition)
|
||||
# ===========================================================================
|
||||
s = new_slide(LIGHT)
|
||||
header(s, "Collections", "Was sind Collections?")
|
||||
rect(s, 0.55, 1.6, 12.2, 1.1, BLACK, rounded=True, radius=0.08)
|
||||
text(s, 0.85, 1.8, 11.6, 0.75,
|
||||
"Eine Collection ist das Verteilungsformat für Ansible-Inhalte. Sie bündelt "
|
||||
"Module, Plugins, Rollen, Playbooks und Dokumentation in einem Paket.",
|
||||
size=15, color=WHITE, leading=1.15)
|
||||
cols = [
|
||||
("Module", "Aktions-Bausteine (z.B. apt, firewalld)"),
|
||||
("Plugins", "Erweiterungen: Inventory, Connection, Filter"),
|
||||
("Rollen", "Wiederverwendbare Aufgaben-Sammlungen"),
|
||||
("Playbooks", "Fertige Abläufe als Vorlage"),
|
||||
("Dokumentation", "Beschreibung & Beispiele (docs/)"),
|
||||
("Test", "Tests & CI für die Collection"),
|
||||
]
|
||||
for i, (t, d) in enumerate(cols):
|
||||
col = i % 3; row = i // 3
|
||||
card(s, 0.55 + col * 4.2, 3.0 + row * 1.6, 3.95, 1.35, "•", t, d)
|
||||
footer(s, 14)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 15 — Collections (Struktur & Galaxy)
|
||||
# ===========================================================================
|
||||
s = new_slide(WHITE)
|
||||
header(s, "Collections", "Collections nutzen")
|
||||
text(s, 0.55, 1.55, 5.8, 0.3, "BEZUGSQUELLE", size=11, bold=True, color=RED)
|
||||
text(s, 0.55, 1.9, 5.8, 0.85,
|
||||
[("Ansible Galaxy", {"bold": True}),
|
||||
(" (galaxy.ansible.com) ist der zentrale Hub — vergleichbar mit einem "
|
||||
"Paket-Manager für Ansible-Inhalte.", {})],
|
||||
size=12, color=BLACK, leading=1.15)
|
||||
text(s, 0.55, 2.85, 5.8, 0.3, "INSTALLATION", size=11, bold=True, color=RED)
|
||||
code_block(s, 0.55, 3.25, 5.8, [
|
||||
"# Installation",
|
||||
"ansible-galaxy collection",
|
||||
" install ansible.posix",
|
||||
"",
|
||||
"# requirements.yml",
|
||||
"collections:",
|
||||
" - name: ansible.posix",
|
||||
" version: '>=1.5.0'",
|
||||
], font_size=11, title="galaxy")
|
||||
text(s, 6.85, 1.55, 5.9, 0.3, "NAMENSSCHEMA", size=11, bold=True, color=RED)
|
||||
text(s, 6.85, 1.9, 5.9, 0.45,
|
||||
[("namespace", {"font": FONT_MONO, "color": DARKRED, "bold": True}),
|
||||
(" . ", {"color": BLACK, "bold": True}),
|
||||
("name", {"font": FONT_MONO, "color": DARKRED, "bold": True}),
|
||||
(" → z.B. ", {}),
|
||||
("ansible.posix", {"font": FONT_MONO, "color": DARKRED, "bold": True})],
|
||||
size=14)
|
||||
text(s, 6.85, 2.5, 5.9, 0.3, "AUFBAU EINER COLLECTION", size=11, bold=True, color=RED)
|
||||
code_block(s, 6.85, 2.9, 5.9, [
|
||||
"ansible-posix/",
|
||||
" plugins/modules/",
|
||||
" plugins/inventory/",
|
||||
" roles/",
|
||||
" playbooks/",
|
||||
" docs/",
|
||||
" galaxy.yml",
|
||||
], font_size=11.5, title="ansible.posix")
|
||||
footer(s, 15)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 16 — Rollen (Konzept)
|
||||
# ===========================================================================
|
||||
s = new_slide(LIGHT)
|
||||
header(s, "Rollen", "Wie funktionieren Rollen?")
|
||||
rect(s, 0.55, 1.6, 12.2, 1.05, BLACK, rounded=True, radius=0.08)
|
||||
text(s, 0.85, 1.78, 11.6, 0.75,
|
||||
"Eine Rolle ist eine wiederverwendbare, in sich geschlossene Einheit von "
|
||||
"Aufgaben. Sie kapselt Tasks, Variablen, Templates und Handler zu einer "
|
||||
"logischen Funktion — z.B. „installiere & konfiguriere einen Webserver“.",
|
||||
size=14.5, color=WHITE, leading=1.15)
|
||||
points = [
|
||||
("Wiederverwendbar", "Einmal schreiben, in vielen Playbooks nutzen."),
|
||||
("Gekapselt", "Eigene Variablen, Templates & Dateien pro Rolle."),
|
||||
("Teilbar", "Über Collections & Galaxy mit anderen teilen."),
|
||||
("Strukturiert", "Klare Verzeichnis-Struktur (tasks, handlers, …)."),
|
||||
]
|
||||
for i, (t, d) in enumerate(points):
|
||||
col = i % 2; row = i // 2
|
||||
card(s, 0.55 + col * 6.2, 3.0 + row * 1.8, 5.95, 1.55, "✓", t, d)
|
||||
footer(s, 16)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 17 — Rollen (Verzeichnisstruktur)
|
||||
# ===========================================================================
|
||||
s = new_slide(WHITE)
|
||||
header(s, "Rollen", "Die Verzeichnisstruktur einer Rolle")
|
||||
text(s, 0.55, 1.55, 5.5, 0.3, "ANATOMIE", size=11, bold=True, color=RED)
|
||||
text(s, 0.55, 1.9, 5.5, 0.9,
|
||||
"Eine Rolle folgt einem festen Aufbau. Jede Datei hat eine klar definierte "
|
||||
"Aufgabe — Ansible lädt sie automatisch.",
|
||||
size=12, color=BLACK, leading=1.15)
|
||||
expl = [
|
||||
("tasks/main.yml", "Hauptaufgaben der Rolle"),
|
||||
("handlers/main.yml", "Neustart-/Trigger-Aktionen"),
|
||||
("templates/", "Jinja2-Templates (.j2)"),
|
||||
("files/", "Statische Dateien (Copy-Quelle)"),
|
||||
("vars/main.yml", "Variablen (hohe Priorität)"),
|
||||
("defaults/main.yml", "Standard-Variablen (niedrig)"),
|
||||
("meta/main.yml", "Abhängigkeiten & Infos"),
|
||||
]
|
||||
yy = 2.6
|
||||
for f, d in expl:
|
||||
text(s, 0.55, yy, 3.0, 0.3, f, size=11, bold=True, color=DARKRED, font=FONT_MONO)
|
||||
text(s, 3.7, yy, 2.6, 0.5, d, size=10.5, color=GRAY, leading=1.0)
|
||||
yy += 0.55
|
||||
code_block(s, 6.7, 1.55, 6.1, [
|
||||
"roles/webserver/",
|
||||
" tasks/",
|
||||
" main.yml",
|
||||
" handlers/",
|
||||
" main.yml",
|
||||
" templates/",
|
||||
" files/",
|
||||
" vars/",
|
||||
" main.yml",
|
||||
" defaults/",
|
||||
" main.yml",
|
||||
" meta/",
|
||||
" main.yml",
|
||||
], font_size=11.5, title="roles/webserver/")
|
||||
footer(s, 17)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 18 — Praxisbeispiel
|
||||
# ===========================================================================
|
||||
s = new_slide(LIGHT)
|
||||
header(s, "Praxis", "Alles zusammen: Playbook mit Rolle")
|
||||
text(s, 0.55, 1.55, 5.3, 0.3, "ZUSAMMENSPIEL", size=11, bold=True, color=RED)
|
||||
text(s, 0.55, 1.9, 5.3, 2.8,
|
||||
[("Das Playbook referenziert die Rolle ", {}),
|
||||
("webserver", {"font": FONT_MONO, "color": DARKRED, "bold": True}),
|
||||
(". FQCN-Module (", {}),
|
||||
("ansible.builtin.*", {"font": FONT_MONO, "color": DARKRED}),
|
||||
(") arbeiten im Hintergrund.\n\n", {}),
|
||||
("1.", {"bold": True, "color": RED}), (" Rolle wird geladen.\n", {}),
|
||||
("2.", {"bold": True, "color": RED}), (" Aufgaben & Variablen aus der Rolle gelten.\n", {}),
|
||||
("3.", {"bold": True, "color": RED}), (" Idempotenz verhindert doppelte Arbeit.", {})],
|
||||
size=12, color=BLACK, leading=1.25)
|
||||
code_block(s, 6.15, 1.55, 6.6, [
|
||||
"---",
|
||||
"- name: Webserver ausrollen",
|
||||
" hosts: webserver",
|
||||
" become: true",
|
||||
"",
|
||||
" roles:",
|
||||
" - webserver",
|
||||
"",
|
||||
" vars:",
|
||||
" nginx_port: 8080",
|
||||
], font_size=11, title="deploy.yml")
|
||||
footer(s, 18)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# FOLIE 19 — Zusammenfassung & Quellen
|
||||
# ===========================================================================
|
||||
s = new_slide(LIGHT)
|
||||
header(s, "Fazit", "Zusammenfassung")
|
||||
takeaways = [
|
||||
("Was", "Agentenloses, deklaratives Automatisierungs-Tool (SSH, YAML)."),
|
||||
("Aufbau", "Control Node, Managed Nodes, Inventory, Module, Playbooks."),
|
||||
("Syntax", "YAML + Jinja2 ({{ variable }}) für dynamische Inhalte."),
|
||||
("Ad-hoc", "ansible <hosts> -m <modul> für schnelle Einzelaktionen."),
|
||||
("Facts", "Systeminfos werden automatisch gesammelt (gather_facts)."),
|
||||
("Variablen", "Auflösung nach Präzedenz — Extra-Vars gewinnen, Defaults verlieren."),
|
||||
("FQCN", "Eindeutige Modul-Referenz: namespace.collection.modul."),
|
||||
("Collections", "Pakete mit Modulen, Rollen & Plugins (Galaxy)."),
|
||||
("Rollen", "Wiederverwendbare, gekapselte Aufgaben-Einheiten."),
|
||||
]
|
||||
yy = 1.6
|
||||
for t, d in takeaways:
|
||||
text(s, 0.75, yy, 2.0, 0.4, t, size=13, bold=True, color=RED)
|
||||
text(s, 2.85, yy + 0.02, 6.7, 0.5, d, size=11.5, color=BLACK, leading=1.05)
|
||||
yy += 0.52
|
||||
rect(s, 9.8, 1.7, 2.95, 4.6, LIGHT, line=BORDER, line_w=1.0, rounded=True, radius=0.06)
|
||||
if os.path.exists(LOGO_RED):
|
||||
s.shapes.add_picture(LOGO_RED, Inches(10.35), Inches(1.95), Inches(1.2), Inches(1.48))
|
||||
text(s, 10.05, 3.6, 2.4, 0.3, "QUELLEN", size=11, bold=True, color=RED, align=PP_ALIGN.CENTER)
|
||||
text(s, 10.05, 3.95, 2.5, 1.9,
|
||||
["docs.ansible.com", "galaxy.ansible.com", "github.com/ansible",
|
||||
"Logo: Wikimedia Commons"],
|
||||
size=9.5, color=GRAY, leading=1.4)
|
||||
footer(s, 19)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Speichern
|
||||
# ---------------------------------------------------------------------------
|
||||
OUT = os.path.join(BASE, "ansible_praesentation.pptx")
|
||||
prs.save(OUT)
|
||||
print(f"OK — gespeichert: {OUT}")
|
||||
print(f"Folien: {len(prs.slides)}")
|
||||
Binary file not shown.
+231
@@ -0,0 +1,231 @@
|
||||
# Ansible — Syntax & Variablen-Handout
|
||||
|
||||
Kompakte Referenz zu YAML-Syntax, Ad-hoc-Befehlen, Jinja2, Facts, Variablen-Auflösung und FQCN.
|
||||
|
||||
---
|
||||
|
||||
## 1. YAML-Grundsyntax
|
||||
|
||||
| Element | Syntax | Beispiel |
|
||||
|--------------------|-----------------|--------------------------|
|
||||
| Schlüssel-Wert | `key: wert` | `name: webserver` |
|
||||
| Liste | `- eintrag` | `- nginx` |
|
||||
| Verschachtelung | Einrückung | 2 Leerzeichen (KEINE Tabs) |
|
||||
| Kommentar | `# text` | `# Dies ist ein Kommentar` |
|
||||
| Zeichenkette | mit/ohne Quotes | `name: "Mein Server"` |
|
||||
|
||||
Einrückung mit 2 Leerzeichen (niemals Tabs!):
|
||||
|
||||
```yaml
|
||||
user:
|
||||
name: admin
|
||||
shell: /bin/bash
|
||||
groups:
|
||||
- sudo
|
||||
- docker
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Ad-hoc-Befehle (ohne Playbook)
|
||||
|
||||
```bash
|
||||
ansible <hosts> -m <modul> -a "<argumente>"
|
||||
```
|
||||
|
||||
Beispiele:
|
||||
|
||||
```bash
|
||||
# Erreichbarkeit testen
|
||||
ansible all -m ping
|
||||
|
||||
# Facts anzeigen
|
||||
ansible webserver -m setup
|
||||
|
||||
# Paket installieren
|
||||
ansible webserver -m apt -a "name=nginx state=present"
|
||||
|
||||
# Dienst neu starten
|
||||
ansible webserver -m service -a "name=nginx state=restarted"
|
||||
```
|
||||
|
||||
Wichtige Optionen:
|
||||
|
||||
| Option | Bedeutung |
|
||||
|--------|----------------------|
|
||||
| `-m` | Modul wählen |
|
||||
| `-a` | Argumente übergeben |
|
||||
| `-i` | Inventory angeben |
|
||||
| `-b` | become (sudo) |
|
||||
| `-u` | Benutzer |
|
||||
|
||||
---
|
||||
|
||||
## 3. Jinja2 — Variablen auflösen
|
||||
|
||||
Ansible nutzt die Template-Engine **Jinja2**. Variablen werden in doppelte
|
||||
geschweifte Klammern gesetzt:
|
||||
|
||||
```yaml
|
||||
# Wert einsetzen
|
||||
message: "Hallo {{ benutzer }}"
|
||||
path: "/home/{{ benutzer }}/.config"
|
||||
|
||||
# Verschachtelte Variablen
|
||||
db_host: "{{ hostvars['db'].ansible_host }}"
|
||||
```
|
||||
|
||||
### Filter
|
||||
|
||||
```yaml
|
||||
name: "{{ name | upper }}" # -> GROSSSCHREIBUNG
|
||||
port: "{{ port | default(80) }}" # Fallback, wenn Variable leer
|
||||
anzahl: "{{ liste | length }}" # Anzahl der Elemente
|
||||
ip: "{{ ansible_host | ipaddr }}" # IP-Adresse validieren
|
||||
```
|
||||
|
||||
### Template-Dateien (.j2)
|
||||
|
||||
Dateien mit Endung `.j2` werden vom Modul `template` gerendert:
|
||||
|
||||
```jinja
|
||||
# nginx.conf.j2
|
||||
server {
|
||||
listen {{ nginx_port }};
|
||||
server_name {{ domain }};
|
||||
root {{ web_root }};
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Gather Facts (Systeminformationen)
|
||||
|
||||
Ansible sammelt automatisch **Facts** (Systeminformationen) über jeden Host —
|
||||
über das Modul `setup`, standardmäßig `gather_facts: true`.
|
||||
|
||||
Häufige Facts:
|
||||
|
||||
| Fact | Bedeutung |
|
||||
|---------------------------------|-------------------------------|
|
||||
| `ansible_os_family` | OS-Familie (Debian, RedHat) |
|
||||
| `ansible_distribution` | z.B. Ubuntu, CentOS, Debian |
|
||||
| `ansible_distribution_version` | Version (z.B. 22.04) |
|
||||
| `ansible_hostname` | Hostname des Systems |
|
||||
| `ansible_default_ipv4.address` | IP-Adresse |
|
||||
| `ansible_architecture` | CPU-Architektur (x86_64) |
|
||||
| `ansible_memtotal_mb` | RAM in MB |
|
||||
| `ansible_processor_vcpus` | Anzahl CPU-Kerne |
|
||||
|
||||
Zugriff im Playbook:
|
||||
|
||||
```yaml
|
||||
- name: OS anzeigen
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ ansible_distribution }} {{ ansible_distribution_version }}"
|
||||
```
|
||||
|
||||
Eigene Facts (Custom Facts) setzen:
|
||||
|
||||
```bash
|
||||
# Datei anlegen (INI-Format):
|
||||
# /etc/ansible/facts.d/app.fact
|
||||
# Inhalt:
|
||||
# [app]
|
||||
# version=1.2.3
|
||||
# Abruf: {{ ansible_local.app.version }}
|
||||
```
|
||||
|
||||
Facts deaktivieren (Performance):
|
||||
|
||||
```yaml
|
||||
gather_facts: false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Wo Variablen definiert werden
|
||||
|
||||
| Quelle | Datei / Ort | Beispiel |
|
||||
|------------|------------------------------------|---------------------------------|
|
||||
| Inventory | `host_vars/`, `group_vars/` | `group_vars/webserver.yml` |
|
||||
| Playbook | `vars:` / `vars_files:` | `vars: { port: 8080 }` |
|
||||
| Rolle | `roles/<rolle>/vars/` + `defaults/`| `vars/main.yml` |
|
||||
| Facts | automatisch gesammelt | `ansible_os_family` |
|
||||
| Laufzeit | `register` / `set_fact` | `register: result` |
|
||||
| CLI | Extra-Variablen | `-e "port=8080"` |
|
||||
|
||||
---
|
||||
|
||||
## 6. Variablen-Präzedenz (Auflösungs-Reihenfolge)
|
||||
|
||||
Ist dieselbe Variable an mehreren Stellen definiert, gewinnt die mit der
|
||||
**höchsten** Priorität (oben = gewinnt):
|
||||
|
||||
1. **Extra-Variablen** (CLI `-e`) — gewinnen immer
|
||||
2. **Task-/Block-Variablen** (`vars:` direkt an der Aufgabe)
|
||||
3. **set_fact / register** (Werte aus der Laufzeit)
|
||||
4. **Rollen-Variablen** (`roles/.../vars/main.yml`)
|
||||
5. **Playbook-Variablen** (`vars:` im Play)
|
||||
6. **host_vars / group_vars** (aus dem Inventory)
|
||||
7. **Rollen-Defaults** (`roles/.../defaults/main.yml`) — verlieren
|
||||
|
||||
> **Faustregel:** Je spezifischer die Quelle, desto höher die Priorität.
|
||||
|
||||
---
|
||||
|
||||
## 7. Module & FQCN
|
||||
|
||||
FQCN = **Fully Qualified Collection Name** — `namespace.collection.modul`.
|
||||
|
||||
```yaml
|
||||
ansible.builtin.apt:
|
||||
name: nginx
|
||||
state: present
|
||||
```
|
||||
|
||||
| FQCN | Zweck |
|
||||
|-----------------------------------|---------------------------|
|
||||
| `ansible.builtin.copy` | Datei kopieren |
|
||||
| `ansible.builtin.apt` | Paket installieren (Debian) |
|
||||
| `ansible.builtin.service` | Dienst verwalten |
|
||||
| `ansible.builtin.template` | `.j2`-Template rendern |
|
||||
| `ansible.posix.firewalld` | Firewall konfigurieren |
|
||||
| `community.general.git_config` | Git-Einstellungen |
|
||||
|
||||
---
|
||||
|
||||
## 8. Vollständiges Beispiel
|
||||
|
||||
**Playbook** (`deploy.yml`):
|
||||
|
||||
```yaml
|
||||
- name: Webserver ausrollen
|
||||
hosts: webserver
|
||||
become: true
|
||||
vars:
|
||||
nginx_port: 8080 # überschreibt den Rollen-Default
|
||||
roles:
|
||||
- webserver
|
||||
```
|
||||
|
||||
**Rollen-Defaults** (`roles/webserver/defaults/main.yml`) — niedrigste Priorität:
|
||||
|
||||
```yaml
|
||||
nginx_port: 80
|
||||
domain: example.com
|
||||
```
|
||||
|
||||
**Rollen-Tasks** (`roles/webserver/tasks/main.yml`):
|
||||
|
||||
```yaml
|
||||
- name: nginx installieren
|
||||
ansible.builtin.apt:
|
||||
name: nginx
|
||||
state: present
|
||||
|
||||
- name: Konfiguration rendern
|
||||
ansible.builtin.template:
|
||||
src: nginx.conf.j2
|
||||
dest: /etc/nginx/nginx.conf
|
||||
```
|
||||
Reference in New Issue
Block a user