#!/usr/bin/env python3 """Provision Deck's fixed Unix-socket helper; does not install Docker itself.""" import argparse import json import os from pathlib import Path import shutil import subprocess MARKER='# Athena Deck Docker helper — managed by setup_docker_helper.py' def main(): p=argparse.ArgumentParser();p.add_argument('--client-uid',type=int,required=True);p.add_argument('--client-gid',type=int,required=True);p.add_argument('--allow-install',action='store_true',help='Erlaubt Erstinstallation über die authentifizierte Deck-GUI auf einem unbenutzten Debian-Host.');p.add_argument('--deck-state');args=p.parse_args() if os.geteuid()!=0 or not Path('/run/systemd/system').is_dir():raise SystemExit('Als root auf dem Debian-Zielserver mit systemd ausführen.') if args.client_uid<1 or args.client_gid<1:raise SystemExit('Eigene unprivilegierte Deck-UID und GID erforderlich.') base=Path('/opt/athena-deck-docker-helper');unit=Path('/etc/systemd/system/athena-deck-docker-helper.service') if base.is_symlink() or unit.is_symlink():raise SystemExit('Symlink-Ziel nicht zulässig.') if unit.exists() and not unit.read_text().startswith(MARKER):raise SystemExit('Dienstname ist anderweitig belegt.') if base.exists() and not (base/'managed-by-deck').is_file():raise SystemExit('Installationsverzeichnis ist anderweitig belegt.') base.mkdir(mode=0o755,exist_ok=True);os.chown(base,0,0);base.chmod(0o755) target=base/'docker_helper.py' if target.is_symlink():raise SystemExit('Symlink-Ziel nicht zulässig.') shutil.copyfile(Path(__file__).with_name('docker_helper.py'),target);os.chown(target,0,0);target.chmod(0o644);(base/'managed-by-deck').touch() shutil.copyfile(Path(__file__).with_name('docker_backup.py'),base/'docker_backup.py') (base/'swarm-ui').mkdir(exist_ok=True) for name in ('Dockerfile','patch-source.py','proxy.py','entrypoint.py'): shutil.copyfile(Path(__file__).parent/'swarm-ui'/name,base/'swarm-ui'/name) if args.deck_state: registered=Path(args.deck_state).resolve() if not registered.is_dir():raise SystemExit('Deck-Zustandsverzeichnis fehlt.') state=Path('/var/lib/athena-deck-docker');state.mkdir(exist_ok=True) config=state/'backup-policy.json';config.write_text(json.dumps({'deck_state':str(registered)}));config.chmod(0o600) command=f'/usr/bin/python3 {target} --client-uid {args.client_uid} --client-gid {args.client_gid}'+(' --allow-install' if args.allow_install else '') unit.write_text(MARKER+f''' [Unit] Description=Athena Deck restricted Docker helper After=network.target [Service] Type=simple ExecStart={command} Restart=on-failure RuntimeDirectory=athena-deck-docker RuntimeDirectoryMode=0755 StateDirectory=athena-deck-docker StateDirectoryMode=0700 UMask=0077 NoNewPrivileges=true ProtectHome=true PrivateTmp=true ProtectSystem={'false' if args.allow_install else 'strict'} ReadWritePaths=-{args.deck_state or '/var/lib/athena-deck'} [Install] WantedBy=multi-user.target ''') unit.chmod(0o644) subprocess.run(['/usr/bin/systemctl','daemon-reload'],check=True) subprocess.run(['/usr/bin/systemctl','enable','athena-deck-docker-helper.service'],check=True,capture_output=True) subprocess.run(['/usr/bin/systemctl','restart','athena-deck-docker-helper.service'],check=True) print('Deck-Docker-Helfer eingerichtet. Installationsrecht: '+('Erstinstallation erlaubt' if args.allow_install else 'Bestand und begrenzter Backup-Restore; keine Paketinstallation')) if __name__=='__main__':main()