feat: Phase 5 — remove legacy service blocks, one-shot container cleanup
Unit Tests / test (push) Successful in 11m20s

Email, calendar, files, webmail (rainloop), and the file manager (filegator)
are removed from the main docker-compose stack. They install as independent
per-service compose projects via ServiceComposer.

On startup, _cleanup_legacy_builtin_containers() stops and removes any of the
5 legacy containers still running from the old main stack (guarded by a
one-shot sentinel in _meta.legacy_builtins_cleaned so it never runs twice).
Per-service installs (com.docker.compose.project != 'pic') are left untouched.

Changes:
- docker-compose.yml: remove mail, radicale, webdav, rainloop, filegator blocks;
  fix dhcp + ntp to profiles: ["core","full"] so they start with --profile core
- Makefile: replace all --profile full with --profile core (6 occurrences);
  remove mailserver.env conditional from update: target
- api/legacy_cleanup.py: new module with cleanup_legacy_builtin_containers()
- api/app.py: import and call cleanup at startup before reapply_on_startup()
- tests/test_legacy_cleanup.py: 7 tests covering sentinel, absent containers,
  per-service project skip, main-stack removal, exception safety

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-29 15:57:45 -04:00
parent a10fe11136
commit a69ca1e402
5 changed files with 166 additions and 123 deletions
+2 -113
View File
@@ -51,7 +51,7 @@ services:
dhcp:
image: alpine:latest
container_name: cell-dhcp
profiles: ["full"]
profiles: ["core", "full"]
ports:
- "${DHCP_PORT:-67}:67/udp"
volumes:
@@ -74,7 +74,7 @@ services:
ntp:
image: alpine:latest
container_name: cell-ntp
profiles: ["full"]
profiles: ["core", "full"]
ports:
- "${NTP_PORT:-123}:123/udp"
volumes:
@@ -92,79 +92,6 @@ services:
max-size: "10m"
max-file: "5"
# Email Server - Postfix + Dovecot
mail:
image: mailserver/docker-mailserver:latest
container_name: cell-mail
profiles: ["full"]
hostname: mail
domainname: cell.local
env_file: ./config/mail/mailserver.env
ports:
- "${MAIL_SMTP_PORT:-25}:25"
- "${MAIL_SUBMISSION_PORT:-587}:587"
- "${MAIL_IMAP_PORT:-993}:993"
volumes:
- ./data/maildata:/var/mail
- ./data/mailstate:/var/mail-state
- ./data/maillogs:/var/log/mail
- ./config/mail/config:/tmp/docker-mailserver/
- ./config/mail/ssl:/etc/letsencrypt
restart: unless-stopped
networks:
cell-network:
ipv4_address: ${MAIL_IP:-172.20.0.6}
cap_add:
- NET_ADMIN
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
# Calendar & Contacts - Radicale
radicale:
image: tomsquest/docker-radicale:latest
container_name: cell-radicale
profiles: ["full"]
ports:
- "127.0.0.1:${RADICALE_PORT:-5232}:5232"
volumes:
- ./config/radicale:/etc/radicale
- ./data/radicale:/data
restart: unless-stopped
networks:
cell-network:
ipv4_address: ${RADICALE_IP:-172.20.0.7}
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
# File Storage - WebDAV
webdav:
image: bytemark/webdav:latest
container_name: cell-webdav
profiles: ["full"]
ports:
- "127.0.0.1:${WEBDAV_PORT:-8080}:80"
environment:
- AUTH_TYPE=Basic
- USERNAME=${WEBDAV_USER:-admin}
- PASSWORD=${WEBDAV_PASS}
volumes:
- ./data/files:/var/lib/dav
restart: unless-stopped
networks:
cell-network:
ipv4_address: ${WEBDAV_IP:-172.20.0.8}
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
# WireGuard VPN
wireguard:
image: linuxserver/wireguard:latest
@@ -251,44 +178,6 @@ services:
max-size: "10m"
max-file: "5"
# Webmail - RainLoop
rainloop:
image: hardware/rainloop
container_name: cell-rainloop
profiles: ["full"]
restart: unless-stopped
networks:
cell-network:
ipv4_address: ${RAINLOOP_IP:-172.20.0.12}
ports:
- "127.0.0.1:${RAINLOOP_PORT:-8888}:8888"
volumes:
- ./data/rainloop:/rainloop/data
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
# File Manager - FileGator
filegator:
image: filegator/filegator
container_name: cell-filegator
profiles: ["full"]
restart: unless-stopped
networks:
cell-network:
ipv4_address: ${FILEGATOR_IP:-172.20.0.13}
ports:
- "127.0.0.1:${FILEGATOR_PORT:-8082}:8080"
volumes:
- ./data/filegator:/var/www/filegator/private
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
networks:
cell-network:
driver: bridge