#!/usr/bin/env python3 """ Debian Forge Composer Integration Module (Simplified) This module provides integration between debian-forge and debian-forge-composer, ensuring 1:1 compatibility with the upstream osbuild/osbuild-composer. Simplified version without external dependencies. """ import json import subprocess import time from typing import Dict, List, Optional, Any from dataclasses import dataclass from pathlib import Path @dataclass class ComposerBuildRequest: """Build request for composer integration""" blueprint_name: str compose_type: str architecture: str = "x86_64" distro: str = "debian-12" size: int = 0 upload: bool = False metadata: Optional[Dict[str, Any]] = None @dataclass class ComposerBuildStatus: """Build status from composer""" id: str status: str blueprint_name: str compose_type: str architecture: str created_at: str started_at: Optional[str] = None finished_at: Optional[str] = None error_message: Optional[str] = None class DebianForgeComposerSimple: """Simplified integration with debian-forge-composer (fork of osbuild/osbuild-composer)""" def __init__(self, composer_path: str = "../debian-forge-composer"): self.composer_path = Path(composer_path) self.composer_binary = self.composer_path / "cmd" / "osbuild-composer" / "osbuild-composer" # Verify composer path exists if not self.composer_path.exists(): raise FileNotFoundError(f"Composer path not found: {composer_path}") def get_composer_version(self) -> str: """Get composer version information""" try: if self.composer_binary.exists(): result = subprocess.run([str(self.composer_binary), "--version"], capture_output=True, text=True, check=True) return result.stdout.strip() except: pass return "Version unknown" def test_composer_integration(self) -> Dict[str, Any]: """Test composer integration functionality""" results = { "composer_path_exists": self.composer_path.exists(), "composer_binary_exists": self.composer_binary.exists(), "composer_version": self.get_composer_version(), "blueprint_operations": False, "compose_operations": False } # Test blueprint creation try: test_blueprint = self.create_debian_blueprint( "test-integration", "1.0.0", ["bash", "coreutils"] ) if test_blueprint and "name" in test_blueprint: results["blueprint_operations"] = True except Exception as e: results["blueprint_error"] = str(e) # Test compose operations (simulated) try: # Simulate compose operations results["compose_operations"] = True results["compose_simulated"] = True except Exception as e: results["compose_error"] = str(e) return results def create_debian_blueprint(self, name: str, version: str, packages: List[str], customizations: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: """Create a Debian-specific blueprint for composer""" blueprint = { "name": name, "version": version, "description": f"Debian atomic blueprint for {name}", "packages": packages, "modules": [], "groups": [], "customizations": customizations or {} } # Add Debian-specific customizations if "debian" not in blueprint["customizations"]: blueprint["customizations"]["debian"] = { "repositories": [ { "name": "debian-main", "baseurl": "http://deb.debian.org/debian", "enabled": True } ] } return blueprint def submit_blueprint(self, blueprint_data: Dict[str, Any]) -> Dict[str, Any]: """Submit a blueprint to composer (simulated)""" # In real implementation, this would make HTTP request to composer API return { "status": "success", "blueprint": blueprint_data.get("name", "unknown"), "message": "Blueprint submitted successfully (simulated)" } def start_compose(self, request: ComposerBuildRequest) -> Dict[str, Any]: """Start a compose using composer (simulated)""" # Simulate compose start compose_id = f"compose-{int(time.time())}" return { "id": compose_id, "status": "queued", "blueprint": request.blueprint_name, "compose_type": request.compose_type } def get_compose_status(self, compose_id: str) -> ComposerBuildStatus: """Get compose status (simulated)""" # Simulate compose status return ComposerBuildStatus( id=compose_id, status="running", created_at=time.strftime("%Y-%m-%d %H:%M:%S"), blueprint="test-blueprint", compose_type="qcow2", architecture="x86_64" ) def list_composes(self) -> List[Dict[str, Any]]: """List all composes (simulated)""" # Simulate compose listing return [ { "id": "compose-1", "blueprint": "debian-atomic-base", "status": "completed", "created_at": "2024-12-19 10:00:00" }, { "id": "compose-2", "blueprint": "debian-atomic-workstation", "status": "running", "created_at": "2024-12-19 11:00:00" } ] def cancel_compose(self, compose_id: str) -> bool: """Cancel a compose (simulated)""" # Simulate compose cancellation return True def get_service_status(self) -> Dict[str, Any]: """Get composer service status (simulated)""" return { "status": "running", "version": self.get_composer_version(), "uptime": "2d 14h 37m" } def get_system_info(self) -> Dict[str, Any]: """Get system information from composer (simulated)""" return { "distros": ["debian-12", "debian-11"], "architectures": ["x86_64", "amd64"], "workers": 2, "status": "healthy" } def get_worker_status(self) -> Dict[str, Any]: """Get worker status from composer (simulated)""" return { "workers": [ { "id": "worker-1", "status": "idle", "arch": "x86_64" }, { "id": "worker-2", "status": "building", "arch": "x86_64" } ] }