docs: update TODO.md and changelog for modular CLI milestone
This commit is contained in:
parent
39e05be88a
commit
b83fa060e2
54 changed files with 7696 additions and 99 deletions
188
src/apt-ostree.py/daemon/main.py
Normal file
188
src/apt-ostree.py/daemon/main.py
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
apt-ostree Daemon - New dbus-next implementation with proper decoupling
|
||||
Atomic package management system for Debian/Ubuntu inspired by rpm-ostree
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import argparse
|
||||
import logging
|
||||
import signal
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
# Add the parent directory to Python path for imports
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from core.daemon import AptOstreeDaemon
|
||||
from daemon.interfaces.sysroot_interface import AptOstreeSysrootInterface, AptOstreeOSInterface
|
||||
from dbus_next.aio import MessageBus
|
||||
from dbus_next import BusType
|
||||
|
||||
class AptOstreeNewDaemon:
|
||||
"""New daemon using dbus-next implementation with proper decoupling"""
|
||||
|
||||
def __init__(self, pid_file: str = None, config: dict = None):
|
||||
self.pid_file = pid_file
|
||||
self.config = config or {}
|
||||
self.running = False
|
||||
self.logger = logging.getLogger('daemon')
|
||||
|
||||
# Core daemon instance (pure Python, no D-Bus dependencies)
|
||||
self.core_daemon: Optional[AptOstreeDaemon] = None
|
||||
|
||||
# D-Bus components
|
||||
self.bus: Optional[MessageBus] = None
|
||||
self.sysroot_interface: Optional[AptOstreeSysrootInterface] = None
|
||||
self.os_interface: Optional[AptOstreeOSInterface] = None
|
||||
|
||||
def _write_pid_file(self):
|
||||
"""Write PID to file"""
|
||||
if self.pid_file:
|
||||
try:
|
||||
with open(self.pid_file, 'w') as f:
|
||||
f.write(str(os.getpid()))
|
||||
os.chmod(self.pid_file, 0o644)
|
||||
except Exception as e:
|
||||
print(f"Failed to write PID file: {e}", file=sys.stderr)
|
||||
|
||||
def _remove_pid_file(self):
|
||||
"""Remove PID file"""
|
||||
if self.pid_file and os.path.exists(self.pid_file):
|
||||
try:
|
||||
os.unlink(self.pid_file)
|
||||
except Exception as e:
|
||||
print(f"Failed to remove PID file: {e}", file=sys.stderr)
|
||||
|
||||
def _setup_signal_handlers(self):
|
||||
"""Setup signal handlers for graceful shutdown"""
|
||||
def signal_handler(signum, frame):
|
||||
self.logger.info(f"Received signal {signum}, shutting down...")
|
||||
self.running = False
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
signal.signal(signal.SIGTERM, signal_handler)
|
||||
|
||||
async def _setup_dbus(self):
|
||||
"""Setup D-Bus connection and interfaces"""
|
||||
try:
|
||||
# Connect to system bus
|
||||
self.bus = await MessageBus(bus_type=BusType.SYSTEM).connect()
|
||||
|
||||
# Create D-Bus interfaces with core daemon instance
|
||||
self.sysroot_interface = AptOstreeSysrootInterface(self.core_daemon)
|
||||
self.os_interface = AptOstreeOSInterface(self.core_daemon)
|
||||
|
||||
# Export interfaces
|
||||
self.bus.export("/org/debian/aptostree1/Sysroot", self.sysroot_interface)
|
||||
self.bus.export("/org/debian/aptostree1/OS/default", self.os_interface)
|
||||
|
||||
# Request D-Bus name
|
||||
await self.bus.request_name("org.debian.aptostree1")
|
||||
|
||||
self.logger.info("D-Bus interfaces exported successfully")
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to setup D-Bus: {e}")
|
||||
return False
|
||||
|
||||
async def _cleanup_dbus(self):
|
||||
"""Cleanup D-Bus connection"""
|
||||
if self.bus:
|
||||
try:
|
||||
self.bus.disconnect()
|
||||
self.logger.info("D-Bus connection closed")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error closing D-Bus connection: {e}")
|
||||
|
||||
async def run(self):
|
||||
"""Run the daemon with proper decoupling"""
|
||||
try:
|
||||
# Write PID file if specified
|
||||
if self.pid_file:
|
||||
self._write_pid_file()
|
||||
|
||||
# Setup signal handlers
|
||||
self._setup_signal_handlers()
|
||||
|
||||
self.logger.info("Starting apt-ostree daemon (dbus-next implementation)")
|
||||
|
||||
# Initialize core daemon (pure Python logic)
|
||||
self.core_daemon = AptOstreeDaemon(self.config, self.logger)
|
||||
if not await self.core_daemon.initialize():
|
||||
self.logger.error("Failed to initialize core daemon")
|
||||
return 1
|
||||
|
||||
# Setup D-Bus interfaces (thin wrapper around core daemon)
|
||||
if not await self._setup_dbus():
|
||||
self.logger.error("Failed to setup D-Bus interfaces")
|
||||
return 1
|
||||
|
||||
self.running = True
|
||||
self.logger.info("Daemon started successfully")
|
||||
|
||||
# Keep the daemon running with proper signal handling
|
||||
try:
|
||||
while self.running:
|
||||
await asyncio.sleep(1) # Check every second instead of waiting forever
|
||||
except KeyboardInterrupt:
|
||||
self.logger.info("Received interrupt signal")
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Daemon error: {e}")
|
||||
return 1
|
||||
finally:
|
||||
# Cleanup in reverse order
|
||||
await self._cleanup_dbus()
|
||||
if self.core_daemon:
|
||||
await self.core_daemon.shutdown()
|
||||
self._remove_pid_file()
|
||||
self.running = False
|
||||
|
||||
return 0
|
||||
|
||||
def parse_arguments():
|
||||
"""Parse command line arguments"""
|
||||
parser = argparse.ArgumentParser(description='apt-ostree System Management Daemon (dbus-next)')
|
||||
parser.add_argument('--daemon', action='store_true',
|
||||
help='Run as daemon (default behavior)')
|
||||
parser.add_argument('--pid-file', type=str,
|
||||
help='Write PID to specified file')
|
||||
parser.add_argument('--foreground', action='store_true',
|
||||
help='Run in foreground (for debugging)')
|
||||
parser.add_argument('--config', type=str,
|
||||
help='Path to configuration file')
|
||||
return parser.parse_args()
|
||||
|
||||
def main():
|
||||
"""Main entry point"""
|
||||
args = parse_arguments()
|
||||
|
||||
# Check if running as root (required for system operations)
|
||||
if os.geteuid() != 0:
|
||||
print("apt-ostree daemon must be run as root", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Setup basic logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
|
||||
# Load configuration (placeholder for now)
|
||||
config = {
|
||||
'daemon.auto_update_policy': 'none',
|
||||
'daemon.idle_exit_timeout': 0,
|
||||
'sysroot.path': '/',
|
||||
'sysroot.test_mode': True
|
||||
}
|
||||
|
||||
daemon = AptOstreeNewDaemon(pid_file=args.pid_file, config=config)
|
||||
|
||||
# Run the daemon
|
||||
return asyncio.run(daemon.run())
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Loading…
Add table
Add a link
Reference in a new issue