initial: import DOLPHIN baseline 2026-04-21 from dolphinng5_predict working tree
Includes core prod + GREEN/BLUE subsystems: - prod/ (BLUE harness, configs, scripts, docs) - nautilus_dolphin/ (GREEN Nautilus-native impl + dvae/ preserved) - adaptive_exit/ (AEM engine + models/bucket_assignments.pkl) - Observability/ (EsoF advisor, TUI, dashboards) - external_factors/ (EsoF producer) - mc_forewarning_qlabs_fork/ (MC regime/envelope) Excludes runtime caches, logs, backups, and reproducible artifacts per .gitignore.
This commit is contained in:
203
prod/services/service_manager.py
Executable file
203
prod/services/service_manager.py
Executable file
@@ -0,0 +1,203 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Dolphin Service Manager - Centralized userland service control
|
||||
No root required! Uses systemd --user
|
||||
"""
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
from typing import List, Optional
|
||||
|
||||
SERVICES = {
|
||||
'exf': 'dolphin-exf.service',
|
||||
'ob': 'dolphin-ob.service',
|
||||
'watchdog': 'dolphin-watchdog.service',
|
||||
'mc': 'dolphin-mc.service',
|
||||
'mc-timer': 'dolphin-mc.timer',
|
||||
}
|
||||
|
||||
def run_cmd(cmd: List[str], check: bool = True) -> subprocess.CompletedProcess:
|
||||
"""Run systemctl command for user services"""
|
||||
full_cmd = ['systemctl', '--user'] + cmd
|
||||
print(f"Running: {' '.join(full_cmd)}")
|
||||
return subprocess.run(full_cmd, check=check, capture_output=True, text=True)
|
||||
|
||||
def status(service: Optional[str] = None):
|
||||
"""Show status of all or specific service"""
|
||||
if service:
|
||||
svc = SERVICES.get(service, service)
|
||||
result = run_cmd(['status', svc], check=False)
|
||||
print(result.stdout or result.stderr)
|
||||
else:
|
||||
print("=== Dolphin Services Status ===\n")
|
||||
for name, svc in SERVICES.items():
|
||||
result = run_cmd(['is-active', svc], check=False)
|
||||
status = "✓ RUNNING" if result.returncode == 0 else "✗ STOPPED"
|
||||
print(f"{name:12} {status}")
|
||||
|
||||
print("\n=== Recent Logs ===")
|
||||
result = run_cmd(['--lines=20', 'status'], check=False)
|
||||
print(result.stdout[-2000:] if result.stdout else "No recent output")
|
||||
|
||||
def start(service: Optional[str] = None):
|
||||
"""Start service(s)"""
|
||||
if service:
|
||||
svc = SERVICES.get(service, service)
|
||||
run_cmd(['start', svc])
|
||||
print(f"Started {service}")
|
||||
else:
|
||||
for name, svc in SERVICES.items():
|
||||
if name == 'mc': # Skip mc service, use timer
|
||||
continue
|
||||
run_cmd(['start', svc])
|
||||
print(f"Started {name}")
|
||||
|
||||
def stop(service: Optional[str] = None):
|
||||
"""Stop service(s)"""
|
||||
if service:
|
||||
svc = SERVICES.get(service, service)
|
||||
run_cmd(['stop', svc])
|
||||
print(f"Stopped {service}")
|
||||
else:
|
||||
for name, svc in SERVICES.items():
|
||||
run_cmd(['stop', svc])
|
||||
print(f"Stopped {name}")
|
||||
|
||||
def restart(service: Optional[str] = None):
|
||||
"""Restart service(s)"""
|
||||
if service:
|
||||
svc = SERVICES.get(service, service)
|
||||
run_cmd(['restart', svc])
|
||||
print(f"Restarted {service}")
|
||||
else:
|
||||
for name, svc in SERVICES.items():
|
||||
run_cmd(['restart', svc])
|
||||
print(f"Restarted {name}")
|
||||
|
||||
def logs(service: str, follow: bool = False, lines: int = 50):
|
||||
"""Show logs for a service"""
|
||||
svc = SERVICES.get(service, service)
|
||||
cmd = ['journalctl', '--user', '-u', svc, f'--lines={lines}']
|
||||
if follow:
|
||||
cmd.append('--follow')
|
||||
subprocess.run(cmd)
|
||||
|
||||
def enable():
|
||||
"""Enable services to start on boot"""
|
||||
for name, svc in SERVICES.items():
|
||||
run_cmd(['enable', svc])
|
||||
print(f"Enabled {name}")
|
||||
|
||||
def disable():
|
||||
"""Disable services from starting on boot"""
|
||||
for name, svc in SERVICES.items():
|
||||
run_cmd(['disable', svc])
|
||||
print(f"Disabled {name}")
|
||||
|
||||
def daemon_reload():
|
||||
"""Reload systemd daemon (after editing .service files)"""
|
||||
run_cmd(['daemon-reload'])
|
||||
print("Daemon reloaded")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Dolphin Service Manager - Userland service control',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
%(prog)s status # Show all service status
|
||||
%(prog)s start exf # Start ExF service
|
||||
%(prog)s logs ob -f # Follow OB service logs
|
||||
%(prog)s restart # Restart all services
|
||||
%(prog)s enable # Enable auto-start on boot
|
||||
"""
|
||||
)
|
||||
|
||||
subparsers = parser.add_subparsers(dest='command', help='Command')
|
||||
|
||||
# Status
|
||||
p_status = subparsers.add_parser('status', help='Show service status')
|
||||
p_status.add_argument('service', nargs='?', help='Specific service')
|
||||
|
||||
# Start
|
||||
p_start = subparsers.add_parser('start', help='Start service(s)')
|
||||
p_start.add_argument('service', nargs='?', help='Specific service')
|
||||
|
||||
# Stop
|
||||
p_stop = subparsers.add_parser('stop', help='Stop service(s)')
|
||||
p_stop.add_argument('service', nargs='?', help='Specific service')
|
||||
|
||||
# Restart
|
||||
p_restart = subparsers.add_parser('restart', help='Restart service(s)')
|
||||
p_restart.add_argument('service', nargs='?', help='Specific service')
|
||||
|
||||
# Logs
|
||||
p_logs = subparsers.add_parser('logs', help='Show service logs')
|
||||
p_logs.add_argument('service', help='Service name')
|
||||
p_logs.add_argument('-f', '--follow', action='store_true', help='Follow logs')
|
||||
p_logs.add_argument('-n', '--lines', type=int, default=50, help='Number of lines')
|
||||
|
||||
# Enable/Disable
|
||||
subparsers.add_parser('enable', help='Enable auto-start')
|
||||
subparsers.add_parser('disable', help='Disable auto-start')
|
||||
subparsers.add_parser('reload', help='Reload systemd daemon')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.command:
|
||||
parser.print_help()
|
||||
return
|
||||
|
||||
try:
|
||||
if args.command == 'status':
|
||||
status(args.service)
|
||||
elif args.command == 'start':
|
||||
start(args.service)
|
||||
elif args.command == 'stop':
|
||||
stop(args.service)
|
||||
elif args.command == 'restart':
|
||||
restart(args.service)
|
||||
elif args.command == 'logs':
|
||||
logs(args.service, args.follow, args.lines)
|
||||
elif args.command == 'enable':
|
||||
enable()
|
||||
elif args.command == 'disable':
|
||||
disable()
|
||||
elif args.command == 'reload':
|
||||
daemon_reload()
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
if e.stderr:
|
||||
print(e.stderr, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
# =============================================================================
|
||||
# SUPERVISOR-SPECIFIC COMMANDS
|
||||
# =============================================================================
|
||||
|
||||
def supervisor_status():
|
||||
"""Show supervisor internal component status"""
|
||||
import subprocess
|
||||
result = subprocess.run(
|
||||
['journalctl', '--user', '-u', 'dolphin-supervisor', '--lines=100', '-o', 'json'],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
print("=== Supervisor Component Status ===")
|
||||
print("(Parse logs for component health)")
|
||||
print(result.stdout[-2000:] if result.stdout else "No logs")
|
||||
|
||||
def supervisor_components():
|
||||
"""List components managed by supervisor"""
|
||||
print("""
|
||||
Components managed by dolphin-supervisor.service:
|
||||
- exf (0.5s) External Factors
|
||||
- ob (0.5s) Order Book Streamer
|
||||
- watchdog (10s) Survival Stack
|
||||
- mc (4h) MC-Forewarner
|
||||
""")
|
||||
|
||||
# Add to main() argument parser if needed
|
||||
Reference in New Issue
Block a user