189 lines
7.7 KiB
YAML
189 lines
7.7 KiB
YAML
- 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 (Benutzer fehlt im Probelauf noch)
|
||
ansible.builtin.command: pveum user token list {{ pve_healer_user }} --output-format json
|
||
register: healer_tokens
|
||
check_mode: false
|
||
changed_when: false
|
||
failed_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 or '[]') | 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
|
||
unsafe_writes: true # pmxcfs: kein chmod, kein atomares Umbenennen
|
||
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
|