v0.5.0 – Clownfischserver HomeIP Auto-Update: myfritz Automatik für SSH (5-Min Cron)

Features:
- install.sh: Frage in Step 4 ob myfritz-Adresse für Auto-SSH-Freigabe genutzt werden soll
- clownfischserver-homeip-updater.sh: DNS-Auflösung + UFW-Update (alle 5 Min via Cron)
- .env-Variable: CLOWNFISCHSERVER_HOME_IP_DOMAIN für myfritz-Adresse
- State-File tracking zur Vermeidung unnötiger UFW-Updates
- Logging: /var/log/clownfischserver-homeip.log
- Dokumentation: scripts/README-HOMEIP.md + CLOWNFISCHSERVER.md update

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-05-01 23:28:36 +02:00
co-authored by Claude Haiku 4.5
commit eff7d0d98b
23 changed files with 4143 additions and 0 deletions
+85
View File
@@ -0,0 +1,85 @@
#!/usr/bin/env python3
"""
🐠 Clownfischserver
Author: Mehlzoerwer-Claude (https://github.com/mehlzoerwer-claude)
License: GPL-3.0 – Keep it open. Always.
Repo: https://github.com/mehlzoerwer-claude/clownfischserver
"""
import asyncio
import logging
import os
import shlex
logger = logging.getLogger(__name__)
MGMT_USER = os.getenv("MGMT_USER", "clownfish")
COMMAND_TIMEOUT = 120 # seconds
async def run_shell(command: str) -> tuple[str, str, int]:
"""Run a shell command as mgmt user, return (stdout, stderr, returncode)"""
try:
current_user = os.getenv("USER", "")
if current_user != MGMT_USER:
full_cmd = f"sudo -u {MGMT_USER} bash -c {shlex.quote(command)}"
else:
full_cmd = command
process = await asyncio.create_subprocess_shell(
full_cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
env={**os.environ, "HOME": f"/home/{MGMT_USER}"}
)
try:
stdout, stderr = await asyncio.wait_for(
process.communicate(),
timeout=COMMAND_TIMEOUT
)
except asyncio.TimeoutError:
process.kill()
return "", f"Timeout nach {COMMAND_TIMEOUT}s", 1
return (
stdout.decode("utf-8", errors="replace").strip(),
stderr.decode("utf-8", errors="replace").strip(),
process.returncode
)
except Exception as e:
logger.error(f"Shell execution error: {e}")
return "", str(e), 1
async def execute_command(shell_cmd: str, ollama_client) -> str:
"""
Execute a pre-determined shell command and return formatted output.
Optionally asks Ollama to explain errors or complex output.
"""
logger.info(f"Executing: {shell_cmd}")
stdout, stderr, returncode = await run_shell(shell_cmd)
# Build response
response_parts = [f"$ {shell_cmd}"]
if stdout:
response_parts.append(stdout)
if stderr and returncode != 0:
response_parts.append(f"[STDERR]\n{stderr}")
if returncode != 0:
response_parts.append(f"[Exit code: {returncode}]")
raw_output = "\n".join(response_parts)
# If there's an error or output is complex, ask Ollama to explain
if returncode != 0 or len(stdout) > 500:
explanation = await ollama_client.explain_output(shell_cmd, stdout, stderr)
if explanation:
raw_output += f"\n\n💡 {explanation}"
return raw_output or "✓ Ausgeführt (keine Ausgabe)"