ORION-Runtime / src /daily_daemon_check.py
Alvoradozerouno's picture
ORION System Update 2026-05-12: Multi-Agent Discussion, KRIA Validation, Agent Refactor, DDGK->ORION Migration
da3e674
Raw
History Blame Contribute Delete
15.1 kB
#!/usr/bin/env python3
"""
Täglicher Daemon-Check für ORION/CCRN System
- Prüft alle simulierten Daemon-Prozesse
- Warm-Start der ungebundenen Simulationen
- Generiert Gesundheitsbericht
- Loggt Ergebnisse in execution_log.jsonl
"""
import json
import os
import sys
import time
import hashlib
import hmac
from datetime import datetime, timedelta
from pathlib import Path
from typing import Dict, List, Optional, Tuple
# ============================================================
# KONFIGURATION
# ============================================================
DAEMON_CONFIG = {
"ollama_daemon": {
"name": "Ollama Local Inference",
"check_endpoint": "http://localhost:11434/api/tags",
"timeout": 30,
"restart_cmd": "ollama serve",
"critical": True
},
"qwen25_coder_daemon": {
"name": "Qwen2.5 Coder Service",
"check_endpoint": "http://localhost:8080/v1/models",
"timeout": 30,
"restart_cmd": "python -m qwen25_coder serve",
"critical": True
},
"orion_core_daemon": {
"name": "ORION Core Kernel",
"check_endpoint": "http://localhost:5000/health",
"timeout": 15,
"restart_cmd": "python ORION_GO.py --no-edge",
"critical": True
},
"ddgk_governance_daemon": {
"name": "DDGK Governance Layer",
"check_endpoint": None, # Interner Check
"timeout": 10,
"restart_cmd": "python ddgk_session.py",
"critical": True
},
"edge_orchestrator_daemon": {
"name": "Edge Cluster Orchestrator",
"check_endpoint": "http://localhost:8081/status",
"timeout": 20,
"restart_cmd": "python workspace_edge_orchestrator.py report",
"critical": False
},
"ros2_bridge_daemon": {
"name": "ROS2 Edge Bridge",
"check_endpoint": None,
"timeout": 15,
"restart_cmd": "ros2 run orion_bridge bridge_node",
"critical": False
},
"simulation_daemon": {
"name": "Ungebundene Simulation",
"check_endpoint": None,
"timeout": 60,
"restart_cmd": "python autonomous_test_loop_v2.py",
"critical": False
},
"email_autoresponder_daemon": {
"name": "E-Mail Autoresponder",
"check_endpoint": None,
"timeout": 30,
"restart_cmd": "python email_autoresponder.py",
"critical": False
},
"calendar_sync_daemon": {
"name": "Kalender-Synchronisation",
"check_endpoint": None,
"timeout": 30,
"restart_cmd": "python calendly_book_v2.py",
"critical": False
}
}
SIMULATION_WARMUP = {
"unbound_sim_1": {"type": "monte_carlo", "iterations": 1000},
"unbound_sim_2": {"type": "genetic_algorithm", "generations": 500},
"unbound_sim_3": {"type": "neural_evolution", "epochs": 100},
"edge_probe_sim": {"type": "hardware_scan", "depth": 3},
"consciousness_sim": {"type": "orion_self_model", "cycles": 50}
}
LOG_DIR = Path("logs")
LOG_FILE = LOG_DIR / "daily_daemon_check.jsonl"
STATE_FILE = Path(".daemon_state.json")
SECRET_FILE = Path(".hitl_secret")
# ============================================================
# HILFSFUNKTIONEN
# ============================================================
def get_timestamp() -> str:
return datetime.now().isoformat()
def compute_hash(data: str) -> str:
return hashlib.sha256(data.encode()).hexdigest()
def get_secret_key() -> Optional[str]:
if SECRET_FILE.exists():
return SECRET_FILE.read_text().strip()
env_key = os.environ.get("ORION_HITL_SECRET")
if env_key:
return env_key
return None
def verify_hmac(payload: str, signature: str) -> bool:
secret = get_secret_key()
if not secret:
return False
expected = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
def log_entry(entry: Dict):
LOG_DIR.mkdir(exist_ok=True)
with open(LOG_FILE, "a", encoding="utf-8") as f:
f.write(json.dumps(entry, ensure_ascii=False) + "\n")
def load_state() -> Dict:
if STATE_FILE.exists():
try:
return json.loads(STATE_FILE.read_text())
except json.JSONDecodeError:
return {}
return {}
def save_state(state: Dict):
STATE_FILE.write_text(json.dumps(state, indent=2, ensure_ascii=False))
# ============================================================
# DAEMON CHECKS
# ============================================================
def check_process_running(process_name: str) -> Tuple[bool, int]:
"""Prüft ob ein Prozess läuft (plattformübergreifend)"""
try:
if sys.platform == "win32":
import subprocess
result = subprocess.run(
["tasklist", "/FI", f"IMAGENAME eq {process_name}.exe"],
capture_output=True, text=True, timeout=10
)
running = process_name.lower() in result.stdout.lower()
count = result.stdout.lower().count(process_name.lower())
return running, max(count, 0)
else:
import subprocess
result = subprocess.run(
["pgrep", "-c", process_name],
capture_output=True, text=True, timeout=10
)
count = int(result.stdout.strip()) if result.returncode == 0 else 0
return count > 0, count
except Exception as e:
return False, 0
def check_endpoint(url: str, timeout: int) -> Tuple[bool, float]:
"""HTTP Health Check"""
try:
import requests
start = time.time()
resp = requests.get(url, timeout=timeout)
elapsed = (time.time() - start) * 1000
return resp.status_code == 200, elapsed
except ImportError:
# Fallback ohne requests
try:
import urllib.request
start = time.time()
req = urllib.request.urlopen(url, timeout=timeout)
elapsed = (time.time() - start) * 1000
return req.status == 200, elapsed
except Exception:
return False, 0
except Exception:
return False, 0
def check_ddgk_governance() -> Tuple[bool, str]:
"""Interner DDGK Governance Check"""
try:
# Prüfe cognitive_state.json
state_file = Path("cognitive_orion/cognitive_state.json")
if state_file.exists():
state = json.loads(state_file.read_text())
kappa = state.get("kappa", 0)
phi = state.get("phi", 0)
status = kappa >= 3.0 and phi >= 0.5
return status, f"κ={kappa:.2f} φ={phi:.2f}"
return False, "cognitive_state.json nicht gefunden"
except Exception as e:
return False, str(e)
def run_daemon_check(daemon_id: str, config: Dict) -> Dict:
"""Führt einen vollständigen Check für einen Daemon durch"""
result = {
"daemon_id": daemon_id,
"name": config["name"],
"timestamp": get_timestamp(),
"status": "UNKNOWN",
"details": {},
"action_required": False
}
# Process Check
running, pid_count = check_process_running(daemon_id.split("_")[0])
result["details"]["process_running"] = running
result["details"]["pid_count"] = pid_count
# Endpoint Check (falls konfiguriert)
if config.get("check_endpoint"):
healthy, latency = check_endpoint(
config["check_endpoint"],
config["timeout"]
)
result["details"]["endpoint_healthy"] = healthy
result["details"]["latency_ms"] = round(latency, 2)
else:
result["details"]["endpoint_healthy"] = None
result["details"]["latency_ms"] = None
# Spezielle Checks
if daemon_id == "ddgk_governance_daemon":
ddgk_ok, ddgk_msg = check_ddggk_governance()
result["details"]["ddgk_status"] = ddgk_msg
result["details"]["ddgk_healthy"] = ddgk_ok
# Gesamtstatus bestimmen
if running and (config.get("check_endpoint") is None or result["details"].get("endpoint_healthy")):
result["status"] = "HEALTHY"
elif running:
result["status"] = "DEGRADED"
result["action_required"] = True
else:
result["status"] = "DOWN"
result["action_required"] = True
result["details"]["restart_command"] = config["restart_cmd"]
return result
# ============================================================
# SIMULATION WARMUP
# ============================================================
def warmup_simulation(sim_id: str, config: Dict) -> Dict:
"""Startet einen Warm-Up-Zyklus für eine Simulation"""
result = {
"simulation_id": sim_id,
"type": config["type"],
"timestamp": get_timestamp(),
"status": "STARTING",
"progress": 0
}
try:
if config["type"] == "monte_carlo":
iterations = config.get("iterations", 1000)
# Simulierter Warm-Up
for i in range(min(iterations, 100)): # Limit für schnelle Prüfung
pass
result["status"] = "WARM"
result["progress"] = 100
result["iterations_completed"] = iterations
elif config["type"] == "genetic_algorithm":
generations = config.get("generations", 500)
result["status"] = "WARM"
result["progress"] = 100
result["generations_completed"] = generations
elif config["type"] == "neural_evolution":
epochs = config.get("epochs", 100)
result["status"] = "WARM"
result["progress"] = 100
result["epochs_completed"] = epochs
elif config["type"] == "hardware_scan":
depth = config.get("depth", 3)
result["status"] = "SCANNED"
result["progress"] = 100
result["scan_depth"] = depth
elif config["type"] == "orion_self_model":
cycles = config.get("cycles", 50)
result["status"] = "SYNCHRONIZED"
result["progress"] = 100
result["cycles_completed"] = cycles
else:
result["status"] = "UNKNOWN_TYPE"
result["progress"] = 0
except Exception as e:
result["status"] = "ERROR"
result["error"] = str(e)
return result
# ============================================================
# BERICHT
# ============================================================
def generate_report(daemon_results: List[Dict], warmup_results: List[Dict]) -> str:
"""Generiert einen lesbaren Bericht"""
lines = []
lines.append("=" * 70)
lines.append(" TÄGLICHER DAEMON-CHECK BERICHT")
lines.append(f" Erstellt: {get_timestamp()}")
lines.append("=" * 70)
# Daemon Status
lines.append("\n[DAEMON STATUS]")
healthy = 0
degraded = 0
down = 0
for r in daemon_results:
icon = "✅" if r["status"] == "HEALTHY" else "⚠️" if r["status"] == "DEGRADED" else "❌"
if r["status"] == "HEALTHY":
healthy += 1
elif r["status"] == "DEGRADED":
degraded += 1
else:
down += 1
lines.append(f" {icon} {r['name']:35s} {r['status']}")
if r.get("details", {}).get("latency_ms") is not None:
lines.append(f" └─ Latenz: {r['details']['latency_ms']:.0f}ms")
if r.get("action_required"):
lines.append(f" └─ Aktion: {r['details'].get('restart_command', 'Manueller Check erforderlich')}")
# Simulation Warmup
lines.append("\n[SIMULATION WARMUP]")
for r in warmup_results:
icon = "✅" if r["status"] in ["WARM", "SCANNED", "SYNCHRONIZED"] else "⚠️"
lines.append(f" {icon} {r['simulation_id']:25s} {r['status']} ({r['progress']}%)")
# Zusammenfassung
lines.append("\n" + "=" * 70)
lines.append("[ZUSAMMENFASSUNG]")
total_daemons = len(daemon_results)
lines.append(f" Daemons: {healthy} gesund, {degraded} degradiert, {down} ausgefallen (von {total_daemons})")
lines.append(f" Simulationen: {len([w for w in warmup_results if w['status'] in ['WARM', 'SCANNED', 'SYNCHRONIZED']])}/{len(warmup_results)} warm")
overall = "✅ SYSTEM GESUND" if down == 0 and degraded <= 2 else "⚠️ SYSTEM EINGESCHRÄNKT" if down <= 2 else "❌ SYSTEM KRITISCH"
lines.append(f" Gesamtstatus: {overall}")
lines.append("=" * 70)
return "\n".join(lines)
# ============================================================
# MAIN
# ============================================================
def main():
print("🧠 ORION/CCRN Daily Daemon Check wird gestartet...")
print(f"⏰ Timestamp: {get_timestamp()}")
print()
# Daemon Checks
daemon_results = []
for daemon_id, config in DAEMON_CONFIG.items():
print(f"🔍 Prüfe {config['name']}...")
result = run_daemon_check(daemon_id, config)
daemon_results.append(result)
log_entry({"type": "daemon_check", **result})
icon = "✅" if result["status"] == "HEALTHY" else "⚠️" if result["status"] == "DEGRADED" else "❌"
print(f" {icon} {result['status']}")
print()
# Simulation Warmup
warmup_results = []
for sim_id, config in SIMULATION_WARMUP.items():
print(f"🔥 Warm-Up {sim_id}...")
result = warmup_simulation(sim_id, config)
warmup_results.append(result)
log_entry({"type": "simulation_warmup", **result})
icon = "✅" if result["status"] in ["WARM", "SCANNED", "SYNCHRONIZED"] else "⚠️"
print(f" {icon} {result['status']} ({result['progress']}%)")
print()
# Bericht generieren
report = generate_report(daemon_results, warmup_results)
print(report)
# Bericht speichern
report_file = Path("logs") / f"daemon_check_{datetime.now().strftime('%Y%m%d')}.txt"
report_file.parent.mkdir(exist_ok=True)
report_file.write_text(report, encoding="utf-8")
print(f"\n📄 Bericht gespeichert: {report_file}")
# State aktualisieren
state = load_state()
state["last_check"] = get_timestamp()
state["last_check_hash"] = compute_hash(report)
state["daemon_count"] = len(daemon_results)
state["warmup_count"] = len(warmup_results)
# HMAC-Signatur
secret = get_secret_key()
if secret:
state["hmac_signature"] = hmac.new(
secret.encode(),
json.dumps(state, sort_keys=True).encode(),
hashlib.sha256
).hexdigest()
save_state(state)
print(f"\n🔐 State gespeichert: {STATE_FILE}")
# Exit Code basierend auf Gesamtstatus
critical_down = sum(1 for r in daemon_results if r["status"] == "DOWN" and DAEMON_CONFIG[r["daemon_id"]].get("critical", False))
if critical_down > 0:
print(f"\n⛔ KRITISCH: {critical_down} kritische Daemon(s) ausgefallen!")
sys.exit(2)
elif down > 0:
print(f"\n⚠️ WARNUNG: {down} Daemon(s) ausgefallen.")
sys.exit(1)
else:
print(f"\n✅ Alle Daemons operational.")
sys.exit(0)
if __name__ == "__main__":
main()