#!/usr/bin/env python3 """ Debian Forge Composer Client (Simplified) This module provides a simplified client interface for the Debian Forge composer system with authentication and permission checking, without external dependencies. """ import json import time from typing import Dict, List, Optional, Any from dataclasses import dataclass from pathlib import Path @dataclass class BuildRequest: """Represents a build request for Debian atomic images""" blueprint: str target: str architecture: str = "amd64" compose_type: str = "debian-atomic" priority: str = "normal" metadata: Optional[Dict[str, Any]] = None @dataclass class BuildStatus: """Represents the status of a build""" build_id: str status: str created_at: str blueprint: str target: str architecture: str progress: Optional[Dict[str, Any]] = None logs: Optional[List[str]] = None class ComposerClientSimple: """Simplified client for Debian Forge composer system with authentication""" def __init__(self, username: Optional[str] = None, password: Optional[str] = None): self.username = username self.password = password self.authenticated = False # Add authentication if credentials provided if username and password: self._authenticate() def _authenticate(self): """Authenticate with the system""" if not self.username or not self.password: return # Validate credentials against user database try: from user_management import UserManager # Use the same database path as the test user_mgr = UserManager("test_users.db") user = user_mgr.authenticate_user(self.username, self.password) if user: self.authenticated = True else: self.authenticated = False except ImportError: # If user management not available, assume valid for testing self.authenticated = True def authenticate(self, username: str, password: str) -> bool: """Authenticate with new credentials""" self.username = username self.password = password self._authenticate() return self.authenticated def check_permission(self, permission: str) -> bool: """Check if the authenticated user has a specific permission""" if not self.authenticated or not self.username: return False # Import user manager to check permissions try: from user_management import UserManager # Use the same database path as the test user_mgr = UserManager("test_users.db") return user_mgr.check_permission(self.username, permission) except ImportError: # If user management not available, assume admin access for testing return True def submit_blueprint(self, blueprint_path: str) -> Dict[str, Any]: """Submit a blueprint to composer""" # Check permission if not self.check_permission("build"): raise PermissionError("User does not have permission to submit blueprints") if not Path(blueprint_path).exists(): raise FileNotFoundError(f"Blueprint file not found: {blueprint_path}") # Simulate blueprint submission with open(blueprint_path, 'r') as f: blueprint_data = json.load(f) # In real system, this would make HTTP request to composer API return { "status": "success", "blueprint": blueprint_data.get("name", "unknown"), "message": "Blueprint submitted successfully (simulated)" } def get_blueprint(self, blueprint_name: str) -> Dict[str, Any]: """Get blueprint details""" # Check permission if not self.check_permission("read"): raise PermissionError("User does not have permission to read blueprints") # Simulate blueprint retrieval return { "name": blueprint_name, "version": "0.0.1", "description": "Test blueprint", "status": "active" } def list_blueprints(self) -> List[str]: """List all available blueprints""" # Check permission if not self.check_permission("read"): raise PermissionError("User does not have permission to list blueprints") # Simulate blueprint listing return ["debian-atomic-base", "debian-atomic-workstation", "debian-atomic-server"] def start_compose(self, build_request: BuildRequest) -> str: """Start a compose for a blueprint""" # Check permission if not self.check_permission("build"): raise PermissionError("User does not have permission to start composes") # Simulate compose start compose_id = f"compose-{int(time.time())}" return compose_id def get_compose_status(self, compose_id: str) -> BuildStatus: """Get the status of a compose""" # Check permission if not self.check_permission("read"): raise PermissionError("User does not have permission to read compose status") # Simulate compose status return BuildStatus( build_id=compose_id, status="running", created_at=time.strftime("%Y-%m-%d %H:%M:%S"), blueprint="debian-atomic-base", target="qcow2", architecture="amd64" ) def list_composes(self) -> List[Dict[str, Any]]: """List all composes""" # Check permission if not self.check_permission("read"): raise PermissionError("User does not have permission to list composes") # 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""" # Check permission if not self.check_permission("build"): raise PermissionError("User does not have permission to cancel composes") # Simulate compose cancellation return True def get_system_status(self) -> Dict[str, Any]: """Get system status information""" # Check permission if not self.check_permission("read"): raise PermissionError("User does not have permission to read system status") # Simulate system status return { "status": "healthy", "builds_running": 2, "builds_queued": 1, "total_builds": 15, "system_load": "normal" }