- ✅ Real package installation (replaced mock installation) - ✅ Real OSTree commit creation from installed packages - ✅ OCI image creation from both commits and rootfs - ✅ Full bootc compatibility with proper labels - ✅ Comprehensive test suite (test-bootc-apt-ostree.sh) - ✅ Container tool validation (skopeo, podman) - ✅ Updated compatibility reports for Ubuntu Questing - ✅ Fixed OCI schema version and field naming issues - ✅ Temporary directory lifecycle fixes - ✅ Serde rename attributes for OCI JSON compliance Ready for Aurora-style workflow deployment!
23 KiB
apt-ostree D-Bus Interface
Executive Summary
apt-ostree implements the same D-Bus interface as rpm-ostree, providing 100% compatibility while adapting the underlying functionality to the APT/DEB ecosystem. The D-Bus interface enables secure, reliable communication between unprivileged clients and the privileged daemon.
D-Bus Architecture
Service Overview
Service Name: org.aptostree.dev
Purpose: Provide system management interface for apt-ostree operations
Architecture:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ CLI Client │ │ GUI Client │ │ API Client │
│ (apt-ostree) │ │ (GNOME/KDE) │ │ (Python/Go) │
└─────────┬───────┘ └─────────┬───────┘ └─────────┬───────┘
│ │ │
└──────────────────────┼──────────────────────┘
│
┌─────────────▼─────────────┐
│ D-Bus Interface │
│ (org.aptostree.dev) │
└─────────────┬─────────────┘
│
┌─────────────▼─────────────┐
│ apt-ostreed Daemon │
│ (Privileged Service) │
└───────────────────────────┘
Design Principles
- 100% Compatibility: Identical interface to rpm-ostree
- Standard Interface: Use standard D-Bus conventions and patterns
- Type Safety: Strong typing for all method parameters and return values
- Error Handling: Comprehensive error reporting and propagation
- Progress Reporting: Real-time progress updates via signals
- Transaction Management: Transaction-based operations with rollback support
- OSTree Detection: Environment validation before operations
Interface Definition
Main Objects
/org/aptostree/dev/Sysroot
Purpose: System root management and deployment operations
Interface: org.aptostree.dev.Sysroot
/org/aptostree/dev/OS
Purpose: Operating system operations and package management
Interface: org.aptostree.dev.OS
Interface XML Definition
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.aptostree.dev.Sysroot">
<method name="GetDeployments">
<arg name="deployments" type="a(sa{sv})" direction="out"/>
</method>
<method name="GetBootedDeployment">
<arg name="deployment" type="(sa{sv})" direction="out"/>
</method>
<method name="GetPendingDeployment">
<arg name="deployment" type="(sa{sv})" direction="out"/>
</method>
<method name="GetDeploymentState">
<arg name="deployment" type="s" direction="in"/>
<arg name="state" type="s" direction="out"/>
</method>
</interface>
<interface name="org.aptostree.dev.OS">
<method name="install_packages">
<arg name="packages" type="as" direction="in"/>
<arg name="options" type="a{sv}" direction="in"/>
<arg name="transaction_address" type="s" direction="out"/>
</method>
<method name="remove_packages">
<arg name="packages" type="as" direction="in"/>
<arg name="options" type="a{sv}" direction="in"/>
<arg name="transaction_address" type="s" direction="out"/>
</method>
<method name="upgrade_system">
<arg name="options" type="a{sv}" direction="in"/>
<arg name="transaction_address" type="s" direction="out"/>
</method>
<method name="rollback">
<arg name="options" type="a{sv}" direction="in"/>
<arg name="transaction_address" type="s" direction="out"/>
</method>
<method name="deploy">
<arg name="ref" type="s" direction="in"/>
<arg name="options" type="a{sv}" direction="in"/>
<arg name="transaction_address" type="s" direction="out"/>
</method>
<method name="rebase">
<arg name="ref" type="s" direction="in"/>
<arg name="options" type="a{sv}" direction="in"/>
<arg name="transaction_address" type="s" direction="out"/>
</method>
<method name="kargs">
<arg name="operation" type="s" direction="in"/>
<arg name="args" type="as" direction="in"/>
<arg name="options" type="a{sv}" direction="in"/>
<arg name="transaction_address" type="s" direction="out"/>
</method>
<method name="cleanup">
<arg name="options" type="a{sv}" direction="in"/>
<arg name="transaction_address" type="s" direction="out"/>
</method>
<method name="show_status">
<arg name="options" type="a{sv}" direction="in"/>
<arg name="status" type="s" direction="out"/>
</method>
<method name="list_packages">
<arg name="options" type="a{sv}" direction="in"/>
<arg name="packages" type="as" direction="out"/>
</method>
<method name="search_packages">
<arg name="query" type="s" direction="in"/>
<arg name="options" type="a{sv}" direction="in"/>
<arg name="results" type="as" direction="out"/>
</method>
<method name="show_package_info">
<arg name="package" type="s" direction="in"/>
<arg name="info" type="s" direction="out"/>
</method>
<signal name="TransactionChanged">
<arg name="transaction_address" type="s"/>
<arg name="state" type="s"/>
<arg name="message" type="s"/>
<arg name="percentage" type="i"/>
</signal>
<signal name="TransactionCompleted">
<arg name="transaction_address" type="s"/>
<arg name="success" type="b"/>
<arg name="result" type="s"/>
</signal>
<signal name="StatusChanged">
<arg name="status" type="s"/>
</signal>
</interface>
</node>
Method Details
Sysroot Methods
GetDeployments
Purpose: Get list of available deployments
Parameters: None
Returns: Array of deployment information
Example:
// Client call
let result = connection.call_method(
Some("org.aptostree.dev"),
"/org/aptostree/dev/Sysroot",
Some("org.aptostree.dev.Sysroot"),
"GetDeployments",
&(),
)?;
// Parse result
let deployments: Vec<(String, HashMap<String, Variant>)> = result.body()?;
GetBootedDeployment
Purpose: Get information about the currently booted deployment
Parameters: None
Returns: Deployment information for booted deployment
Example:
let result = connection.call_method(
Some("org.aptostree.dev"),
"/org/aptostree/dev/Sysroot",
Some("org.aptostree.dev.Sysroot"),
"GetBootedDeployment",
&(),
)?;
GetPendingDeployment
Purpose: Get information about the pending deployment
Parameters: None
Returns: Deployment information for pending deployment
OS Methods
install_packages
Purpose: Install packages with atomic commits
Parameters:
packages: Array of package namesoptions: Dictionary of installation options
Options:
reboot: Boolean - Automatically reboot after installationallow-inactive: Boolean - Allow installing on inactive deploymentidempotent: Boolean - Don't error if packages already installed
Returns: Transaction address for tracking operation
Example:
// Prepare packages array
let packages = vec!["vim".to_string(), "git".to_string()];
// Prepare options
let mut options = HashMap::new();
options.insert("reboot".to_string(), Variant::from(false));
// Call method
let result = connection.call_method(
Some("org.aptostree.dev"),
"/org/aptostree/dev/OS",
Some("org.aptostree.dev.OS"),
"install_packages",
&(packages, options),
)?;
// Get transaction address
let transaction_address: String = result.body()?;
remove_packages
Purpose: Remove packages with rollback support
Parameters:
packages: Array of package namesoptions: Dictionary of removal options
Options:
reboot: Boolean - Automatically reboot after removalidempotent: Boolean - Don't error if packages not installed
Returns: Transaction address for tracking operation
upgrade_system
Purpose: Upgrade system with automatic policies
Parameters:
options: Dictionary of upgrade options
Options:
reboot: Boolean - Automatically reboot after upgradedownload-only: Boolean - Download updates without installingallow-downgrade: Boolean - Allow downgrading packagesunchanged-exit-77: Boolean - Exit with 77 if no changes
Returns: Transaction address for tracking operation
Example:
// Prepare options
let mut options = HashMap::new();
options.insert("reboot".to_string(), Variant::from(true));
options.insert("download-only".to_string(), Variant::from(false));
// Call method
let result = connection.call_method(
Some("org.aptostree.dev"),
"/org/aptostree/dev/OS",
Some("org.aptostree.dev.OS"),
"upgrade_system",
&(options,),
)?;
// Get transaction address
let transaction_address: String = result.body()?;
rollback
Purpose: Rollback to previous deployment
Parameters:
options: Dictionary of rollback options
Options:
reboot: Boolean - Automatically reboot after rollbacknot-as-default: Boolean - Don't set as default boot option
Returns: Transaction address for tracking operation
deploy
Purpose: Deploy specific version or commit
Parameters:
ref: Deployment reference (version or commit hash)options: Dictionary of deployment options
Options:
reboot: Boolean - Automatically reboot after deploymentnot-as-default: Boolean - Don't set as default boot optionos: String - Specify operating system name
Returns: Transaction address for tracking operation
rebase
Purpose: Switch to different base image
Parameters:
ref: Base image referenceoptions: Dictionary of rebase options
Options:
reboot: Boolean - Automatically reboot after rebaseos: String - Specify operating system name
Returns: Transaction address for tracking operation
kargs
Purpose: Manage kernel arguments
Parameters:
operation: Operation type ("append", "delete", "replace", "show")args: Array of kernel argumentsoptions: Dictionary of kernel argument options
Options:
reboot: Boolean - Automatically reboot after changes
Returns: Transaction address for tracking operation
cleanup
Purpose: Clean up old deployments
Parameters:
options: Dictionary of cleanup options
Options:
base: Boolean - Clean up base imagesrepomd: Boolean - Clean up repository metadatarollback: Boolean - Clean up rollback deployments
Returns: Transaction address for tracking operation
show_status
Purpose: Show system status and deployment information
Parameters:
options: Dictionary of status options
Options:
json: Boolean - Output in JSON formatbooted: Boolean - Show only booted deploymentpending: Boolean - Show only pending deployment
Returns: Status string (JSON or text format)
Example:
// Prepare options
let mut options = HashMap::new();
options.insert("json".to_string(), Variant::from(false));
// Call method
let result = connection.call_method(
Some("org.aptostree.dev"),
"/org/aptostree/dev/OS",
Some("org.aptostree.dev.OS"),
"show_status",
&(options,),
)?;
// Get status
let status: String = result.body()?;
println!("Status: {}", status);
list_packages
Purpose: List installed packages
Parameters:
options: Dictionary of list options
Options:
json: Boolean - Output in JSON format
Returns: Array of package names
search_packages
Purpose: Search for packages
Parameters:
query: Search query stringoptions: Dictionary of search options
Options:
json: Boolean - Output in JSON formatlimit: Integer - Limit number of results
Returns: Array of matching package names
Example:
// Prepare options
let mut options = HashMap::new();
options.insert("json".to_string(), Variant::from(false));
options.insert("limit".to_string(), Variant::from(10));
// Call method
let result = connection.call_method(
Some("org.aptostree.dev"),
"/org/aptostree/dev/OS",
Some("org.aptostree.dev.OS"),
"search_packages",
&("firefox", options),
)?;
// Get results
let results: Vec<String> = result.body()?;
for package in results {
println!("Found package: {}", package);
}
show_package_info
Purpose: Show detailed package information
Parameters:
package: Package name
Returns: JSON-formatted package information
Example:
let result = connection.call_method(
Some("org.aptostree.dev"),
"/org/aptostree/dev/OS",
Some("org.aptostree.dev.OS"),
"show_package_info",
&("vim",),
)?;
let info: String = result.body()?;
println!("Package info: {}", info);
Signals
TransactionChanged
Purpose: Report transaction state changes
Parameters:
transaction_address: Transaction identifierstate: Transaction state ("preparing", "downloading", "installing", "finalizing")message: Human-readable status messagepercentage: Progress percentage (0-100)
Example:
// Signal handler
fn handle_transaction_changed(
msg: &Message,
_: &Connection,
_: &Message,
) -> Result<(), Box<dyn std::error::Error>> {
let (transaction_address, state, message, percentage): (String, String, String, i32) = msg.body()?;
println!("Transaction {}: {} - {} ({}%)",
transaction_address, state, message, percentage);
Ok(())
}
// Subscribe to signal
connection.add_match(
"type='signal',interface='org.aptostree.dev.OS',member='TransactionChanged'",
)?;
connection.add_signal_handler(
"org.aptostree.dev.OS",
"TransactionChanged",
handle_transaction_changed,
)?;
TransactionCompleted
Purpose: Report transaction completion
Parameters:
transaction_address: Transaction identifiersuccess: Boolean indicating success or failureresult: Result message or error description
Example:
fn handle_transaction_completed(
msg: &Message,
_: &Connection,
_: &Message,
) -> Result<(), Box<dyn std::error::Error>> {
let (transaction_address, success, result): (String, bool, String) = msg.body()?;
if success {
println!("Transaction {} completed successfully: {}", transaction_address, result);
} else {
println!("Transaction {} failed: {}", transaction_address, result);
}
Ok(())
}
StatusChanged
Purpose: Report system status changes
Parameters:
status: New system status
Transaction Management
Transaction Lifecycle
- Initiation: Client calls method, receives transaction address
- Progress: Daemon emits TransactionChanged signals
- Completion: Daemon emits TransactionCompleted signal
- Cleanup: Transaction resources are cleaned up
Transaction States
- preparing: Transaction is being prepared
- downloading: Packages are being downloaded via APT
- installing: Packages are being installed
- finalizing: Transaction is being finalized
- completed: Transaction completed successfully
- failed: Transaction failed
Transaction Tracking
Example:
// Start transaction
let transaction_address: String = result.body()?;
// Subscribe to transaction signals
connection.add_match(
"type='signal',interface='org.aptostree.dev.OS',member='TransactionChanged'",
)?;
connection.add_match(
"type='signal',interface='org.aptostree.dev.OS',member='TransactionCompleted'",
)?;
connection.add_signal_handler(
"org.aptostree.dev.OS",
"TransactionChanged",
handle_transaction_changed,
)?;
connection.add_signal_handler(
"org.aptostree.dev.OS",
"TransactionCompleted",
handle_transaction_completed,
)?;
Error Handling
Error Types
- org.freedesktop.DBus.Error.ServiceUnknown: Daemon service not available
- org.freedesktop.DBus.Error.NoReply: Daemon not responding
- org.freedesktop.DBus.Error.Timeout: Operation timed out
- org.freedesktop.DBus.Error.Failed: General operation failure
- org.freedesktop.DBus.Error.InvalidArgs: Invalid method arguments
- org.aptostree.dev.Error.OstreeEnvironment: Non-OSTree system
Error Handling Example
let result = connection.call_method(
Some("org.aptostree.dev"),
"/org/aptostree/dev/OS",
Some("org.aptostree.dev.OS"),
"upgrade_system",
&(options,),
);
match result {
Ok(response) => {
let transaction_address: String = response.body()?;
println!("Upgrade started: {}", transaction_address);
}
Err(Error::MethodError(ref name, ref message, _)) => {
match name.as_str() {
"org.freedesktop.DBus.Error.ServiceUnknown" => {
eprintln!("Daemon is not running. Using direct system calls.");
}
"org.aptostree.dev.Error.OstreeEnvironment" => {
eprintln!("This system is not running on an OSTree deployment.");
}
_ => {
eprintln!("Error: {} - {}", name, message);
}
}
}
Err(e) => {
eprintln!("Unexpected error: {}", e);
}
}
Security
Authentication
PolicyKit Integration:
<policyconfig>
<action id="org.aptostree.dev.upgrade">
<description>Upgrade system</description>
<message>Authentication is required to upgrade the system</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/libexec/apt-ostreed</annotate>
</action>
<action id="org.aptostree.dev.install">
<description>Install packages</description>
<message>Authentication is required to install packages</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/libexec/apt-ostreed</annotate>
</action>
</policyconfig>
Access Control
- System Bus: D-Bus system bus for privileged operations
- Service Activation: Automatic service activation via systemd
- User Permissions: PolicyKit-based user permission management
OSTree Environment Detection
Detection Integration
apt-ostree integrates OSTree environment detection into the D-Bus interface:
Error Handling:
// Check OSTree environment before operations
if !ostree_detection.detect_ostree_environment()? {
return Err(Error::MethodError(
"org.aptostree.dev.Error.OstreeEnvironment".to_string(),
"This system is not running on an OSTree deployment.".to_string(),
None,
));
}
Error Messages:
Error: apt-ostree requires an OSTree environment to operate.
This system does not appear to be running on an OSTree deployment.
To use apt-ostree:
1. Ensure you are running on an OSTree-based system
2. Verify that /ostree directory exists
3. Verify that /run/ostree-booted file exists
4. Ensure you have a valid booted deployment
Performance Considerations
Connection Management
Connection Pooling:
// Reuse connections when possible
lazy_static! {
static ref CONNECTION: Mutex<Option<Connection>> = Mutex::new(None);
}
fn get_connection() -> Result<Connection, Box<dyn std::error::Error>> {
let mut conn_guard = CONNECTION.lock().unwrap();
if conn_guard.is_none() {
*conn_guard = Some(Connection::new_system_sync()?);
}
Ok(conn_guard.as_ref().unwrap().clone())
}
Async Operations
Non-blocking Calls:
connection.call_method(
Some("org.aptostree.dev"),
"/org/aptostree/dev/OS",
Some("org.aptostree.dev.OS"),
"upgrade_system",
&(options,),
)?.body::<String>()
.map(|transaction_address| {
println!("Upgrade started: {}", transaction_address);
})
.map_err(|e| {
eprintln!("Error: {}", e);
});
Monitoring and Debugging
D-Bus Monitoring
Monitor D-Bus Traffic:
# Monitor all D-Bus traffic
dbus-monitor --system
# Monitor specific service
dbus-monitor --system "destination='org.aptostree.dev'"
Debugging Tools
D-Bus Introspection:
# Introspect service
gdbus introspect --system --dest org.aptostree.dev --object-path /org/aptostree/dev/OS
D-Bus Call Testing:
# Test method call
gdbus call --system --dest org.aptostree.dev --object-path /org/aptostree/dev/OS --method org.aptostree.dev.OS.show_status
APT Integration
APT-Specific Methods
Package Management:
install_packages: Install packages via APTremove_packages: Remove packages via APTupgrade_system: Upgrade system via APTlist_packages: List packages via APT databasesearch_packages: Search packages via APTshow_package_info: Show package info via APT
APT Database Integration:
// APT database operations in D-Bus methods
pub fn handle_install_packages(
&self,
packages: Vec<String>,
options: HashMap<String, Variant>,
) -> Result<String, Box<dyn std::error::Error>> {
// Initialize APT database
let mut apt_manager = AptManager::new()?;
// Install packages
apt_manager.install_packages(&packages)?;
// Create transaction
let transaction_id = self.create_transaction("install")?;
Ok(transaction_id)
}
Future Enhancements
Planned Features
- Event Streaming: Real-time event streaming for status updates
- Batch Operations: Support for batch operations
- Advanced Filtering: Enhanced filtering and querying capabilities
- Performance Optimization: Further performance improvements
Interface Improvements
- Versioning: Interface versioning for backward compatibility
- Extensions: Extensible interface for custom operations
- Validation: Enhanced parameter validation
- Documentation: Improved interface documentation
APT Enhancements
- Advanced Dependency Resolution: Enhanced dependency handling
- Package Conflict Resolution: Improved conflict resolution
- Repository Management: Enhanced repository management
- Package Verification: Enhanced package verification