apt-ostree/docs/apt-ostree-daemon-plan/reference/dbus-api.md
robojerk 306a68b89a fix: Resolve compilation errors in parallel and cache modules
- Fix parallel execution logic to properly handle JoinHandle<Result<R, E>> types
- Use join_all instead of try_join_all for proper Result handling
- Fix double question mark (??) issue in parallel execution methods
- Clean up unused imports in parallel and cache modules
- Ensure all performance optimization modules compile successfully
- Fix CI build failures caused by compilation errors
2025-08-16 15:10:00 -07:00

22 KiB

🔌 apt-ostree DBus API Reference

🎯 Overview

This document provides a complete reference for the apt-ostree DBus API, including all interfaces, methods, signals, and data types. The API enables communication between the CLI client and the aptostreed daemon, following the same patterns as rpm-ostree.

🏗️ DBus Architecture

Service Information

  • Service Name: org.projectatomic.aptostree1
  • Object Path: /org/projectatomic/aptostree1
  • Interface: org.projectatomic.aptostree1
  • Bus Type: System bus (privileged operations)

Connection Details

# Connect to DBus service
busctl --system call org.projectatomic.aptostree1 \
    /org/projectatomic/aptostree1 \
    org.freedesktop.DBus.Properties \
    Get org.projectatomic.aptostree1 Version

# List available methods
busctl --system introspect org.projectatomic.aptostree1 \
    /org/projectatomic/aptostree1 \
    org.projectatomic.aptostree1

📋 Core Interfaces

Main Interface: org.projectatomic.aptostree1

Properties

<!-- org.projectatomic.aptostree1.xml -->
<interface name="org.projectatomic.aptostree1">
    <property name="Version" type="s" access="read"/>
    <property name="Status" type="s" access="read"/>
    <property name="ActiveTransaction" type="s" access="read"/>
    <property name="LastOperation" type="s" access="read"/>
    <property name="LastOperationTime" type="t" access="read"/>
</interface>

Methods

<!-- System Status Methods -->
<method name="GetStatus">
    <arg name="options" type="a{sv}" direction="in"/>
    <arg name="status" type="a{sv}" direction="out"/>
</method>

<method name="GetDeployments">
    <arg name="options" type="a{sv}" direction="in"/>
    <arg name="deployments" type="a{sv}" direction="out"/>
</method>

<method name="GetSystemInfo">
    <arg name="info" type="a{sv}" direction="out"/>
</method>

<!-- Package Management Methods -->
<method name="InstallPackages">
    <arg name="transaction_id" type="s" direction="in"/>
    <arg name="packages" type="as" direction="in"/>
    <arg name="options" type="a{sv}" direction="in"/>
    <arg name="result" type="b" direction="out"/>
</method>

<method name="UninstallPackages">
    <arg name="transaction_id" type="s" direction="in"/>
    <arg name="packages" type="as" direction="in"/>
    <arg name="options" type="a{sv}" direction="in"/>
    <arg name="result" type="b" direction="out"/>
</method>

<method name="UpgradeSystem">
    <arg name="transaction_id" type="s" direction="in"/>
    <arg name="options" type="a{sv}" direction="in"/>
    <arg name="result" type="b" direction="out"/>
</method>

<!-- Transaction Management Methods -->
<method name="CreateTransaction">
    <arg name="transaction_type" type="s" direction="in"/>
    <arg name="options" type="a{sv}" direction="in"/>
    <arg name="transaction_id" type="s" direction="out"/>
</method>

<method name="CommitTransaction">
    <arg name="transaction_id" type="s" direction="in"/>
    <arg name="result" type="b" direction="out"/>
</method>

<method name="CancelTransaction">
    <arg name="transaction_id" type="s" direction="in"/>
    <arg name="result" type="b" direction="out"/>
</method>

<!-- Package Override Methods -->
<method name="OverridePackage">
    <arg name="package" type="s" direction="in"/>
    <arg name="version" type="s" direction="in"/>
    <arg name="options" type="a{sv}" direction="in"/>
    <arg name="result" type="b" direction="out"/>
</method>

<method name="ResetPackageOverride">
    <arg name="package" type="s" direction="in"/>
    <arg name="result" type="b" direction="out"/>
</method>

<method name="ListPackageOverrides">
    <arg name="overrides" type="a{sv}" direction="out"/>
