# πŸ” **rpm-ostree vs rpm-ostreed: Responsibility Analysis** ## πŸ“‹ **Overview** This document analyzes the separation of responsibilities between `rpm-ostree` (the CLI client) and `rpm-ostreed` (the system daemon) based on examination of the rpm-ostree source code. Understanding this separation is crucial for implementing a similar architecture in apt-ostree. ## πŸ—οΈ **Architecture Overview** ### **Component Structure** ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ rpm-ostree β”‚ β”‚ DBus Layer β”‚ β”‚ rpm-ostreed β”‚ β”‚ (CLI Client) │◄──►│ (Communication)│◄──►│ (System Daemon)β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β€’ Command Line β”‚ β”‚ β€’ Client Proxy β”‚ β”‚ β€’ OSTree Ops β”‚ β”‚ β€’ User Interfaceβ”‚ β”‚ β€’ Signal Handlerβ”‚ β”‚ β€’ Package Mgmt β”‚ β”‚ β€’ Progress Displayβ”‚ β”‚ β€’ Error Handlingβ”‚ β”‚ β€’ Transactions β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### **Key Design Principles** 1. **Separation of Concerns**: CLI handles user interaction, daemon handles system operations 2. **Privilege Isolation**: Daemon runs with elevated privileges, CLI runs as user 3. **Transaction Management**: Daemon manages long-running operations, CLI monitors progress 4. **Fallback Support**: CLI can operate without daemon for read-only operations ## πŸ” **Detailed Responsibility Analysis** ### **1. rpm-ostree (CLI Client) Responsibilities** #### **Command Line Interface** ```cpp // From libmain.cxx - Command registration and dispatch static RpmOstreeCommand commands[] = { { "compose", RPM_OSTREE_BUILTIN_FLAG_LOCAL_CMD | RPM_OSTREE_BUILTIN_FLAG_REQUIRES_ROOT, "Commands to compose a tree", rpmostree_builtin_compose }, { "status", (RpmOstreeBuiltinFlags)0, "Get the version of the booted system", rpmostree_builtin_status }, { "upgrade", RPM_OSTREE_BUILTIN_FLAG_SUPPORTS_PKG_INSTALLS, "Perform a system upgrade", rpmostree_builtin_upgrade }, { "install", RPM_OSTREE_BUILTIN_FLAG_CONTAINER_CAPABLE, "Overlay additional packages", rpmostree_builtin_install }, // ... more commands }; ``` **Responsibilities**: - **Command parsing** and argument validation - **Option handling** and help display - **Command dispatch** to appropriate builtin functions - **User interface** and output formatting #### **DBus Client Communication** ```cpp // From rpmostree-clientlib.cxx - Client-side DBus handling static gboolean app_load_sysroot_impl (const char *sysroot, GCancellable *cancellable, GDBusConnection **out_conn, GError **error) { // Start daemon if not running ROSCXX_TRY (client_start_daemon (), error); // Connect to system bus g_autoptr (GDBusConnection) connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, cancellable, error); // Register as client if (uid == 0 || sd_session_is_active (session_id) == 1) { rpmostree_sysroot_call_register_client (sysroot_proxy, options, NULL, NULL); } } ``` **Responsibilities**: - **DBus connection** establishment and management - **Client registration** with daemon - **Method invocation** on daemon interfaces - **Signal handling** for progress updates - **Error handling** and retry logic #### **Progress Monitoring and Display** ```cpp // From rpmostree-builtin-status.cxx - Status display static void print_deployment (RpmOstreeDeployment *deployment, gboolean verbose, gboolean only_booted, guint textarea_width) { // Format and display deployment information g_print ("%s %s %s %s\n", deployment->osname, deployment->checksum, deployment->version, deployment->timestamp); } ``` **Responsibilities**: - **Progress display** during long operations - **Status reporting** and user feedback - **Output formatting** (text, JSON, etc.) - **Error message** presentation #### **Fallback Operations** ```cpp // From rpmostree-builtin-status.cxx - Fallback when daemon unavailable static gboolean rpmostree_builtin_status (int argc, char **argv, RpmOstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error) { // Try daemon first, fallback to direct OSTree if needed if (rpmostree_client_connection_new (invocation, cancellable, &connection, error)) { // Use daemon for status return get_status_via_daemon (connection, invocation, cancellable, error); } else { // Fallback to direct OSTree operations return get_status_direct (invocation, cancellable, error); } } ``` **Responsibilities**: - **Fallback logic** when daemon unavailable - **Direct OSTree operations** for read-only tasks - **Graceful degradation** of functionality - **User notification** of limited capabilities ### **2. rpm-ostreed (Daemon) Responsibilities** #### **System State Management** ```cpp // From rpmostreed-daemon.cxx - Daemon state management struct _RpmostreedDaemon { GObject parent_instance; GHashTable *bus_clients; // Active client tracking gboolean running; // Daemon running state gboolean rebooting; // System reboot state RpmostreedSysroot *sysroot; // OSTree sysroot management gchar *sysroot_path; // System root path // Configuration settings guint idle_exit_timeout; // Auto-exit timeout RpmostreedAutomaticUpdatePolicy auto_update_policy; // Update policy gboolean lock_layering; // Package layering lock gboolean disable_recommends; // Recommends handling // DBus infrastructure GDBusConnection *connection; // DBus connection GDBusObjectManagerServer *object_manager; // Object management // Async runtime std::optional> tokio_handle; }; ``` **Responsibilities**: - **Global state** management and persistence - **Configuration** loading and validation - **Client lifecycle** management - **System monitoring** and health checks #### **OSTree Operations** ```cpp // From rpmostreed-sysroot.cxx - OSTree system management struct _RpmostreedSysroot { RPMOSTreeSysrootSkeleton parent_instance; OstreeSysroot *ot_sysroot; // OSTree sysroot object OstreeRepo *repo; // OSTree repository struct stat repo_last_stat; // Repository stat cache RpmostreedTransaction *transaction; // Active transaction guint close_transaction_timeout_id; // Transaction timeout PolkitAuthority *authority; // PolicyKit authority gboolean on_session_bus; // Session bus flag GHashTable *os_interfaces; // OS interface objects GHashTable *osexperimental_interfaces; // Experimental interfaces GFileMonitor *monitor; // Filesystem monitoring guint sig_changed; // Change signal handler }; ``` **Responsibilities**: - **OSTree repository** management and operations - **Deployment** creation, modification, and removal - **Filesystem** operations and staging - **Boot configuration** management - **System updates** and rollbacks #### **Transaction Management** ```cpp // From rpmostreed-transaction.cxx - Transaction lifecycle struct _RpmostreedTransactionPrivate { GDBusMethodInvocation *invocation; // DBus method invocation gboolean executed; // Transaction completion state GCancellable *cancellable; // Cancellation support // System state during transaction char *sysroot_path; // Sysroot path OstreeSysroot *sysroot; // OSTree sysroot gboolean sysroot_locked; // Sysroot lock state // Client tracking char *client_description; // Client description char *agent_id; // Client agent ID char *sd_unit; // Systemd unit // Progress tracking gint64 last_progress_journal; // Progress journal timestamp gboolean redirect_output; // Output redirection flag // Peer connections GDBusServer *server; // DBus server GHashTable *peer_connections; // Client connections // Completion state GVariant *finished_params; // Completion parameters guint watch_id; // Watch identifier }; ``` **Responsibilities**: - **Transaction lifecycle** management - **Atomic operation** execution - **Progress tracking** and reporting - **Rollback** and error recovery - **Client communication** during operations #### **Security and Privilege Management** ```cpp // From rpmostreed-sysroot.cxx - Security integration static void rpmostreed_sysroot_iface_init (RPMOSTreeSysrootIface *iface) { iface->handle_reload = rpmostreed_sysroot_handle_reload; iface->handle_reload_config = rpmostreed_sysroot_handle_reload_config; iface->handle_get_os = rpmostreed_sysroot_handle_get_os; } static gboolean rpmostreed_sysroot_handle_get_os (RPMOSTreeSysroot *skeleton, GDBusMethodInvocation *invocation, const char *name) { // Check authorization before allowing OS access if (!rpmostreed_sysroot_check_authorization (self, invocation, "org.projectatomic.rpmostree1.reload-daemon")) { return FALSE; } // Proceed with OS access rpmostreed_sysroot_complete_get_os (skeleton, invocation, object_path); return TRUE; } ``` **Responsibilities**: - **PolicyKit integration** and authorization - **Privilege escalation** management - **Access control** and security policies - **Audit logging** and security events ## πŸ”„ **Communication Flow** ### **1. Command Execution Flow** ``` User Command β†’ CLI Parsing β†’ DBus Request β†’ Daemon Processing β†’ Progress Updates β†’ Completion ``` **Detailed Flow**: 1. **User enters command** (e.g., `rpm-ostree install package`) 2. **CLI parses command** and validates arguments 3. **CLI connects to daemon** via DBus 4. **CLI registers as client** with daemon 5. **CLI invokes daemon method** (e.g., `PkgChange`) 6. **Daemon creates transaction** and returns transaction path 7. **CLI monitors transaction** via DBus signals 8. **Daemon executes operations** and emits progress 9. **CLI displays progress** to user 10. **Daemon completes transaction** and emits completion signal 11. **CLI displays results** and exits ### **2. Signal Handling Flow** ``` Daemon Event β†’ DBus Signal β†’ Client Handler β†’ User Display ``` **Signal Types**: - **`Message`**: Text messages and status updates - **`TaskBegin`/`TaskEnd`**: Task start/completion notifications - **`PercentProgress`**: Progress percentage updates - **`DownloadProgress`**: Download progress details - **`Finished`**: Transaction completion notification ## πŸ“Š **Responsibility Matrix** | Responsibility | CLI (rpm-ostree) | Daemon (rpm-ostreed) | Notes | |----------------|-------------------|----------------------|-------| | **Command Parsing** | βœ… Primary | ❌ None | CLI handles all user input | | **Argument Validation** | βœ… Primary | ❌ None | CLI validates before sending | | **DBus Communication** | βœ… Client | βœ… Server | Both sides of communication | | **OSTree Operations** | ❌ None | βœ… Primary | Daemon has exclusive access | | **Package Management** | ❌ None | βœ… Primary | Daemon handles RPM/OSTree | | **Transaction Management** | ❌ None | βœ… Primary | Daemon manages lifecycle | | **Progress Reporting** | βœ… Display | βœ… Generation | Daemon generates, CLI displays | | **Error Handling** | βœ… User-facing | βœ… System-level | Different error contexts | | **Security** | ❌ None | βœ… Primary | Daemon handles authorization | | **Configuration** | βœ… Reading | βœ… Reading/Writing | Daemon can modify system | | **Fallback Operations** | βœ… Primary | ❌ None | CLI handles when daemon unavailable | ## πŸš€ **apt-ostree Implementation Strategy** ### **1. CLI Client (`apt-ostree`)** ```rust // src/main.rs - CLI entry point #[tokio::main] async fn main() -> Result<(), Box> { let args: Vec = env::args().collect(); match args.get(1).map(|s| s.as_str()) { Some("status") => show_system_status().await?, Some("install") => install_packages(&args[2..]).await?, Some("upgrade") => upgrade_system().await?, Some("rollback") => rollback_system().await?, Some("--help") | Some("-h") => show_usage(), Some("--version") | Some("-V") => show_version(), _ => { eprintln!("Unknown command. Use --help for usage information."); std::process::exit(1); } } Ok(()) } async fn install_packages(packages: &[String]) -> Result<(), Error> { // Try daemon first if let Ok(client) = AptOstreeClient::new().await { let transaction_id = client.create_transaction().await?; let success = client.install_packages(&transaction_id, packages.to_vec()).await?; if success { println!("βœ… Packages installed successfully!"); } else { println!("❌ Package installation failed"); } } else { // Fallback to direct operations (limited functionality) println!("⚠️ Daemon unavailable, using limited fallback mode"); install_packages_direct(packages).await?; } Ok(()) } ``` ### **2. Daemon (`apt-ostreed`)** ```rust // daemon/src/main.rs - Daemon entry point #[tokio::main] async fn main() -> Result<(), Box> { // Initialize logging tracing_subscriber::fmt::init(); // Create daemon instance let daemon = Arc::new(AptOstreeDaemon::new()?); // Set up DBus connection let _connection = ConnectionBuilder::system()? .name("org.projectatomic.aptostree1")? .serve_at("/org/projectatomic/aptostree1/Sysroot", daemon.clone())? .serve_at("/org/projectatomic/aptostree1/OS/debian", daemon.clone())? .build() .await?; // Keep daemon running loop { tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; } } // DBus interface implementation #[dbus_interface(name = "org.projectatomic.aptostree1.Sysroot")] impl AptOstreeDaemon { async fn install_packages( &self, transaction_id: &str, packages: Vec, ) -> zbus::fdo::Result { // Check authorization if !self.security_manager.check_package_operation(self.get_user_id().await?).await? { return Err(zbus::fdo::Error::PermissionDenied("Not authorized".into())); } // Create and execute transaction let mut transaction = self.get_transaction(transaction_id).await?; transaction.add_operation(Operation::InstallPackage { packages }); match transaction.execute(self).await { Ok(()) => Ok(true), Err(_) => Ok(false), } } } ``` ## 🎯 **Key Implementation Principles** ### **1. Clear Separation of Concerns** - **CLI**: User interface, command parsing, progress display - **Daemon**: System operations, OSTree management, security ### **2. Graceful Degradation** - **Primary mode**: Full functionality via daemon - **Fallback mode**: Limited functionality when daemon unavailable ### **3. Security by Design** - **Privilege isolation**: Daemon handles privileged operations - **Authorization**: PolicyKit integration for all system changes - **Sandboxing**: Package script execution in controlled environment ### **4. Transaction Safety** - **Atomic operations**: All changes are atomic - **Rollback support**: Automatic rollback on failure - **Progress tracking**: Real-time operation monitoring ### **5. Performance Optimization** - **Caching**: Intelligent caching of deployment and package information - **Parallel operations**: Concurrent package processing where possible - **Resource management**: Efficient memory and disk usage This analysis provides the foundation for implementing a production-ready apt-ostree system that maintains the proven architecture of rpm-ostree while adapting to the Debian/Ubuntu ecosystem.