ci / test (push) Failing after 22s
main (bis 13.10.) enthielt eine parallele Fassung von Task 0.4 (c81e372) sowie
KNOW-Befunde und die Ontologie. Konflikte zugunsten des Plan-Branches gelöst
(ausgerollter Stand); übernommen aus main: Ontologie (core/src/knaster/ontology,
ontology/, Tests, Router-Image), KNOW-Doku, cpu_roles im Placement samt
Kennzeichnung von pve61 und gode-pc-05/06 im Inventar und Test.
infra-stack kopiert jetzt auch ontology/ nach infra (Router-Build braucht es).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
184 lines
6.6 KiB
YAML
184 lines
6.6 KiB
YAML
# Compose-Stack infra: Router, TTS, Postgres, Prometheus, Alertmanager, Grafana, pve-exporter, node-exporter.
|
||
# Idempotent: Geheimnisse nur anlegen, wenn sie fehlen; compose up ändert nur, was sich geändert hat.
|
||
- name: Werkzeuge
|
||
ansible.builtin.apt:
|
||
name: [rsync, openssl, curl]
|
||
state: present
|
||
update_cache: true
|
||
cache_valid_time: 3600
|
||
|
||
- name: Verzeichnisse
|
||
ansible.builtin.file:
|
||
path: "{{ item.path }}"
|
||
state: directory
|
||
mode: "{{ item.mode }}"
|
||
loop:
|
||
- {path: /opt/knaster, mode: "0755"}
|
||
- {path: "{{ infra_repo_dir }}", mode: "0755"}
|
||
- {path: "{{ infra_state_dir }}", mode: "0700"}
|
||
- {path: "{{ infra_state_dir }}/secrets", mode: "0700"}
|
||
- {path: "{{ infra_state_dir }}/secrets/k3s", mode: "0755"}
|
||
|
||
# Nur die Teile, die Build und Konfiguration brauchen. Nie .git, .venv, tofu-State oder .env-Dateien.
|
||
- name: Repo-Auszug von ops abgleichen
|
||
ansible.posix.synchronize:
|
||
src: "{{ infra_repo_src }}/"
|
||
dest: "{{ infra_repo_dir }}/"
|
||
delete: true
|
||
rsync_opts:
|
||
# Der Clone auf ops ist teils 0600/0700; Container-Benutzer (nobody, grafana, knaster) müssen lesen können
|
||
- "--chmod=go+rX,go-w"
|
||
- "--exclude=__pycache__"
|
||
- "--exclude=.pytest_cache"
|
||
- "--exclude=*.egg-info"
|
||
- "--exclude=.env"
|
||
- "--exclude=secrets/"
|
||
- "--include=/core/***"
|
||
- "--include=/config/***"
|
||
- "--include=/catalog/***"
|
||
- "--include=/skills/***"
|
||
- "--include=/ontology/***" # Router-Image kopiert ontology/ (KNASTER_ONTOLOGY)
|
||
- "--include=/sites/***"
|
||
- "--include=/deploy/***"
|
||
- "--exclude=*"
|
||
|
||
- name: Einstellungen in .env
|
||
ansible.builtin.lineinfile:
|
||
path: "{{ infra_state_dir }}/.env"
|
||
regexp: "^{{ item.key }}="
|
||
line: "{{ item.key }}={{ item.value }}"
|
||
create: true
|
||
mode: "0600"
|
||
loop: "{{ infra_settings | dict2items }}"
|
||
|
||
# Gibt nur Namen aus, nie Werte
|
||
- name: Fehlende Geheimnisse im Container erzeugen
|
||
ansible.builtin.shell: |
|
||
set -eu
|
||
umask 077
|
||
f={{ infra_state_dir }}/.env
|
||
for k in {{ infra_secrets | join(' ') }}; do
|
||
grep -q "^$k=" "$f" || { echo "$k=$(openssl rand -hex 24)" >> "$f"; echo "neu: $k"; }
|
||
done
|
||
chmod 0600 "$f"
|
||
args:
|
||
executable: /bin/bash
|
||
register: secrets_gen
|
||
changed_when: "'neu:' in secrets_gen.stdout"
|
||
|
||
- name: Router-Token für Alertmanager (= KNASTER_API_TOKEN, lesbar für nobody im Container)
|
||
ansible.builtin.shell: |
|
||
set -eu
|
||
umask 077
|
||
cd {{ infra_state_dir }}
|
||
v=$(sed -n 's/^KNASTER_API_TOKEN=//p' .env)
|
||
t=secrets/router_token
|
||
if [ ! -f "$t" ] || [ "$(cat "$t")" != "$v" ]; then printf '%s' "$v" > "$t"; echo geändert; fi
|
||
chown 65534:65534 "$t"
|
||
chmod 0400 "$t"
|
||
args:
|
||
executable: /bin/bash
|
||
register: router_token
|
||
changed_when: "'geändert' in router_token.stdout"
|
||
no_log: true
|
||
|
||
- name: Proxmox-Lese-Token für den pve-exporter
|
||
ansible.builtin.copy:
|
||
src: "{{ infra_pve_exporter_env }}"
|
||
dest: "{{ infra_state_dir }}/secrets/pve-exporter.env"
|
||
mode: "0600"
|
||
no_log: true
|
||
|
||
# Task 6.5: Token des ServiceAccounts prometheus-infra und CA des Clusters (von playbooks/monitoring-k3s.yml
|
||
# auf ops abgelegt). Lesbar für nobody (Prometheus im Container). Fehlen sie, bleiben die k3s-Jobs down.
|
||
- name: k3s-Zugang für Prometheus vorhanden? (auf ops)
|
||
ansible.builtin.stat:
|
||
path: "{{ item }}"
|
||
loop: ["{{ infra_k3s_token }}", "{{ infra_k3s_ca }}"]
|
||
delegate_to: localhost
|
||
register: k3s_access
|
||
|
||
- name: k3s-Zugang für Prometheus kopieren
|
||
ansible.builtin.copy:
|
||
src: "{{ item.src }}"
|
||
dest: "{{ infra_state_dir }}/secrets/k3s/{{ item.dest }}"
|
||
owner: "65534"
|
||
group: "65534"
|
||
mode: "0400"
|
||
loop:
|
||
- {src: "{{ infra_k3s_token }}", dest: token}
|
||
- {src: "{{ infra_k3s_ca }}", dest: ca.crt}
|
||
loop_control:
|
||
label: "{{ item.dest }}"
|
||
when: k3s_access.results | map(attribute='stat.exists') | min
|
||
no_log: true
|
||
|
||
- name: file_sd-Ziele
|
||
ansible.builtin.include_tasks: targets.yml
|
||
|
||
# HA-Umzug: Nach zfs receive liefert der Zielknoten für früher gemappte Dateien veralteten Seiten-Cache
|
||
# (12.10.2026 belegt). Vor jedem Docker-Start den Cache dieses Containers verwerfen. BETRIEB.md Abschnitt 7.
|
||
- name: Schutz gegen veralteten Seiten-Cache – Skript
|
||
ansible.builtin.copy:
|
||
src: knaster-drop-stale-cache.py
|
||
dest: /usr/local/sbin/knaster-drop-stale-cache
|
||
mode: "0755"
|
||
|
||
- name: Schutz gegen veralteten Seiten-Cache – systemd-Dienst vor containerd/docker
|
||
ansible.builtin.copy:
|
||
src: knaster-drop-stale-cache.service
|
||
dest: /etc/systemd/system/knaster-drop-stale-cache.service
|
||
mode: "0644"
|
||
register: dropcache_unit
|
||
|
||
- name: Schutz gegen veralteten Seiten-Cache – aktivieren
|
||
ansible.builtin.systemd:
|
||
name: knaster-drop-stale-cache.service
|
||
enabled: true
|
||
daemon_reload: "{{ dropcache_unit.changed }}"
|
||
|
||
- name: Stack bauen und starten
|
||
ansible.builtin.command: >
|
||
docker compose -p {{ infra_compose_project }} --env-file {{ infra_state_dir }}/.env
|
||
-f {{ infra_compose_file }} up -d --build --remove-orphans
|
||
register: compose_up
|
||
changed_when: compose_up.stderr is search('Container \S+\s+(Created|Recreated|Started)')
|
||
|
||
- name: Prometheus und Alertmanager laden geänderte Konfiguration (bind-mount, kein Neustart nötig)
|
||
ansible.builtin.command: "curl -fsS -m 10 -X POST http://127.0.0.1:{{ item }}/-/reload"
|
||
loop: [9090, 9093]
|
||
register: reload
|
||
retries: 15
|
||
delay: 4
|
||
until: reload.rc == 0
|
||
changed_when: false
|
||
|
||
- name: Grafana-Konto kiosk (Viewer) anlegen, Passwort aus .env
|
||
ansible.builtin.shell: |
|
||
set -eu
|
||
cd {{ infra_state_dir }}
|
||
A=$(sed -n 's/^GRAFANA_ADMIN_PASSWORD=//p' .env)
|
||
K=$(sed -n 's/^GRAFANA_KIOSK_PASSWORD=//p' .env)
|
||
umask 077
|
||
cfg=$(mktemp)
|
||
trap 'rm -f "$cfg"' EXIT
|
||
printf 'user = "admin:%s"\n' "$A" > "$cfg" # Passwort nicht in der Prozessliste
|
||
g() { curl -sS -K "$cfg" -H 'Content-Type: application/json' "$@"; }
|
||
for i in $(seq 60); do curl -fsS -m 3 http://127.0.0.1:3000/api/health >/dev/null 2>&1 && break; sleep 2; done
|
||
code=$(g -o /dev/null -w '%{http_code}' 'http://127.0.0.1:3000/api/users/lookup?loginOrEmail=kiosk')
|
||
if [ "$code" = 404 ]; then
|
||
printf '{"name":"Kiosk","login":"kiosk","password":"%s"}' "$K" \
|
||
| g -f -X POST --data @- http://127.0.0.1:3000/api/admin/users >/dev/null
|
||
echo angelegt
|
||
elif [ "$code" != 200 ]; then
|
||
echo "Grafana-API antwortet $code" >&2
|
||
exit 1
|
||
fi
|
||
id=$(g -f 'http://127.0.0.1:3000/api/users/lookup?loginOrEmail=kiosk' | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')
|
||
g -f -X PATCH --data '{"role":"Viewer"}' "http://127.0.0.1:3000/api/org/users/$id" >/dev/null
|
||
args:
|
||
executable: /bin/bash
|
||
register: kiosk
|
||
changed_when: "'angelegt' in kiosk.stdout"
|
||
no_log: true
|