</method>

<!-- User Overlay Methods -->
<method name="ApplyUserOverlay">
    <arg name="name" type="s" direction="in"/>
    <arg name="source" type="s" direction="in"/>
    <arg name="target" type="s" direction="in"/>
    <arg name="options" type="a{sv}" direction="in"/>
    <arg name="result" type="b" direction="out"/>
</method>

<method name="RemoveUserOverlay">
    <arg name="name" type="s" direction="in"/>
    <arg name="result" type="b" direction="out"/>
</method>

<method name="ListUserOverlays">
    <arg name="overlays" type="a{sv}" direction="out"/>
</method>

<!-- Live Update Methods -->
<method name="ApplyLiveUpdate">
    <arg name="deployment" type="s" direction="in"/>
    <arg name="options" type="a{sv}" direction="in"/>
    <arg name="result" type="b" direction="out"/>
</method>

<method name="GetLiveUpdateStatus">
    <arg name="status" type="a{sv}" direction="out"/>
</method>

<!-- Boot Management Methods -->
<method name="RegenerateInitramfs">
    <arg name="options" type="a{sv}" direction="in"/>
    <arg name="result" type="b" direction="out"/>
</method>

<method name="SetKernelArgs">
    <arg name="args" type="as" direction="in"/>
    <arg name="options" type="a{sv}" direction="in"/>
    <arg name="result" type="b" direction="out"/>
</method>

<method name="GetKernelArgs">
    <arg name="args" type="as" direction="out"/>
</method>
</interface>

Signals

<!-- Progress and Status Signals -->
<signal name="TransactionProgress">
    <arg name="transaction_id" type="s"/>
    <arg name="progress" type="u"/>
    <arg name="message" type="s"/>
</signal>

<signal name="TransactionCompleted">
    <arg name="transaction_id" type="s"/>
    <arg name="success" type="b"/>
    <arg name="message" type="s"/>
</signal>

<signal name="SystemStatusChanged">
    <arg name="status" type="s"/>
    <arg name="details" type="a{sv}"/>
</signal>

<signal name="PackageStatusChanged">
    <arg name="package" type="s"/>
    <arg name="status" type="s"/>
    <arg name="details" type="a{sv}"/>
</signal>

🔧 Transaction Management Interface

Transaction Types

