11use anyhow:: { Context , Result , anyhow, bail} ;
2+ use std:: path:: Path ;
23use std:: process:: Command ;
34use std:: str;
45
56use crate :: grub:: get_boot_counter;
67
8+ /// Detects if the system is managed by bootc or is a rpm-ostree system
9+ fn detect_os_deployment ( ) -> Option < & ' static str > {
10+ // 1. Check if this is a bootc-managed host.
11+ if let Ok ( output) = Command :: new ( "bootc" )
12+ . args ( [ "status" , "--booted" , "--json" ] )
13+ . output ( )
14+ {
15+ if output. status . success ( ) {
16+ let stdout_str = String :: from_utf8_lossy ( & output. stdout ) ;
17+ // Check for the key-value pair as a substring. This is less robust
18+ // than proper JSON parsing but avoids the external dependency.
19+ if stdout_str. contains ( r#""type": "bootcHost""# ) {
20+ log:: info!( "System detected as bootc-managed host." ) ;
21+ return Some ( "bootc" ) ;
22+ }
23+ }
24+ }
25+
26+ // 2. If not bootc, check if it's an ostree-based OS by looking for /run/ostree-booted.
27+ if Path :: new ( "/run/ostree-booted" ) . exists ( ) {
28+ log:: info!( "System detected as ostree-based (via /run/ostree-booted)." ) ;
29+ return Some ( "rpm-ostree" ) ;
30+ }
31+
32+ // 3. If neither check passes, the deployment type is unsupported.
33+ log:: warn!( "System is neither bootc nor a known ostree variant." ) ;
34+ None
35+ }
36+
737/// reboots the system if boot_counter is greater than 0 or can be forced too
838pub fn handle_reboot ( force : bool ) -> Result < ( ) > {
939 if !force {
@@ -17,7 +47,7 @@ pub fn handle_reboot(force: bool) -> Result<()> {
1747 Ok ( ( ) )
1848}
1949
20- /// rollback to previous deployment if boot counter is less than 0
50+ /// Rollback to the previous deployment if the boot counter allows.
2151pub fn handle_rollback ( ) -> Result < ( ) > {
2252 let boot_counter = get_boot_counter ( "/boot/grub2/grubenv" ) ?;
2353
@@ -28,17 +58,30 @@ pub fn handle_rollback() -> Result<()> {
2858 }
2959 // Proceed with rollback if boot_counter is <= 0
3060 Some ( counter) if counter <= 0 => {
31- log:: info!( "Greenboot will now attempt to rollback to previous deployment" ) ;
32- let status = Command :: new ( "bootc" )
33- . arg ( "rollback" )
34- . status ( )
35- . context ( "Failed to execute bootc rollback" ) ?;
36- if !status. success ( ) {
37- bail ! ( "Rollback error: {}" , status) ;
61+ log:: info!( "Greenboot will now attempt to rollback to a previous deployment." ) ;
62+ if let Some ( deployment_cmd) = detect_os_deployment ( ) {
63+ log:: info!(
64+ "Deployment manager '{}' detected, attempting rollback." ,
65+ deployment_cmd
66+ ) ;
67+ let status = Command :: new ( deployment_cmd)
68+ . arg ( "rollback" )
69+ . status ( )
70+ . context ( format ! ( "Failed to execute '{} rollback'" , deployment_cmd) ) ?;
71+
72+ if !status. success ( ) {
73+ bail ! (
74+ "Rollback with '{}' failed with status: {}" ,
75+ deployment_cmd,
76+ status
77+ ) ;
78+ }
79+ } else {
80+ bail ! ( "Rollback only supported in bootc or rpm-ostree environment." ) ;
3881 }
3982 Ok ( ( ) )
4083 }
41- // Reject if boot_counter is > 0 with the actual value
84+ // Reject if boot_counter is > 0
4285 Some ( counter) => bail ! ( "Rollback not initiated as boot_counter is {}" , counter) ,
4386 }
4487}
0 commit comments