mirror of
https://github.com/fscotto/infra.git
synced 2026-10-03 13:29:58 +00:00
Retire Prometheus Compose stack and document cleanup
This commit is contained in:
@@ -8,6 +8,8 @@ effective_user_home: "{{ server_user_home }}"
|
||||
server_container_stack_dir: /opt/docker/server
|
||||
server_npm_quadlet_stage: false
|
||||
server_npm_quadlet_cutover: false
|
||||
server_legacy_stack_retired: false
|
||||
server_legacy_cleanup: false
|
||||
ai_agents: {}
|
||||
vim_plugins_enabled: false
|
||||
|
||||
@@ -101,8 +103,9 @@ server_backup_export_source_keep: 3
|
||||
server_backup_export_paths: >-
|
||||
{{ ['opt/npm/data', 'opt/npm/letsencrypt']
|
||||
+ ([] if server_gitea_on_atlas | bool else ['opt/gitea/data', 'home/git/.ssh'])
|
||||
+ ['opt/docker/server/docker-compose.yml',
|
||||
'etc/systemd/system/podman-compose-server.service']
|
||||
+ ([] if server_legacy_stack_retired | bool else
|
||||
['opt/docker/server/docker-compose.yml',
|
||||
'etc/systemd/system/podman-compose-server.service'])
|
||||
+ (['etc/containers/systemd/prometheus-npm.container',
|
||||
'etc/containers/systemd/server-web.network']
|
||||
if server_npm_quadlet_stage | bool else [])
|
||||
|
||||
@@ -6,6 +6,15 @@ ansible_port: 22
|
||||
ansible_ssh_private_key_file: /home/fscotto/.ssh/id_ed25519
|
||||
|
||||
server_username: rocky
|
||||
server_legacy_stack_retired: true
|
||||
# Destructive deletion runs only with an explicit extra-var and cleanup tag.
|
||||
server_legacy_cleanup: false
|
||||
# Explicit opt-in cleanup; no data, volumes, networks or NPM images are removed.
|
||||
server_legacy_image_cleanup: false
|
||||
server_legacy_images:
|
||||
- docker.gitea.com/gitea:1.25.2
|
||||
- docker.io/deluan/navidrome:latest
|
||||
- docker.io/library/postgres:13
|
||||
server_npm_quadlet_stage: true
|
||||
server_npm_quadlet_image: docker.io/jc21/nginx-proxy-manager@sha256:52b2c59994f3d36acfcf70a1626f29734df0ed8c71bacc0269f78b6f939858bb
|
||||
# The stopped-source export and live Quadlet cutover passed on 2026-10-03.
|
||||
@@ -17,7 +26,6 @@ server_gitea_cutover_tools_enabled: true
|
||||
server_gitea_on_atlas: true
|
||||
server_gitea_npm_domains:
|
||||
- git.fscotto.duckdns.org
|
||||
- git.ov-ad3410.infomaniak.ch
|
||||
server_duckdns_domain: fscotto
|
||||
server_ssh_authorized_keys:
|
||||
- name: ikaros
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0750"
|
||||
validate: "bash -n %s"
|
||||
when: server_backup_export_enabled | bool
|
||||
|
||||
- name: Install Prometheus backup export systemd units
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0750"
|
||||
when: server_gitea_cutover_tools_enabled | bool
|
||||
when:
|
||||
- server_gitea_cutover_tools_enabled | bool
|
||||
- not server_legacy_stack_retired | bool
|
||||
|
||||
- name: Require the prepared source and explicit final-export approval
|
||||
tags: [services, gitea_final_export]
|
||||
@@ -15,6 +17,7 @@
|
||||
that:
|
||||
- server_gitea_cutover_tools_enabled | bool
|
||||
- server_backup_export_enabled | bool
|
||||
- not server_legacy_stack_retired | bool
|
||||
- not ansible_check_mode
|
||||
fail_msg: >-
|
||||
Install the cutover helper and perform an explicit non-check-mode run
|
||||
@@ -31,4 +34,5 @@
|
||||
no_log: true
|
||||
when:
|
||||
- server_gitea_final_export | bool
|
||||
- not server_legacy_stack_retired | bool
|
||||
- not ansible_check_mode
|
||||
|
||||
112
ansible/roles/profile_server/tasks/legacy_cleanup.yml
Normal file
112
ansible/roles/profile_server/tasks/legacy_cleanup.yml
Normal file
@@ -0,0 +1,112 @@
|
||||
---
|
||||
- name: Require explicit retirement of the migrated Prometheus source
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- inventory_hostname == 'prometheus'
|
||||
- server_legacy_stack_retired | bool
|
||||
- server_gitea_on_atlas | bool
|
||||
- server_npm_quadlet_cutover | bool
|
||||
- server_backup_export_enabled | bool
|
||||
|
||||
- name: Verify legacy paths have no mounts or container users
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- python3
|
||||
- -c
|
||||
- |
|
||||
import json, os, pathlib, subprocess
|
||||
def run(*args):
|
||||
return subprocess.check_output(args, text=True).strip()
|
||||
paths = ['/opt/gitea', '/home/git/.ssh', '/opt/navidrome',
|
||||
'/opt/postgres', '/opt/music', '/opt/containerd', '/opt/docker']
|
||||
mounts = json.loads(run('findmnt', '--json', '--list', '-o', 'TARGET'))['filesystems']
|
||||
for path in paths:
|
||||
assert os.path.realpath(path) == path, 'Symlink in cleanup path: ' + path
|
||||
for mount in mounts:
|
||||
target = mount['target']
|
||||
assert target != path and not target.startswith(path + '/'), 'Mounted cleanup path: ' + path
|
||||
ids = run('podman', 'ps', '-aq').split()
|
||||
containers = json.loads(run('podman', 'inspect', *ids)) if ids else []
|
||||
for container in containers:
|
||||
assert container['Name'].lstrip('/') == 'nginx-proxy-manager', 'Unexpected container; review before cleanup'
|
||||
for mount in container.get('Mounts', []):
|
||||
source = os.path.realpath(mount['Source'])
|
||||
for path in paths:
|
||||
assert source != path and not source.startswith(path + '/'), 'Container uses cleanup path: ' + path
|
||||
for path in ['/opt/music', '/opt/containerd']:
|
||||
if os.path.isdir(path):
|
||||
for entry in pathlib.Path(path).rglob('*'):
|
||||
assert entry.is_dir() and not entry.is_symlink(), 'Unexpected file in empty legacy path: ' + str(entry)
|
||||
if os.path.isdir('/opt/docker'):
|
||||
allowed = {'/opt/docker/server', '/opt/docker/server/docker-compose.yml'}
|
||||
for entry in pathlib.Path('/opt/docker').rglob('*'):
|
||||
assert str(entry) in allowed and not entry.is_symlink(), 'Unexpected legacy Docker content: ' + str(entry)
|
||||
assert run('systemctl', 'is-active', 'prometheus-npm.service') == 'active'
|
||||
assert subprocess.run(['systemctl', 'is-active', '--quiet', 'podman-compose-server.service']).returncode != 0
|
||||
assert subprocess.run(['systemctl', 'is-active', '--quiet', 'prometheus-backup-export.service']).returncode != 0
|
||||
print('Legacy cleanup preflight passed')
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
|
||||
- name: Require the updated backup configuration before deleting fallback files
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- python3
|
||||
- -c
|
||||
- |
|
||||
import pathlib, subprocess
|
||||
unit = subprocess.check_output(['systemctl', 'show', 'prometheus-backup-export.service',
|
||||
'-p', 'RequiresMountsFor', '--value'], text=True)
|
||||
assert '/opt/gitea' not in unit, 'Backup unit still depends on legacy Gitea'
|
||||
helper = pathlib.Path('/usr/local/sbin/prometheus-backup-export').read_text()
|
||||
assert 'podman-compose-server' not in helper and 'opt/docker/server' not in helper
|
||||
subprocess.run(['bash', '-n', '/usr/local/sbin/prometheus-backup-export'], check=True)
|
||||
changed_when: false
|
||||
when: not ansible_check_mode
|
||||
|
||||
- name: Delete only the explicitly approved legacy data and fallback files
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- /opt/gitea
|
||||
- /home/git/.ssh
|
||||
- /opt/navidrome
|
||||
- /opt/postgres
|
||||
- /opt/music
|
||||
- /opt/containerd
|
||||
- /opt/docker
|
||||
- /usr/local/sbin/prometheus-gitea-final-export
|
||||
- /etc/systemd/system/podman-compose-server.service
|
||||
register: server_legacy_deleted
|
||||
diff: false
|
||||
|
||||
- name: Reload systemd after removing the inactive legacy unit
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
when:
|
||||
- server_legacy_deleted is changed
|
||||
- not ansible_check_mode
|
||||
|
||||
- name: Inspect the obsolete Git home without following symlinks
|
||||
ansible.builtin.stat:
|
||||
path: /home/git
|
||||
follow: false
|
||||
register: server_legacy_git_home
|
||||
|
||||
- name: Require the obsolete Git account to be absent before removing its empty home
|
||||
ansible.builtin.command:
|
||||
argv: [getent, passwd, git]
|
||||
register: server_legacy_git_account
|
||||
changed_when: false
|
||||
failed_when: server_legacy_git_account.rc != 2
|
||||
check_mode: false
|
||||
when: server_legacy_git_home.stat.exists
|
||||
|
||||
# rmdir refuses any nonempty directory; never recursively delete this parent.
|
||||
- name: Remove only the empty obsolete Git home
|
||||
ansible.builtin.command:
|
||||
argv: [rmdir, /home/git]
|
||||
register: server_legacy_git_home_removed
|
||||
changed_when: server_legacy_git_home_removed.rc == 0
|
||||
when: server_legacy_git_home.stat.exists
|
||||
33
ansible/roles/profile_server/tasks/legacy_image_cleanup.yml
Normal file
33
ansible/roles/profile_server/tasks/legacy_image_cleanup.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
- name: Require the migrated Prometheus topology for image cleanup
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- inventory_hostname == 'prometheus'
|
||||
- server_gitea_on_atlas | bool
|
||||
- server_npm_quadlet_cutover | bool
|
||||
- server_legacy_images | default([]) | length > 0
|
||||
- >-
|
||||
server_legacy_images | difference([
|
||||
'docker.gitea.com/gitea:1.25.2',
|
||||
'docker.io/deluan/navidrome:latest',
|
||||
'docker.io/library/postgres:13']) | length == 0
|
||||
|
||||
- name: Check whether the explicitly selected legacy images exist
|
||||
ansible.builtin.command:
|
||||
argv: [podman, image, exists, "{{ item }}"]
|
||||
loop: "{{ server_legacy_images }}"
|
||||
register: server_legacy_image_presence
|
||||
changed_when: false
|
||||
failed_when: server_legacy_image_presence.rc not in [0, 1]
|
||||
check_mode: false
|
||||
|
||||
# No --force: Podman must refuse images referenced by any existing container.
|
||||
- name: Remove only unused explicitly selected legacy images
|
||||
ansible.builtin.command:
|
||||
argv: [podman, image, rm, "{{ item.item }}"]
|
||||
loop: "{{ server_legacy_image_presence.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item }}"
|
||||
when: item.rc == 0
|
||||
register: server_legacy_image_removal
|
||||
changed_when: server_legacy_image_removal.rc == 0
|
||||
@@ -23,6 +23,9 @@
|
||||
loop: "{{ server_directories | default([]) }}"
|
||||
loop_control:
|
||||
label: "{{ item.path }}"
|
||||
when:
|
||||
- item.path != '/opt/gitea/data' or not server_gitea_on_atlas | bool
|
||||
- item.path != server_container_stack_dir or not server_legacy_stack_retired | bool
|
||||
|
||||
- name: Copy server dotfiles
|
||||
tags: [dotfiles, dotfiles:server]
|
||||
@@ -48,19 +51,32 @@
|
||||
loop_control:
|
||||
label: "{{ item.dest }}"
|
||||
no_log: "{{ item.no_log | default(false) }}"
|
||||
when: item.src != 'server/docker-compose.yml.j2' or not server_legacy_stack_retired | bool
|
||||
|
||||
- name: Manage Podman Compose stack
|
||||
tags: [services, podman]
|
||||
ansible.builtin.include_tasks: podman-compose.yml
|
||||
when: not server_legacy_stack_retired | bool
|
||||
|
||||
- name: Import staged NPM Quadlet tasks
|
||||
ansible.builtin.import_tasks: npm_quadlet.yml
|
||||
|
||||
- name: Import explicit legacy server image cleanup
|
||||
ansible.builtin.import_tasks: legacy_image_cleanup.yml
|
||||
tags: [never, server_image_cleanup]
|
||||
when: server_legacy_image_cleanup | default(false) | bool
|
||||
|
||||
- name: Import Prometheus backup export identity tasks
|
||||
ansible.builtin.import_tasks: backup_export_identity.yml
|
||||
|
||||
- name: Import Prometheus backup export job tasks
|
||||
ansible.builtin.import_tasks: backup_export_job.yml
|
||||
tags: [server_legacy_cleanup]
|
||||
|
||||
- name: Import explicitly approved legacy server data cleanup
|
||||
ansible.builtin.import_tasks: legacy_cleanup.yml
|
||||
tags: [never, server_legacy_cleanup]
|
||||
when: server_legacy_cleanup | bool
|
||||
|
||||
- name: Import explicit Prometheus Gitea final-export tasks
|
||||
ansible.builtin.import_tasks: gitea_final_export.yml
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[Unit]
|
||||
Description=Prepare a read-only Prometheus application backup for Atlas
|
||||
RequiresMountsFor=/opt/npm /opt/gitea {{ server_backup_export_root }}
|
||||
RequiresMountsFor=/opt/npm {% if not server_gitea_on_atlas | bool %}/opt/gitea {% endif %}{{ server_backup_export_root }}
|
||||
ConditionFileIsExecutable=/usr/local/sbin/prometheus-backup-export
|
||||
|
||||
[Service]
|
||||
|
||||
@@ -4,6 +4,9 @@ umask 077
|
||||
|
||||
export_root={{ server_backup_export_root | quote }}
|
||||
versions="$export_root/versions"
|
||||
{% if server_legacy_stack_retired | bool %}
|
||||
stack_unit=prometheus-npm.service
|
||||
{% else %}
|
||||
stack_unit=''
|
||||
compose_active=false
|
||||
quadlet_active=false
|
||||
@@ -18,6 +21,7 @@ if "$quadlet_active"; then
|
||||
else
|
||||
stack_unit=podman-compose-server.service
|
||||
fi
|
||||
{% endif %}
|
||||
stamp=$(date -u +%Y%m%dT%H%M%SZ)
|
||||
stage=''
|
||||
stack_stopped=false
|
||||
|
||||
Reference in New Issue
Block a user