feat: adopt the ru-vps Caddy stack, fix cluster quorum, decommission ZeroTier
One ru-vps housekeeping sweep (2026-09-02/03): - playbooks/ru-vps-base.yml (new): adopt the Caddy compose stack into Ansible (pinned image by digest, homelab-caddy.service), and manage the corosync-qnetd UFW rule - allow 5403/tcp from homelab_pve_egress_ip, drop the stale rule for the retired ZeroTier 10.122.62.0/24. The qdevice had gone silent because its only allowed path was the decommissioned ZeroTier network. - group_vars/all/main.yml: homelab_pve_egress_ip (the NATed home egress the PVE nodes reach corosync-qnetd from - a direct path that does not depend on the OpenVPN tunnel). Marked dynamic: a change silently re-breaks the qdevice. - playbooks/status.yml: CLUSTER QUORUM section (pvecm status per PVE node) so a repeat failure is visible. Also drops the memoir-bot unit list and moves the gitea offsite-restic unit to the gitea host (see the OpenTofu-migration commit). - playbooks/ru-vps-zerotier-decommission.yml (new): stop the zerotier container, disable ssh-zt22.service, remove the interface/9993/9001/10.122.62.0/24 UFW rules. Node identity and data are kept; removal is a separate step. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012uoq5AVK8mkBgg83Mq6o5V
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
e24b75534e
commit
79878e36f9
@@ -26,7 +26,6 @@
|
||||
# grimmory{,-docker-firewall} playbooks/pve-grimmory.yml
|
||||
# gyro.timer roles/gyro (gyro.service is oneshot -> see jobs)
|
||||
# hermes-ai-tun-proxy.service playbooks/pve-hermes-ai.yml
|
||||
# memoir-bot.service playbooks/pve-memoir-bot.yml
|
||||
# mihomo{,-ui}.service playbooks/pve-mihomo.yml
|
||||
# uptime-kuma.service roles/uptime_kuma
|
||||
# vaultwarden.service playbooks/pve-vaultwarden.yml
|
||||
@@ -39,7 +38,6 @@
|
||||
grimmory: [docker.service, grimmory.service, grimmory-docker-firewall.service]
|
||||
gyro: [gyro.timer]
|
||||
hermes-ai: [docker.service, hermes-ai-tun-proxy.service]
|
||||
memoir-bot: [docker.service, memoir-bot.service]
|
||||
mihomo: [docker.service, mihomo.service, mihomo-ui.service]
|
||||
monitoring: [docker.service, uptime-kuma.service]
|
||||
ru-vps: [docker.service]
|
||||
@@ -51,8 +49,9 @@
|
||||
# Yandex Disk over the network, so we only read what systemd already knows.
|
||||
status_job_units:
|
||||
cloud-pc:
|
||||
- homelab-restic-offsite-gitea.service
|
||||
- homelab-backup-audit-gitea.service
|
||||
gitea:
|
||||
- homelab-restic-offsite-gitea.service
|
||||
grimmory:
|
||||
- homelab-restic-offsite-grimmory.service
|
||||
- homelab-backup-audit-grimmory.service
|
||||
@@ -136,6 +135,18 @@
|
||||
failed_when: false
|
||||
when: status_units | length > 0
|
||||
|
||||
# Двухнодовый кластер держится на арбитре corosync-qnetd (ru-vps:5403).
|
||||
# Когда арбитр молчит, Total votes < Expected votes и падение ЛЮБОЙ ноды
|
||||
# оставляет выжившую без кворума. Один раз это уже сломалось молча —
|
||||
# после вывода ZeroTier правило UFW для 5403 осталось на мёртвой сети.
|
||||
- name: Read cluster quorum state
|
||||
ansible.builtin.shell:
|
||||
cmd: LC_ALL=C pvecm status 2>/dev/null | grep -E 'Quorate:|Expected votes|Total votes' | tr -s ' ' | tr '\n' ' '
|
||||
register: status_quorum
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: inventory_hostname in (groups['pve_nodes'] | default([]))
|
||||
|
||||
- name: List failed systemd units
|
||||
ansible.builtin.shell:
|
||||
cmd: >-
|
||||
@@ -232,6 +243,7 @@
|
||||
if inventory_hostname in (groups['vpn_openvpn'] | default([])) else '-' }}
|
||||
vpn_peer_ip: "{{ openvpn_peer_ip | default('-') }}"
|
||||
vpn_probes: "{{ status_vpn_probe.stdout_lines | default([]) }}"
|
||||
quorum: "{{ status_quorum.stdout | default('') | trim }}"
|
||||
|
||||
|
||||
- name: Print HomeLab status summary
|
||||
@@ -331,6 +343,19 @@
|
||||
loop: "{{ status_hosts }}"
|
||||
when: hostvars[item].status_record.vpn_peer != '-'
|
||||
|
||||
- name: Add cluster quorum section header
|
||||
ansible.builtin.set_fact:
|
||||
status_report: >-
|
||||
{{ status_report + ['', 'CLUSTER QUORUM (qdevice = третий голос)', '-' * 80] }}
|
||||
|
||||
- name: Add quorum line per PVE node
|
||||
ansible.builtin.set_fact:
|
||||
status_report: >-
|
||||
{{ status_report + [' ' ~ item ~ ': '
|
||||
~ (hostvars[item].status_record.quorum | default('') | trim | default('нет данных', true))] }}
|
||||
loop: "{{ status_hosts }}"
|
||||
when: hostvars[item].status_record.quorum | default('') | length > 0
|
||||
|
||||
- name: Add backup and job section header
|
||||
ansible.builtin.set_fact:
|
||||
status_report: >-
|
||||
|
||||
Reference in New Issue
Block a user