// Transaction type definitions
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TransactionType {
    PackageInstall,
    PackageUninstall,
    SystemUpgrade,
    PackageOverride,
    UserOverlay,
    LiveUpdate,
    BootManagement,
    Custom(String),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionOptions {
    pub timeout: Option<u64>,
    pub force: bool,
    pub dry_run: bool,
    pub reboot_after: bool,
    pub user_id: Option<u32>,
    pub session_id: Option<String>,
}

Transaction States

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TransactionState {
    Created,
    Running,
    Completed,
    Failed,
    Cancelled,
    RollingBack,
    RolledBack,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionInfo {
    pub id: String,
    pub transaction_type: TransactionType,
    pub state: TransactionState,
    pub created_at: u64,
    pub started_at: Option<u64>,
    pub completed_at: Option<u64>,
    pub progress: u32,
    pub message: String,
    pub options: TransactionOptions,
    pub result: Option<TransactionResult>,
}

📦 Package Management Interface

Package Information

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PackageInfo {
    pub name: String,
    pub version: String,
    pub architecture: String,
    pub description: Option<String>,
    pub depends: Vec<String>,
    pub recommends: Vec<String>,
    pub suggests: Vec<String>,
    pub conflicts: Vec<String>,
    pub installed_size: u64,
    pub maintainer: Option<String>,
    pub section: Option<String>,
    pub priority: Option<String>,
    pub source: Option<String>,
    pub installed: bool,
    pub status: PackageStatus,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PackageStatus {
    NotInstalled,
    Installed,
    Upgradable,
    Broken,
    Hold,
    PendingInstall,
    PendingRemove,
    PendingUpgrade,
}

Package Operations

// Package installation options
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InstallOptions {
    pub version: Option<String>,
    pub force: bool,
    pub allow_downgrade: bool,
    pub allow_remove_essential: bool,
    pub allow_unauthenticated: bool,
    pub install_recommends: bool,
    pub install_suggests: bool,
    pub user_id: Option<u32>,
    pub session_id: Option<String>,
}

// Package search and query options
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QueryOptions {
    pub installed_only: bool,
    pub upgradable_only: bool,
    pub search_pattern: Option<String>,
    pub architecture: Option<String>,
    pub section: Option<String>,
    pub priority: Option<String>,
}

🌳 OSTree Management Interface

Deployment Information

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeploymentInfo {
    pub id: String,
    pub osname: String,
    pub ref: String,
    pub checksum: String,
    pub version: String,
    pub timestamp: u64,
    pub booted: bool,
    pub staged: bool,
    pub pending: bool,
    pub rollback: bool,
    pub origin: String,
    pub packages: Vec<PackageInfo>,
    pub kernel_args: Vec<String>,
    pub initramfs: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OSTreeStatus {
    pub deployments: Vec<DeploymentInfo>,
    pub booted_deployment: Option<String>,
    pub staged_deployment: Option<String>,
    pub pending_deployment: Option<String>,
    pub repository_status: RepositoryStatus,
    pub system_status: SystemStatus,
}

Repository Operations

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RepositoryStatus {
    pub path: String,
    pub mode: String,
    pub compression: String,
    pub refs: Vec<String>,
    pub commits: u64,
    pub objects: u64,
    pub size: u64,
    pub free_space: u64,
    pub healthy: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommitInfo {
    pub checksum: String,
    pub subject: String,
    pub body: Option<String>,
    pub author: String,
    pub timestamp: u64,
    pub parent: Option<String>,
    pub tree: String,
    pub metadata: HashMap<String, String>,
}

🔒 Security and Authorization Interface

Polkit Integration

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthorizationRequest {
    pub action: String,
    pub user_id: u32,
    pub session_id: Option<String>,
    pub details: HashMap<String, String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthorizationResult {
    pub authorized: bool,
    pub details: Option<String>,
    pub expires_at: Option<u64>,
    pub challenge: Option<String>,
}

// Authorization actions
pub const ACTIONS: &[&str] = &[
    "org.projectatomic.aptostree.status",
    "org.projectatomic.aptostree.upgrade",
    "org.projectatomic.aptostree.install",
    "org.projectatomic.aptostree.uninstall",
    "org.projectatomic.aptostree.override",
    "org.projectatomic.aptostree.usroverlay",
    "org.projectatomic.aptostree.live-update",
    "org.projectatomic.aptostree.boot-management",
];

User and Session Management

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserInfo {
    pub user_id: u32,
    pub username: String,
    pub groups: Vec<String>,
    pub home_directory: String,
    pub shell: String,
    pub authorized_actions: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionInfo {
    pub session_id: String,
    pub user_id: u32,
    pub service: String,
    pub type_: String,
    pub state: String,
    pub created_at: u64,
    pub last_activity: u64,
}

📊 Monitoring and Metrics Interface

System Metrics

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemMetrics {
    pub cpu_usage: f64,
    pub memory_usage: u64,
    pub memory_total: u64,
    pub disk_usage: u64,
    pub disk_total: u64,
    pub network_rx: u64,
    pub network_tx: u64,
    pub uptime: u64,
    pub load_average: [f64; 3],
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApplicationMetrics {
    pub operations_total: u64,
    pub operations_failed: u64,
    pub active_connections: u32,
    pub package_installations: u64,
    pub package_removals: u64,
    pub system_upgrades: u64,
    pub average_response_time: f64,
    pub cache_hit_rate: f64,
}

Health Check Interface

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthStatus {
    pub overall: HealthState,
    pub components: HashMap<String, ComponentHealth>,
    pub last_check: u64,
    pub next_check: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum HealthState {
    Healthy,
    Degraded,
    Unhealthy,
    Unknown,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComponentHealth {
    pub state: HealthState,
    pub message: String,
    pub details: Option<String>,
    pub last_check: u64,
    pub error_count: u32,
}

🔌 Client Implementation Examples

Rust Client Example

use zbus::{Connection, Proxy};
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize)]
pub struct AptOstreeClient {
    connection: Connection,
    proxy: Proxy<'static>,
}

impl AptOstreeClient {
    pub async fn new() -> Result<Self, Box<dyn std::error::Error>> {
        let connection = Connection::system().await?;
        let proxy = Proxy::new(
            &connection,
            "org.projectatomic.aptostree1",
            "/org/projectatomic/aptostree1",
            "org.projectatomic.aptostree1",
        ).await?;
        
        Ok(Self { connection, proxy })
    }
    
    pub async fn get_status(&self) -> Result<OSTreeStatus, Box<dyn std::error::Error>> {
        let status: a{sv} = self.proxy.call_method("GetStatus", &()).await?;
        let status: OSTreeStatus = serde_json::from_value(status.into())?;
        Ok(status)
    }
    
    pub async fn install_packages(
        &self,
        transaction_id: &str,
        packages: &[String],
        options: &InstallOptions,
    ) -> Result<bool, Box<dyn std::error::Error>> {
        let result: bool = self.proxy.call_method(
            "InstallPackages",
            &(transaction_id, packages, options),
        ).await?;
        Ok(result)
    }
    
    pub async fn create_transaction(
        &self,
        transaction_type: &str,
        options: &TransactionOptions,
    ) -> Result<String, Box<dyn std::error::Error>> {
        let transaction_id: String = self.proxy.call_method(
            "CreateTransaction",
            &(transaction_type, options),
        ).await?;
        Ok(transaction_id)
    }
}

Python Client Example

import dbus
import json
from typing import Dict, List, Optional

class AptOstreeClient:
    def __init__(self):
        self.bus = dbus.SystemBus()
        self.proxy = self.bus.get_object(
            'org.projectatomic.aptostree1',
            '/org/projectatomic/aptostree1'
        )
        self.interface = dbus.Interface(
            self.proxy,
            'org.projectatomic.aptostree1'
        )
    
    def get_status(self) -> Dict:
        """Get system status"""
        result = self.interface.GetStatus({})
        return json.loads(result)
    
    def install_packages(
        self,
        transaction_id: str,
        packages: List[str],
        options: Dict
    ) -> bool:
        """Install packages"""
        result = self.interface.InstallPackages(
            transaction_id,
            packages,
            options
        )
        return bool(result)
    
    def create_transaction(
        self,
        transaction_type: str,
        options: Dict
    ) -> str:
        """Create a new transaction"""
        transaction_id = self.interface.CreateTransaction(
            transaction_type,
            options
        )
        return str(transaction_id)
    
    def get_deployments(self) -> List[Dict]:
        """Get list of deployments"""
        result = self.interface.GetDeployments({})
        return json.loads(result)

# Usage example
if __name__ == "__main__":
    client = AptOstreeClient()
    
    # Get system status
    status = client.get_status()
    print(f"System status: {status}")
    
    # Create transaction and install package
    transaction_id = client.create_transaction("PackageInstall", {})
    success = client.install_packages(transaction_id, ["vim"], {})
    print(f"Installation successful: {success}")

Shell Script Example

#!/bin/bash

# apt-ostree DBus client script

DBUS_SERVICE="org.projectatomic.aptostree1"
DBUS_OBJECT="/org/projectatomic/aptostree1"
DBUS_INTERFACE="org.projectatomic.aptostree1"

# Function to call DBus method
call_dbus_method() {
    local method="$1"
    shift
    busctl --system call "$DBUS_SERVICE" "$DBUS_OBJECT" "$DBUS_INTERFACE" "$method" "$@"
}

# Function to get property
get_property() {
    local property="$1"
    busctl --system get-property "$DBUS_SERVICE" "$DBUS_OBJECT" "$DBUS_INTERFACE" "$property"
}

# Get system status
get_status() {
    echo "Getting system status..."
    call_dbus_method "GetStatus" '{}'
}

# Get deployments
get_deployments() {
    echo "Getting deployments..."
    call_dbus_method "GetDeployments" '{}'
}

# Install packages
install_packages() {
    local packages="$1"
    local transaction_id
    
    echo "Creating transaction..."
    transaction_id=$(call_dbus_method "CreateTransaction" 's' "PackageInstall" '{}')
    transaction_id=$(echo "$transaction_id" | sed 's/"//g')
    
    echo "Installing packages: $packages"
    call_dbus_method "InstallPackages" 's' "$transaction_id" 'as' "$packages" '{}'
    
    echo "Committing transaction..."
    call_dbus_method "CommitTransaction" 's' "$transaction_id"
}

# Main script
case "$1" in
    "status")
        get_status
        ;;
    "deployments")
        get_deployments
        ;;
    "install")
        if [ -z "$2" ]; then
            echo "Usage: $0 install <package1> [package2] ..."
            exit 1
        fi
        shift
        install_packages "$@"
        ;;
    *)
        echo "Usage: $0 {status|deployments|install}"
        exit 1
        ;;
esac

📝 Error Handling

Error Types

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AptOstreeError {
    // System errors
    SystemError(String),
    PermissionDenied(String),
    ResourceNotFound(String),
    ResourceBusy(String),
    
    // Package errors
    PackageNotFound(String),
    PackageConflict(String),
    DependencyError(String),
    InstallationFailed(String),
    
    // OSTree errors
    OSTreeError(String),
    RepositoryError(String),
    DeploymentError(String),
    CommitError(String),
    
    // Transaction errors
    TransactionNotFound(String),
    TransactionFailed(String),
    TransactionTimeout(String),
    
    // Security errors
    AuthorizationFailed(String),
    InvalidCredentials(String),
    PolicyViolation(String),
    
    // Network errors
    NetworkError(String),
    TimeoutError(String),
    ConnectionError(String),
}

impl std::fmt::Display for AptOstreeError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            AptOstreeError::SystemError(msg) => write!(f, "System error: {}", msg),
            AptOstreeError::PermissionDenied(msg) => write!(f, "Permission denied: {}", msg),
            AptOstreeError::PackageNotFound(pkg) => write!(f, "Package not found: {}", pkg),
            AptOstreeError::OSTreeError(msg) => write!(f, "OSTree error: {}", msg),
            AptOstreeError::TransactionFailed(msg) => write!(f, "Transaction failed: {}", msg),
            AptOstreeError::AuthorizationFailed(msg) => write!(f, "Authorization failed: {}", msg),
            _ => write!(f, "Unknown error: {:?}", self),
        }
    }
}

Error Response Format

<!-- Error response structure -->
<method name="InstallPackages">
    <arg name="transaction_id" type="s" direction="in"/>
    <arg name="packages" type="as" direction="in"/>
    <arg name="options" type="a{sv}" direction="in"/>
    <arg name="result" type="b" direction="out"/>
    <annotation name="org.freedesktop.DBus.GLib.Error" value="AptOstreeError"/>
</method>

🔄 Event Handling

Signal Handling

use zbus::{Connection, SignalReceiver};
use futures_util::StreamExt;

pub async fn handle_signals(connection: Connection) -> Result<(), Box<dyn std::error::Error>> {
    let receiver = SignalReceiver::new(connection, "org.projectatomic.aptostree1").await?;
    
    while let Some(signal) = receiver.next().await {
        match signal.member_name().as_str() {
            "TransactionProgress" => {
                let (transaction_id, progress, message) = signal.body().deserialize()?;
                println!("Transaction {}: {}% - {}", transaction_id, progress, message);
            }
            "TransactionCompleted" => {
                let (transaction_id, success, message) = signal.body().deserialize()?;
                println!("Transaction {} completed: {} - {}", 
                    transaction_id, if success { "SUCCESS" } else { "FAILED" }, message);
            }
            "SystemStatusChanged" => {
                let (status, details) = signal.body().deserialize()?;
                println!("System status changed: {} - {:?}", status, details);
            }
            _ => {
                println!("Unknown signal: {:?}", signal);
            }
        }
    }
    
    Ok(())
}

🎯 Next Steps

Immediate Actions

  1. Implement core DBus interface in the daemon
  2. Create client libraries for Rust, Python, and shell
  3. Set up signal handling for real-time updates
  4. Implement error handling and response formatting

Short-term Goals

  1. Complete all interface methods with proper implementations
  2. Add comprehensive error handling and validation
  3. Implement security and authorization checks
  4. Add monitoring and metrics endpoints

Long-term Vision

  1. Performance optimization and connection pooling
  2. Advanced event handling and filtering
  3. Multi-language client support
  4. Integration with system monitoring tools

This DBus API reference provides comprehensive coverage of all interfaces and methods for apt-ostree. For detailed implementation information, refer to the architecture documents in the docs/apt-ostree-daemon-plan/architecture/ directory.