Major milestone: Complete apt-ostree bootc compatibility and OCI integration
- ✅ 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!
This commit is contained in:
parent
0ba99d6195
commit
d295f9bb4d
171 changed files with 15230 additions and 26739 deletions
846
.notes/dbus/apt-ostree.md
Normal file
846
.notes/dbus/apt-ostree.md
Normal file
|
|
@ -0,0 +1,846 @@
|
|||
# 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
|
||||
|
||||
1. **100% Compatibility**: Identical interface to rpm-ostree
|
||||
2. **Standard Interface**: Use standard D-Bus conventions and patterns
|
||||
3. **Type Safety**: Strong typing for all method parameters and return values
|
||||
4. **Error Handling**: Comprehensive error reporting and propagation
|
||||
5. **Progress Reporting**: Real-time progress updates via signals
|
||||
6. **Transaction Management**: Transaction-based operations with rollback support
|
||||
7. **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
|
||||
|
||||
```xml
|
||||
<!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**:
|
||||
```rust
|
||||
// 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**:
|
||||
```rust
|
||||
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 names
|
||||
- `options`: Dictionary of installation options
|
||||
|
||||
**Options**:
|
||||
- `reboot`: Boolean - Automatically reboot after installation
|
||||
- `allow-inactive`: Boolean - Allow installing on inactive deployment
|
||||
- `idempotent`: Boolean - Don't error if packages already installed
|
||||
|
||||
**Returns**: Transaction address for tracking operation
|
||||
|
||||
**Example**:
|
||||
```rust
|
||||
// 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 names
|
||||
- `options`: Dictionary of removal options
|
||||
|
||||
**Options**:
|
||||
- `reboot`: Boolean - Automatically reboot after removal
|
||||
- `idempotent`: 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 upgrade
|
||||
- `download-only`: Boolean - Download updates without installing
|
||||
- `allow-downgrade`: Boolean - Allow downgrading packages
|
||||
- `unchanged-exit-77`: Boolean - Exit with 77 if no changes
|
||||
|
||||
**Returns**: Transaction address for tracking operation
|
||||
|
||||
**Example**:
|
||||
```rust
|
||||
// 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 rollback
|
||||
- `not-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 deployment
|
||||
- `not-as-default`: Boolean - Don't set as default boot option
|
||||
- `os`: String - Specify operating system name
|
||||
|
||||
**Returns**: Transaction address for tracking operation
|
||||
|
||||
#### rebase
|
||||
|
||||
**Purpose**: Switch to different base image
|
||||
|
||||
**Parameters**:
|
||||
- `ref`: Base image reference
|
||||
- `options`: Dictionary of rebase options
|
||||
|
||||
**Options**:
|
||||
- `reboot`: Boolean - Automatically reboot after rebase
|
||||
- `os`: 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 arguments
|
||||
- `options`: 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 images
|
||||
- `repomd`: Boolean - Clean up repository metadata
|
||||
- `rollback`: 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 format
|
||||
- `booted`: Boolean - Show only booted deployment
|
||||
- `pending`: Boolean - Show only pending deployment
|
||||
|
||||
**Returns**: Status string (JSON or text format)
|
||||
|
||||
**Example**:
|
||||
```rust
|
||||
// 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 string
|
||||
- `options`: Dictionary of search options
|
||||
|
||||
**Options**:
|
||||
- `json`: Boolean - Output in JSON format
|
||||
- `limit`: Integer - Limit number of results
|
||||
|
||||
**Returns**: Array of matching package names
|
||||
|
||||
**Example**:
|
||||
```rust
|
||||
// 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**:
|
||||
```rust
|
||||
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 identifier
|
||||
- `state`: Transaction state ("preparing", "downloading", "installing", "finalizing")
|
||||
- `message`: Human-readable status message
|
||||
- `percentage`: Progress percentage (0-100)
|
||||
|
||||
**Example**:
|
||||
```rust
|
||||
// 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 identifier
|
||||
- `success`: Boolean indicating success or failure
|
||||
- `result`: Result message or error description
|
||||
|
||||
**Example**:
|
||||
```rust
|
||||
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
|
||||
|
||||
1. **Initiation**: Client calls method, receives transaction address
|
||||
2. **Progress**: Daemon emits TransactionChanged signals
|
||||
3. **Completion**: Daemon emits TransactionCompleted signal
|
||||
4. **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**:
|
||||
```rust
|
||||
// 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
|
||||
|
||||
1. **org.freedesktop.DBus.Error.ServiceUnknown**: Daemon service not available
|
||||
2. **org.freedesktop.DBus.Error.NoReply**: Daemon not responding
|
||||
3. **org.freedesktop.DBus.Error.Timeout**: Operation timed out
|
||||
4. **org.freedesktop.DBus.Error.Failed**: General operation failure
|
||||
5. **org.freedesktop.DBus.Error.InvalidArgs**: Invalid method arguments
|
||||
6. **org.aptostree.dev.Error.OstreeEnvironment**: Non-OSTree system
|
||||
|
||||
### Error Handling Example
|
||||
|
||||
```rust
|
||||
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**:
|
||||
```xml
|
||||
<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**:
|
||||
```rust
|
||||
// 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**:
|
||||
```rust
|
||||
// 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**:
|
||||
```rust
|
||||
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**:
|
||||
```bash
|
||||
# Monitor all D-Bus traffic
|
||||
dbus-monitor --system
|
||||
|
||||
# Monitor specific service
|
||||
dbus-monitor --system "destination='org.aptostree.dev'"
|
||||
```
|
||||
|
||||
### Debugging Tools
|
||||
|
||||
**D-Bus Introspection**:
|
||||
```bash
|
||||
# Introspect service
|
||||
gdbus introspect --system --dest org.aptostree.dev --object-path /org/aptostree/dev/OS
|
||||
```
|
||||
|
||||
**D-Bus Call Testing**:
|
||||
```bash
|
||||
# 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 APT
|
||||
- `remove_packages`: Remove packages via APT
|
||||
- `upgrade_system`: Upgrade system via APT
|
||||
- `list_packages`: List packages via APT database
|
||||
- `search_packages`: Search packages via APT
|
||||
- `show_package_info`: Show package info via APT
|
||||
|
||||
**APT Database Integration**:
|
||||
```rust
|
||||
// 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
|
||||
|
||||
1. **Event Streaming**: Real-time event streaming for status updates
|
||||
2. **Batch Operations**: Support for batch operations
|
||||
3. **Advanced Filtering**: Enhanced filtering and querying capabilities
|
||||
4. **Performance Optimization**: Further performance improvements
|
||||
|
||||
### Interface Improvements
|
||||
|
||||
1. **Versioning**: Interface versioning for backward compatibility
|
||||
2. **Extensions**: Extensible interface for custom operations
|
||||
3. **Validation**: Enhanced parameter validation
|
||||
4. **Documentation**: Improved interface documentation
|
||||
|
||||
### APT Enhancements
|
||||
|
||||
1. **Advanced Dependency Resolution**: Enhanced dependency handling
|
||||
2. **Package Conflict Resolution**: Improved conflict resolution
|
||||
3. **Repository Management**: Enhanced repository management
|
||||
4. **Package Verification**: Enhanced package verification
|
||||
731
.notes/dbus/rpm-ostree.md
Normal file
731
.notes/dbus/rpm-ostree.md
Normal file
|
|
@ -0,0 +1,731 @@
|
|||
# rpm-ostree D-Bus Interface
|
||||
|
||||
## Executive Summary
|
||||
|
||||
rpm-ostree uses D-Bus as its primary inter-process communication mechanism, providing a standardized interface for client-daemon communication. The D-Bus interface enables secure, reliable communication between unprivileged clients and the privileged daemon.
|
||||
|
||||
## D-Bus Architecture
|
||||
|
||||
### Service Overview
|
||||
|
||||
**Service Name**: `org.projectatomic.rpmostree1`
|
||||
|
||||
**Purpose**: Provide system management interface for rpm-ostree operations
|
||||
|
||||
**Architecture**:
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ CLI Client │ │ GUI Client │ │ API Client │
|
||||
│ (rpmostree) │ │ (GNOME/KDE) │ │ (Python/Go) │
|
||||
└─────────┬───────┘ └─────────┬───────┘ └─────────┬───────┘
|
||||
│ │ │
|
||||
└──────────────────────┼──────────────────────┘
|
||||
│
|
||||
┌─────────────▼─────────────┐
|
||||
│ D-Bus Interface │
|
||||
│ (org.projectatomic.rpmo │
|
||||
│ stree1) │
|
||||
└─────────────┬─────────────┘
|
||||
│
|
||||
┌─────────────▼─────────────┐
|
||||
│ rpm-ostreed Daemon │
|
||||
│ (Privileged Service) │
|
||||
└───────────────────────────┘
|
||||
```
|
||||
|
||||
### Design Principles
|
||||
|
||||
1. **Standard Interface**: Use standard D-Bus conventions and patterns
|
||||
2. **Type Safety**: Strong typing for all method parameters and return values
|
||||
3. **Error Handling**: Comprehensive error reporting and propagation
|
||||
4. **Progress Reporting**: Real-time progress updates via signals
|
||||
5. **Transaction Management**: Transaction-based operations with rollback support
|
||||
|
||||
## Interface Definition
|
||||
|
||||
### Main Objects
|
||||
|
||||
#### `/org/projectatomic/rpmostree1/Sysroot`
|
||||
|
||||
**Purpose**: System root management and deployment operations
|
||||
|
||||
**Interface**: `org.projectatomic.rpmostree1.Sysroot`
|
||||
|
||||
#### `/org/projectatomic/rpmostree1/OS`
|
||||
|
||||
**Purpose**: Operating system operations and package management
|
||||
|
||||
**Interface**: `org.projectatomic.rpmostree1.OS`
|
||||
|
||||
### Interface XML Definition
|
||||
|
||||
```xml
|
||||
<!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.projectatomic.rpmostree1.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.projectatomic.rpmostree1.OS">
|
||||
<method name="Upgrade">
|
||||
<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="PkgChange">
|
||||
<arg name="packages" type="as" direction="in"/>
|
||||
<arg name="change_type" type="s" direction="in"/>
|
||||
<arg name="options" type="a{sv}" direction="in"/>
|
||||
<arg name="transaction_address" type="s" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="KernelArgs">
|
||||
<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="GetStatus">
|
||||
<arg name="status" type="s" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="GetPackages">
|
||||
<arg name="packages" type="as" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="SearchPackages">
|
||||
<arg name="query" type="s" direction="in"/>
|
||||
<arg name="results" type="as" direction="out"/>
|
||||
</method>
|
||||
|
||||
<method name="GetPackageInfo">
|
||||
<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**:
|
||||
```cpp
|
||||
// Client call
|
||||
GVariant* result = g_dbus_connection_call_sync(
|
||||
connection,
|
||||
"org.projectatomic.rpmostree1",
|
||||
"/org/projectatomic/rpmostree1/Sysroot",
|
||||
"org.projectatomic.rpmostree1.Sysroot",
|
||||
"GetDeployments",
|
||||
nullptr,
|
||||
nullptr,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
|
||||
// Parse result
|
||||
GVariantIter* iter;
|
||||
g_variant_get(result, "(a(sa{sv}))", &iter);
|
||||
```
|
||||
|
||||
#### GetBootedDeployment
|
||||
|
||||
**Purpose**: Get information about the currently booted deployment
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: Deployment information for booted deployment
|
||||
|
||||
**Example**:
|
||||
```cpp
|
||||
GVariant* result = g_dbus_connection_call_sync(
|
||||
connection,
|
||||
"org.projectatomic.rpmostree1",
|
||||
"/org/projectatomic/rpmostree1/Sysroot",
|
||||
"org.projectatomic.rpmostree1.Sysroot",
|
||||
"GetBootedDeployment",
|
||||
nullptr,
|
||||
nullptr,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
```
|
||||
|
||||
#### GetPendingDeployment
|
||||
|
||||
**Purpose**: Get information about the pending deployment
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: Deployment information for pending deployment
|
||||
|
||||
### OS Methods
|
||||
|
||||
#### Upgrade
|
||||
|
||||
**Purpose**: Upgrade system to latest version
|
||||
|
||||
**Parameters**:
|
||||
- `options`: Dictionary of upgrade options
|
||||
|
||||
**Options**:
|
||||
- `reboot`: Boolean - Automatically reboot after upgrade
|
||||
- `download-only`: Boolean - Download updates without installing
|
||||
- `allow-downgrade`: Boolean - Allow downgrading packages
|
||||
- `unchanged-exit-77`: Boolean - Exit with 77 if no changes
|
||||
|
||||
**Returns**: Transaction address for tracking operation
|
||||
|
||||
**Example**:
|
||||
```cpp
|
||||
// Prepare options
|
||||
GVariantBuilder* builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
|
||||
g_variant_builder_add(builder, "{sv}", "reboot", g_variant_new_boolean(TRUE));
|
||||
g_variant_builder_add(builder, "{sv}", "download-only", g_variant_new_boolean(FALSE));
|
||||
|
||||
GVariant* options = g_variant_builder_end(builder);
|
||||
|
||||
// Call method
|
||||
GVariant* result = g_dbus_connection_call_sync(
|
||||
connection,
|
||||
"org.projectatomic.rpmostree1",
|
||||
"/org/projectatomic/rpmostree1/OS",
|
||||
"org.projectatomic.rpmostree1.OS",
|
||||
"Upgrade",
|
||||
g_variant_new("(a{sv})", options),
|
||||
nullptr,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
|
||||
// Get transaction address
|
||||
const char* transaction_address;
|
||||
g_variant_get(result, "(s)", &transaction_address);
|
||||
```
|
||||
|
||||
#### Rollback
|
||||
|
||||
**Purpose**: Rollback to previous deployment
|
||||
|
||||
**Parameters**:
|
||||
- `options`: Dictionary of rollback options
|
||||
|
||||
**Options**:
|
||||
- `reboot`: Boolean - Automatically reboot after rollback
|
||||
- `not-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 deployment
|
||||
- `not-as-default`: Boolean - Don't set as default boot option
|
||||
- `os`: String - Specify operating system name
|
||||
|
||||
**Returns**: Transaction address for tracking operation
|
||||
|
||||
#### Rebase
|
||||
|
||||
**Purpose**: Switch to different base image
|
||||
|
||||
**Parameters**:
|
||||
- `ref`: Base image reference
|
||||
- `options`: Dictionary of rebase options
|
||||
|
||||
**Options**:
|
||||
- `reboot`: Boolean - Automatically reboot after rebase
|
||||
- `os`: String - Specify operating system name
|
||||
|
||||
**Returns**: Transaction address for tracking operation
|
||||
|
||||
#### PkgChange
|
||||
|
||||
**Purpose**: Install or remove packages
|
||||
|
||||
**Parameters**:
|
||||
- `packages`: Array of package names
|
||||
- `change_type`: Type of change ("install" or "remove")
|
||||
- `options`: Dictionary of package change options
|
||||
|
||||
**Options**:
|
||||
- `reboot`: Boolean - Automatically reboot after package change
|
||||
- `allow-inactive`: Boolean - Allow installing on inactive deployment
|
||||
- `idempotent`: Boolean - Don't error if packages already installed/removed
|
||||
|
||||
**Returns**: Transaction address for tracking operation
|
||||
|
||||
**Example**:
|
||||
```cpp
|
||||
// Prepare packages array
|
||||
GVariantBuilder* packages_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
|
||||
g_variant_builder_add(packages_builder, "s", "vim");
|
||||
g_variant_builder_add(packages_builder, "s", "git");
|
||||
|
||||
GVariant* packages = g_variant_builder_end(packages_builder);
|
||||
|
||||
// Prepare options
|
||||
GVariantBuilder* options_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
|
||||
g_variant_builder_add(options_builder, "{sv}", "reboot", g_variant_new_boolean(FALSE));
|
||||
|
||||
GVariant* options = g_variant_builder_end(options_builder);
|
||||
|
||||
// Call method
|
||||
GVariant* result = g_dbus_connection_call_sync(
|
||||
connection,
|
||||
"org.projectatomic.rpmostree1",
|
||||
"/org/projectatomic/rpmostree1/OS",
|
||||
"org.projectatomic.rpmostree1.OS",
|
||||
"PkgChange",
|
||||
g_variant_new("(assa{sv})", packages, "install", options),
|
||||
nullptr,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
```
|
||||
|
||||
#### KernelArgs
|
||||
|
||||
**Purpose**: Manage kernel arguments
|
||||
|
||||
**Parameters**:
|
||||
- `operation`: Operation type ("append", "delete", "replace", "show")
|
||||
- `args`: Array of kernel arguments
|
||||
- `options`: 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 images
|
||||
- `repomd`: Boolean - Clean up repository metadata
|
||||
- `rollback`: Boolean - Clean up rollback deployments
|
||||
|
||||
**Returns**: Transaction address for tracking operation
|
||||
|
||||
#### GetStatus
|
||||
|
||||
**Purpose**: Get system status
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: JSON-formatted status string
|
||||
|
||||
**Example**:
|
||||
```cpp
|
||||
GVariant* result = g_dbus_connection_call_sync(
|
||||
connection,
|
||||
"org.projectatomic.rpmostree1",
|
||||
"/org/projectatomic/rpmostree1/OS",
|
||||
"org.projectatomic.rpmostree1.OS",
|
||||
"GetStatus",
|
||||
nullptr,
|
||||
nullptr,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
|
||||
const char* status;
|
||||
g_variant_get(result, "(s)", &status);
|
||||
printf("Status: %s\n", status);
|
||||
```
|
||||
|
||||
#### GetPackages
|
||||
|
||||
**Purpose**: Get list of installed packages
|
||||
|
||||
**Parameters**: None
|
||||
|
||||
**Returns**: Array of package names
|
||||
|
||||
#### SearchPackages
|
||||
|
||||
**Purpose**: Search for packages
|
||||
|
||||
**Parameters**:
|
||||
- `query`: Search query string
|
||||
|
||||
**Returns**: Array of matching package names
|
||||
|
||||
#### GetPackageInfo
|
||||
|
||||
**Purpose**: Get detailed package information
|
||||
|
||||
**Parameters**:
|
||||
- `package`: Package name
|
||||
|
||||
**Returns**: JSON-formatted package information
|
||||
|
||||
## Signals
|
||||
|
||||
### TransactionChanged
|
||||
|
||||
**Purpose**: Report transaction state changes
|
||||
|
||||
**Parameters**:
|
||||
- `transaction_address`: Transaction identifier
|
||||
- `state`: Transaction state ("preparing", "downloading", "installing", "finalizing")
|
||||
- `message`: Human-readable status message
|
||||
- `percentage`: Progress percentage (0-100)
|
||||
|
||||
**Example**:
|
||||
```cpp
|
||||
// Signal handler
|
||||
void handle_transaction_changed(GDBusConnection* connection,
|
||||
const char* sender,
|
||||
const char* object_path,
|
||||
const char* interface_name,
|
||||
const char* signal_name,
|
||||
GVariant* parameters,
|
||||
void* user_data) {
|
||||
const char* transaction_address;
|
||||
const char* state;
|
||||
const char* message;
|
||||
int percentage;
|
||||
|
||||
g_variant_get(parameters, "(sssi)", &transaction_address, &state, &message, &percentage);
|
||||
|
||||
printf("Transaction %s: %s - %s (%d%%)\n",
|
||||
transaction_address, state, message, percentage);
|
||||
}
|
||||
```
|
||||
|
||||
### TransactionCompleted
|
||||
|
||||
**Purpose**: Report transaction completion
|
||||
|
||||
**Parameters**:
|
||||
- `transaction_address`: Transaction identifier
|
||||
- `success`: Boolean indicating success or failure
|
||||
- `result`: Result message or error description
|
||||
|
||||
**Example**:
|
||||
```cpp
|
||||
void handle_transaction_completed(GDBusConnection* connection,
|
||||
const char* sender,
|
||||
const char* object_path,
|
||||
const char* interface_name,
|
||||
const char* signal_name,
|
||||
GVariant* parameters,
|
||||
void* user_data) {
|
||||
const char* transaction_address;
|
||||
gboolean success;
|
||||
const char* result;
|
||||
|
||||
g_variant_get(parameters, "(sbs)", &transaction_address, &success, &result);
|
||||
|
||||
if (success) {
|
||||
printf("Transaction %s completed successfully: %s\n", transaction_address, result);
|
||||
} else {
|
||||
printf("Transaction %s failed: %s\n", transaction_address, result);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### StatusChanged
|
||||
|
||||
**Purpose**: Report system status changes
|
||||
|
||||
**Parameters**:
|
||||
- `status`: New system status
|
||||
|
||||
## Transaction Management
|
||||
|
||||
### Transaction Lifecycle
|
||||
|
||||
1. **Initiation**: Client calls method, receives transaction address
|
||||
2. **Progress**: Daemon emits TransactionChanged signals
|
||||
3. **Completion**: Daemon emits TransactionCompleted signal
|
||||
4. **Cleanup**: Transaction resources are cleaned up
|
||||
|
||||
### Transaction States
|
||||
|
||||
- **preparing**: Transaction is being prepared
|
||||
- **downloading**: Packages are being downloaded
|
||||
- **installing**: Packages are being installed
|
||||
- **finalizing**: Transaction is being finalized
|
||||
- **completed**: Transaction completed successfully
|
||||
- **failed**: Transaction failed
|
||||
|
||||
### Transaction Tracking
|
||||
|
||||
**Example**:
|
||||
```cpp
|
||||
// Start transaction
|
||||
const char* transaction_address;
|
||||
g_variant_get(result, "(s)", &transaction_address);
|
||||
|
||||
// Subscribe to transaction signals
|
||||
g_dbus_connection_signal_subscribe(
|
||||
connection,
|
||||
"org.projectatomic.rpmostree1",
|
||||
"org.projectatomic.rpmostree1.OS",
|
||||
"TransactionChanged",
|
||||
"/org/projectatomic/rpmostree1/OS",
|
||||
nullptr,
|
||||
G_DBUS_SIGNAL_FLAGS_NONE,
|
||||
handle_transaction_changed,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
|
||||
g_dbus_connection_signal_subscribe(
|
||||
connection,
|
||||
"org.projectatomic.rpmostree1",
|
||||
"org.projectatomic.rpmostree1.OS",
|
||||
"TransactionCompleted",
|
||||
"/org/projectatomic/rpmostree1/OS",
|
||||
nullptr,
|
||||
G_DBUS_SIGNAL_FLAGS_NONE,
|
||||
handle_transaction_completed,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Error Types
|
||||
|
||||
1. **G_DBUS_ERROR_SERVICE_UNKNOWN**: Daemon service not available
|
||||
2. **G_DBUS_ERROR_NO_REPLY**: Daemon not responding
|
||||
3. **G_DBUS_ERROR_TIMEOUT**: Operation timed out
|
||||
4. **G_DBUS_ERROR_FAILED**: General operation failure
|
||||
5. **G_DBUS_ERROR_INVALID_ARGS**: Invalid method arguments
|
||||
|
||||
### Error Handling Example
|
||||
|
||||
```cpp
|
||||
GError* error = nullptr;
|
||||
GVariant* result = g_dbus_connection_call_sync(
|
||||
connection,
|
||||
"org.projectatomic.rpmostree1",
|
||||
"/org/projectatomic/rpmostree1/OS",
|
||||
"org.projectatomic.rpmostree1.OS",
|
||||
"Upgrade",
|
||||
g_variant_new("(a{sv})", options),
|
||||
nullptr,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
nullptr,
|
||||
&error
|
||||
);
|
||||
|
||||
if (error != nullptr) {
|
||||
if (g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) {
|
||||
fprintf(stderr, "Daemon is not running. Please start the rpm-ostreed service.\n");
|
||||
} else if (g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_NO_REPLY)) {
|
||||
fprintf(stderr, "Daemon is not responding. Please check the service status.\n");
|
||||
} else {
|
||||
fprintf(stderr, "Error: %s\n", error->message);
|
||||
}
|
||||
g_error_free(error);
|
||||
}
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
### Authentication
|
||||
|
||||
**PolicyKit Integration**:
|
||||
```xml
|
||||
<policyconfig>
|
||||
<action id="org.projectatomic.rpmostree1.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/rpm-ostreed</annotate>
|
||||
</action>
|
||||
|
||||
<action id="org.projectatomic.rpmostree1.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/rpm-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
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Connection Management
|
||||
|
||||
**Connection Pooling**:
|
||||
```cpp
|
||||
// Reuse connections when possible
|
||||
static GDBusConnection* get_connection() {
|
||||
static GDBusConnection* connection = nullptr;
|
||||
if (connection == nullptr) {
|
||||
connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, nullptr);
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
```
|
||||
|
||||
### Async Operations
|
||||
|
||||
**Non-blocking Calls**:
|
||||
```cpp
|
||||
g_dbus_connection_call(
|
||||
connection,
|
||||
"org.projectatomic.rpmostree1",
|
||||
"/org/projectatomic/rpmostree1/OS",
|
||||
"org.projectatomic.rpmostree1.OS",
|
||||
"Upgrade",
|
||||
g_variant_new("(a{sv})", options),
|
||||
nullptr,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
nullptr,
|
||||
handle_upgrade_response,
|
||||
nullptr
|
||||
);
|
||||
```
|
||||
|
||||
## Monitoring and Debugging
|
||||
|
||||
### D-Bus Monitoring
|
||||
|
||||
**Monitor D-Bus Traffic**:
|
||||
```bash
|
||||
# Monitor all D-Bus traffic
|
||||
dbus-monitor --system
|
||||
|
||||
# Monitor specific service
|
||||
dbus-monitor --system "destination='org.projectatomic.rpmostree1'"
|
||||
```
|
||||
|
||||
### Debugging Tools
|
||||
|
||||
**D-Bus Introspection**:
|
||||
```bash
|
||||
# Introspect service
|
||||
gdbus introspect --system --dest org.projectatomic.rpmostree1 --object-path /org/projectatomic/rpmostree1/OS
|
||||
```
|
||||
|
||||
**D-Bus Call Testing**:
|
||||
```bash
|
||||
# Test method call
|
||||
gdbus call --system --dest org.projectatomic.rpmostree1 --object-path /org/projectatomic/rpmostree1/OS --method org.projectatomic.rpmostree1.OS.GetStatus
|
||||
```
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Features
|
||||
|
||||
1. **Event Streaming**: Real-time event streaming for status updates
|
||||
2. **Batch Operations**: Support for batch operations
|
||||
3. **Advanced Filtering**: Enhanced filtering and querying capabilities
|
||||
4. **Performance Optimization**: Further performance improvements
|
||||
|
||||
### Interface Improvements
|
||||
|
||||
1. **Versioning**: Interface versioning for backward compatibility
|
||||
2. **Extensions**: Extensible interface for custom operations
|
||||
3. **Validation**: Enhanced parameter validation
|
||||
4. **Documentation**: Improved interface documentation
|
||||
Loading…
Add table
Add a link
Reference in a new issue