Files
cluster-knaster/platform/proxmox/ansible/roles/pve-cluster/tasks/main.yml
T
2026-10-13 17:05:43 +02:00

189 lines
7.6 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
- name: Site-Datei laden
ansible.builtin.set_fact:
knaster_pve: "{{ lookup('ansible.builtin.file', pve_site_file) | from_yaml }}"
delegate_to: localhost
# ---------- 4.1 Benutzer, Gruppen, Rollen, Token ----------
- name: Rollen, Gruppen, Benutzer und ACLs lesen
ansible.builtin.shell: |
set -euo pipefail
python3 - <<'PY'
import json, subprocess
def get(p): return json.loads(subprocess.check_output(["pvesh", "get", p, "--output-format", "json"]))
print(json.dumps({
"roles": [r["roleid"] for r in get("/access/roles")],
"groups": [g["groupid"] for g in get("/access/groups")],
"users": [u["userid"] for u in get("/access/users")],
"acl": [[a["path"], a["ugid"], a["roleid"]] for a in get("/access/acl")],
}))
PY
args: {executable: /bin/bash}
register: access_raw
check_mode: false
changed_when: false
- name: Zugangsdaten als Fakt
ansible.builtin.set_fact:
pve_access: "{{ access_raw.stdout | from_json }}"
- name: Rolle für den Healer (nur Ein/Aus und Lesen der GPU-VMs)
ansible.builtin.command: pveum role add {{ pve_healer_role }} --privs "{{ pve_healer_privs }}"
when: pve_healer_role not in pve_access.roles
changed_when: true
- name: Admin-Gruppe
ansible.builtin.command: pveum group add {{ knaster_pve.access.admin_group }} --comment "Administratoren (knaster), root@pam nur Notfall"
when: knaster_pve.access.admin_group not in pve_access.groups
changed_when: true
- name: Admin-Gruppe darf alles (Administrator auf /)
ansible.builtin.command: pveum acl modify / --groups {{ knaster_pve.access.admin_group }} --roles Administrator
when: "['/', knaster_pve.access.admin_group, 'Administrator'] not in pve_access.acl"
changed_when: true
# Ohne Passwort: das setzt scripts/pve-admin-user.sh vom Laptop (zusammen mit TOTP und Recovery-Keys)
- name: Persönliche Admin-Konten
ansible.builtin.command: >
pveum user add {{ item }}@pve --groups {{ knaster_pve.access.admin_group }}
--comment "persönlicher Admin, Passwort/TOTP per pve-admin-user.sh"
loop: "{{ knaster_pve.access.admin_users }}"
when: (item ~ '@pve') not in pve_access.users
changed_when: true
- name: Healer-Benutzer
ansible.builtin.command: pveum user add {{ pve_healer_user }} --comment "knaster Healer (SPEC-healer), nur Token"
when: pve_healer_user not in pve_access.users
changed_when: true
- name: Healer darf GPU-VMs im Pool gpu schalten
ansible.builtin.command: pveum acl modify /pool/gpu --users {{ pve_healer_user }} --roles {{ pve_healer_role }}
when: "['/pool/gpu', pve_healer_user, pve_healer_role] not in pve_access.acl"
changed_when: true
- name: Healer-Token lesen
ansible.builtin.command: pveum user token list {{ pve_healer_user }} --output-format json
register: healer_tokens
check_mode: false
changed_when: false
- name: Healer-Token anlegen (Geheimnis nur einmal sichtbar)
ansible.builtin.command: >
pveum user token add {{ pve_healer_user }} {{ pve_healer_token }} --privsep 0
--comment "knaster Healer auf infra" --output-format json
register: healer_token_new
when: healer_tokens.stdout | from_json | selectattr('tokenid', 'equalto', pve_healer_token) | list | length == 0
no_log: true
changed_when: true
- name: Healer-Token auf ops ablegen (nur beim Anlegen)
ansible.builtin.copy:
dest: "{{ pve_healer_token_file }}"
content: |
PVE_USER={{ pve_healer_user }}
PVE_TOKEN_NAME={{ pve_healer_token }}
PVE_TOKEN_VALUE={{ (healer_token_new.stdout | from_json).value }}
mode: "0600"
delegate_to: localhost
when: healer_token_new is not skipped
no_log: true
- name: Healer-Token-Datei auf ops prüfen
ansible.builtin.stat:
path: "{{ pve_healer_token_file }}"
delegate_to: localhost
register: healer_file
- name: Hinweis, wenn der Token existiert, aber die Datei fehlt
ansible.builtin.debug:
msg: "Token {{ pve_healer_user }}!{{ pve_healer_token }} existiert, {{ pve_healer_token_file }} fehlt – Token entfernen (pveum user token remove) und Lauf wiederholen."
when: not healer_file.stat.exists
# ---------- 4.3 Benachrichtigungen ----------
- name: Benachrichtigungsziele und Matcher lesen
ansible.builtin.shell: |
set -euo pipefail
python3 - <<'PY'
import json, subprocess
def get(p): return json.loads(subprocess.check_output(["pvesh", "get", p, "--output-format", "json"]))
print(json.dumps({
"sendmail": {e["name"]: e for e in get("/cluster/notifications/endpoints/sendmail")},
"matchers": {m["name"]: m for m in get("/cluster/notifications/matchers")},
}))
PY
args: {executable: /bin/bash}
register: notify_raw
check_mode: false
changed_when: false
- name: Benachrichtigungen als Fakt
ansible.builtin.set_fact:
pve_notify: "{{ notify_raw.stdout | from_json }}"
# Zustellung direkt an die MX von mygodel.de (Postfix auf dem Knoten, 13.10. getestet: 250 queued)
- name: Mail-Ziel knaster-mail
ansible.builtin.command: >
pvesh create /cluster/notifications/endpoints/sendmail --name knaster-mail
--mailto {{ knaster_pve.access.mail_to }} --comment "Proxmox-Ereignisse an das KI-Postfach"
when: "'knaster-mail' not in pve_notify.sendmail"
register: notify_target
changed_when: true
- name: Matcher knaster-alles (jedes Ereignis an knaster-mail)
ansible.builtin.command: >
pvesh create /cluster/notifications/matchers --name knaster-alles --target knaster-mail
--comment "Backup, Fencing, Updates, Replikation"
when: "'knaster-alles' not in pve_notify.matchers"
changed_when: true
- name: Standard-Matcher abschalten (sonst kommt jede Mail doppelt)
ansible.builtin.command: pvesh set /cluster/notifications/matchers/default-matcher --disable 1
when: not (pve_notify.matchers['default-matcher'].disable | default(false))
changed_when: true
- name: Testnachricht über knaster-mail
ansible.builtin.command: pvesh create /cluster/notifications/targets/knaster-mail/test
when: notify_target is changed
changed_when: false
# ---------- 4.4 Firewall ----------
- name: Firewall-Regelwerk des Clusters schreiben
ansible.builtin.template:
src: cluster.fw.j2
dest: /etc/pve/firewall/cluster.fw
mode: "0640"
unsafe_writes: true
register: cluster_fw
- name: Regelwerk übersetzen (Syntaxprüfung, ändert nichts)
ansible.builtin.command: pve-firewall compile
check_mode: false
changed_when: false
- name: Totmannschalter stellen (Firewall nach {{ pve_firewall_deadman_seconds }} s wieder aus)
ansible.builtin.shell: |
systemctl stop knaster-fw-totmann.timer 2>/dev/null || true
systemd-run --on-active={{ pve_firewall_deadman_seconds }} --unit knaster-fw-totmann --description "knaster: Firewall-Rollback" sed -i 's/^enable: 1$/enable: 0/' /etc/pve/firewall/cluster.fw
when: cluster_fw is changed and knaster_pve.firewall.enable
changed_when: true
- name: Warten, bis alle Knoten das Regelwerk geladen haben
ansible.builtin.pause:
seconds: 15
when: cluster_fw is changed
- name: Prüfung von ops aus (SSH und 8006 zu jedem Knoten)
ansible.builtin.shell: |
set -euo pipefail
ssh -o BatchMode=yes -o ConnectTimeout=5 root@{{ hostvars[item].ansible_host }} 'pve-firewall status'
curl -sk -m 5 -o /dev/null -w '%{http_code}\n' https://{{ hostvars[item].ansible_host }}:8006/ | grep -q 200
args: {executable: /bin/bash}
loop: "{{ groups['pve_all'] | sort }}"
delegate_to: localhost
changed_when: false
when: cluster_fw is changed and knaster_pve.firewall.enable
- name: Totmannschalter aufheben (Prüfung bestanden)
ansible.builtin.command: systemctl stop knaster-fw-totmann.timer
when: cluster_fw is changed and knaster_pve.firewall.enable
changed_when: true