Initial commit: apt-ostree project with 100% rpm-ostree CLI compatibility

This commit is contained in:
robojerk 2025-07-18 08:31:01 +00:00
commit a48ad95d70
81 changed files with 28515 additions and 0 deletions

View file

@ -0,0 +1,370 @@
# rpm-ostree install Command Flow Analysis
## Overview
This document provides a detailed, step-by-step analysis of what happens when a user runs `rpm-ostree install htop`. The analysis is based on examination of the rpm-ostree source code and reveals the complex orchestration between client-side CLI parsing, D-Bus communication, daemon-side processing, and the underlying OSTree and DNF (libdnf) systems.
## Command Entry Point
### 1. CLI Parsing and Validation
**File**: `src/app/rpmostree-pkg-builtins.cxx`
**Function**: `rpmostree_builtin_install()`
```cpp
gboolean
rpmostree_builtin_install (int argc, char **argv, RpmOstreeCommandInvocation *invocation,
GCancellable *cancellable, GError **error)
```
**Steps**:
1. **Option Parsing**: Parse command-line options using GLib's `GOptionContext`
- `--reboot`, `--dry-run`, `--apply-live`, `--idempotent`, etc.
- Package names are extracted from positional arguments
2. **Argument Validation**: Ensure at least one package is specified
```cpp
if (argc < 2) {
rpmostree_usage_error (context, "At least one PACKAGE must be specified", error);
return FALSE;
}
```
3. **Interactive Confirmation**: Handle `--apply-live` without `--assumeyes`
- If running interactively, perform a dry-run first and prompt for confirmation
- If non-interactive (script), auto-infer `--assumeyes` with a warning
4. **Container Detection**: Check if running in an OSTree container
- If in container, use different code path for container rebuilds
- Otherwise, proceed with normal system installation
### 2. Core Package Change Logic
**Function**: `pkg_change()`
**Steps**:
1. **Package Classification**: Determine package types
```cpp
gboolean met_local_pkg = FALSE;
for (const char *const *it = packages_to_add; it && *it; it++)
met_local_pkg = met_local_pkg || g_str_has_suffix (*it, ".rpm") || g_str_has_prefix (*it, "file://");
```
2. **Option Dictionary Creation**: Build GVariant dictionary with all options
```cpp
GVariantDict dict;
g_variant_dict_init (&dict, NULL);
g_variant_dict_insert (&dict, "reboot", "b", opt_reboot);
g_variant_dict_insert (&dict, "cache-only", "b", opt_cache_only);
g_variant_dict_insert (&dict, "download-only", "b", opt_download_only);
// ... more options
```
3. **API Selection**: Choose between legacy and new D-Bus APIs
- **Legacy API**: `rpmostree_os_call_pkg_change_sync()` for simple cases
- **New API**: `rpmostree_update_deployment()` for complex cases (local packages, apply-live, etc.)
## D-Bus Communication Layer
### 3. Client-Side D-Bus Setup
**File**: `src/app/rpmostree-clientlib.cxx`
**Steps**:
1. **Daemon Startup**: Ensure rpm-ostreed daemon is running
```cpp
ROSCXX_TRY (client_start_daemon (), error);
```
2. **System Bus Connection**: Connect to system D-Bus
```cpp
g_autoptr (GDBusConnection) connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, error);
```
3. **Client Registration**: Register as a client with the daemon
```cpp
g_dbus_connection_call_sync (connection, bus_name, sysroot_objpath,
"org.projectatomic.rpmostree1.Sysroot", "RegisterClient", ...);
```
4. **OS Proxy Creation**: Get proxy to the OS interface
```cpp
glnx_unref_object RPMOSTreeOS *os_proxy = NULL;
if (!rpmostree_load_os_proxy (sysroot_proxy, opt_osname, cancellable, &os_proxy, error))
return FALSE;
```
### 4. D-Bus Method Invocation
**Legacy API Path** (`rpmostree_os_call_pkg_change_sync`):
```cpp
if (!rpmostree_os_call_pkg_change_sync (os_proxy, options, install_pkgs, uninstall_pkgs, NULL,
&transaction_address, NULL, cancellable, error))
return FALSE;
```
**New API Path** (`rpmostree_update_deployment`):
```cpp
if (!rpmostree_update_deployment (os_proxy, NULL, /* refspec */
NULL, /* revision */
install_pkgs, install_fileoverride_pkgs, uninstall_pkgs,
NULL, /* override replace */
NULL, /* override remove */
NULL, /* override reset */
NULL, /* local_repo_remote */
NULL, /* treefile */
options, &transaction_address, cancellable, error))
return FALSE;
```
## Daemon-Side Processing
### 5. D-Bus Method Handler
**File**: `src/daemon/rpmostreed-os.cxx`
**Steps**:
1. **Authorization Check**: Verify user permissions via Polkit
```cpp
else if (g_strcmp0 (method_name, "PkgChange") == 0) {
g_ptr_array_add (actions, (void *)"org.projectatomic.rpmostree1.install-uninstall-packages");
}
```
2. **Transaction Management**: Check for existing transactions or create new one
```cpp
if (!rpmostreed_sysroot_prep_for_txn (rsysroot, invocation, &transaction, &local_error))
return os_throw_dbus_invocation_error (invocation, &local_error);
```
3. **Transaction Creation**: Create appropriate transaction type
- For package changes: `rpmostreed_transaction_new_pkg_change()`
- For deployment updates: `rpmostreed_transaction_new_update_deployment()`
4. **Transaction Address Return**: Return D-Bus object path for transaction monitoring
```cpp
const char *client_address = rpmostreed_transaction_get_client_address (transaction);
rpmostree_os_complete_pkg_change (interface, invocation, client_address);
```
### 6. Transaction Processing
**File**: `src/daemon/rpmostreed-transaction.cxx`
**Steps**:
1. **Transaction State Management**: Track transaction progress and state
2. **Dependency Resolution**: Use libdnf to resolve package dependencies
3. **Package Download**: Download required RPM packages from repositories
4. **OSTree Integration**: Prepare for OSTree commit creation
## Core Package Management
### 7. DNF Integration (libdnf)
**Steps**:
1. **Repository Setup**: Initialize DNF context with configured repositories
```cpp
g_autoptr (DnfContext) dnfctx = dnf_context_new ();
```
2. **Package Resolution**: Resolve package names to specific RPM packages
```cpp
hy_autoquery HyQuery query = hy_query_create (dnf_context_get_sack (dnfctx));
hy_query_filter (query, HY_PKG_NAME, HY_EQ, package_name);
```
3. **Dependency Resolution**: Calculate full dependency tree
- Resolve all required dependencies
- Handle conflicts and alternatives
- Determine download order
4. **Package Download**: Download RPM files to local cache
- Use DNF's download infrastructure
- Verify package integrity
- Handle network failures and retries
### 8. OSTree Integration
**Steps**:
1. **Base Tree Preparation**: Get current OSTree deployment as base
```cpp
OstreeDeployment *booted = ostree_sysroot_get_booted_deployment (sysroot);
```
2. **Package Import**: Import downloaded RPMs into OSTree repository
- Extract RPM contents
- Apply to filesystem tree
- Handle file conflicts and replacements
3. **Commit Creation**: Create new OSTree commit with layered packages
```cpp
// Create new commit with package changes
ostree_repo_prepare_transaction (repo, NULL, NULL, error);
// ... package application logic ...
ostree_repo_commit_transaction (repo, NULL, error);
```
4. **Metadata Generation**: Generate commit metadata
- Package lists and versions
- Dependency information
- Origin and timestamp data
## Filesystem and Deployment
### 9. Filesystem Assembly
**Steps**:
1. **Base Tree Checkout**: Checkout base OSTree commit to temporary location
2. **Package Application**: Apply RPM contents to filesystem
- Extract files from RPMs
- Handle file permissions and ownership
- Apply package scripts (preinst, postinst)
3. **Layer Management**: Create layered filesystem structure
- `/usr` - Base system files (immutable)
- `/var` - Variable data (mutable)
- `/etc` - Configuration (merged)
- Package overlays in `/usr/lib/rpm-ostree/`
4. **Script Execution**: Run package installation scripts
- Pre-installation scripts
- Post-installation scripts
- Handle script failures and rollback
### 10. Deployment Management
**Steps**:
1. **Deployment Creation**: Create new OSTree deployment
```cpp
ostree_sysroot_deploy_tree (sysroot, osname, new_commit, ...);
```
2. **Boot Configuration**: Update bootloader configuration
- Generate new initramfs if needed
- Update kernel arguments
- Configure boot entries
3. **State Persistence**: Save deployment state
- Update deployment index
- Save package metadata
- Update rollback information
## Transaction Monitoring
### 11. Progress Reporting
**Steps**:
1. **Signal Emission**: Emit D-Bus signals for progress
```cpp
// Progress signals
rpmostree_transaction_emit_percent_progress (transaction, "Downloading packages", 50);
rpmostree_transaction_emit_message (transaction, "Installing htop-2.2.0-1.fc33.x86_64");
```
2. **Client Monitoring**: Client receives and displays progress
```cpp
// Client connects to transaction and monitors signals
rpmostree_transaction_client_run (invocation, sysroot_proxy, os_proxy, options, ...);
```
3. **Error Handling**: Handle failures and provide rollback
- Network failures during download
- Package conflicts
- Script execution failures
- OSTree commit failures
### 12. Transaction Completion
**Steps**:
1. **Success Path**:
- Mark transaction as successful
- Emit completion signals
- Clean up temporary files
- Update system state
2. **Failure Path**:
- Rollback to previous state
- Clean up partial changes
- Emit error signals
- Provide error details
3. **Reboot Handling**: If `--reboot` specified
```cpp
if (opt_reboot) {
// Schedule reboot after transaction completion
rpmostree_sysroot_deploy_tree (sysroot, osname, new_commit,
OSTREE_SYSROOT_DEPLOY_FLAGS_REBOOT, ...);
}
```
## Final Steps
### 13. System State Update
**Steps**:
1. **Deployment Activation**: Activate new deployment
- Update bootloader entries
- Set new deployment as default
- Preserve rollback deployment
2. **Cache Updates**: Update package metadata cache
- Refresh repository metadata
- Update package lists
- Cache dependency information
3. **Cleanup**: Remove temporary files and caches
- Clean downloaded RPMs
- Remove temporary directories
- Update system journal
### 14. User Feedback
**Steps**:
1. **Status Display**: Show final status
```bash
# Example output
Checking out packages...done
Running pre scripts...done
Running post scripts...done
Writing rpmdb...done
Writing OSTree commit...done
```
2. **Deployment Information**: Display deployment details
- New deployment checksum
- Package changes summary
- Reboot requirement (if applicable)
3. **Next Steps**: Provide guidance for user
- Reboot instructions if needed
- Package verification commands
- Rollback instructions
## Key Architectural Insights
### 1. **Client-Daemon Architecture**
- CLI client handles user interaction and D-Bus communication
- Daemon (rpm-ostreed) handles all privileged operations
- Clear separation of concerns and security boundaries
### 2. **Transaction-Based Design**
- All operations wrapped in transactions
- Atomic operations with rollback capability
- Progress monitoring and cancellation support
### 3. **Layered Filesystem Model**
- Base OSTree commit remains immutable
- Package changes applied as overlays
- Clear separation between system and user packages
### 4. **Dependency Management**
- Full dependency resolution via libdnf
- Handles complex dependency graphs
- Conflict resolution and alternatives
### 5. **Error Handling and Recovery**
- Comprehensive error handling at each stage
- Automatic rollback on failures
- Detailed error reporting and logging
This analysis reveals the sophisticated architecture of rpm-ostree, which combines the atomic deployment model of OSTree with the powerful package management capabilities of DNF, all orchestrated through a robust client-daemon architecture with comprehensive transaction management.