@@ -80,12 +80,12 @@ pub(crate) struct UpgradeOpts {
80
80
#[ clap( long, conflicts_with = "check" ) ]
81
81
pub ( crate ) apply : bool ,
82
82
83
- /// Queue a soft reboot after staging the deployment .
83
+ /// Configure soft reboot behavior .
84
84
///
85
- /// This will prepare the system for a soft reboot instead of a full reboot,
86
- /// which allows userspace to restart without rebooting the kernel .
87
- #[ clap( long, conflicts_with = "check" ) ]
88
- pub ( crate ) queue_soft_reboot : bool ,
85
+ /// 'required' will fail if soft reboot is not available.
86
+ /// 'auto' will use soft reboot if available, otherwise fall back to regular reboot .
87
+ #[ clap( long = "soft-reboot" , conflicts_with = "check" ) ]
88
+ pub ( crate ) soft_reboot : Option < SoftRebootMode > ,
89
89
90
90
#[ clap( flatten) ]
91
91
pub ( crate ) progress : ProgressOptions ,
@@ -106,12 +106,12 @@ pub(crate) struct SwitchOpts {
106
106
#[ clap( long) ]
107
107
pub ( crate ) apply : bool ,
108
108
109
- /// Queue a soft reboot after staging the deployment .
109
+ /// Configure soft reboot behavior .
110
110
///
111
- /// This will prepare the system for a soft reboot instead of a full reboot,
112
- /// which allows userspace to restart without rebooting the kernel .
113
- #[ clap( long) ]
114
- pub ( crate ) queue_soft_reboot : bool ,
111
+ /// 'required' will fail if soft reboot is not available.
112
+ /// 'auto' will use soft reboot if available, otherwise fall back to regular reboot .
113
+ #[ clap( long = "soft-reboot" ) ]
114
+ pub ( crate ) soft_reboot : Option < SoftRebootMode > ,
115
115
116
116
/// The transport; e.g. oci, oci-archive, containers-storage. Defaults to `registry`.
117
117
#[ clap( long, default_value = "registry" ) ]
@@ -157,12 +157,12 @@ pub(crate) struct RollbackOpts {
157
157
#[ clap( long) ]
158
158
pub ( crate ) apply : bool ,
159
159
160
- /// Queue a soft reboot after performing the rollback .
160
+ /// Configure soft reboot behavior .
161
161
///
162
- /// This will prepare the system for a soft reboot instead of a full reboot,
163
- /// which allows userspace to restart without rebooting the kernel .
164
- #[ clap( long) ]
165
- pub ( crate ) queue_soft_reboot : bool ,
162
+ /// 'required' will fail if soft reboot is not available.
163
+ /// 'auto' will use soft reboot if available, otherwise fall back to regular reboot .
164
+ #[ clap( long = "soft-reboot" ) ]
165
+ pub ( crate ) soft_reboot : Option < SoftRebootMode > ,
166
166
}
167
167
168
168
/// Perform an edit operation
@@ -188,6 +188,15 @@ pub(crate) enum OutputFormat {
188
188
Json ,
189
189
}
190
190
191
+ #[ derive( Debug , Clone , Copy , ValueEnum , PartialEq , Eq ) ]
192
+ #[ clap( rename_all = "lowercase" ) ]
193
+ pub ( crate ) enum SoftRebootMode {
194
+ /// Require a soft reboot; fail if not possible
195
+ Required ,
196
+ /// Automatically use soft reboot if possible, otherwise use regular reboot
197
+ Auto ,
198
+ }
199
+
191
200
/// Perform an status operation
192
201
#[ derive( Debug , Parser , PartialEq , Eq ) ]
193
202
pub ( crate ) struct StatusOpts {
@@ -781,6 +790,42 @@ fn prepare_soft_reboot(
781
790
Ok ( ( ) )
782
791
}
783
792
793
+ /// Handle soft reboot based on the configured mode
794
+ #[ context( "Handling soft reboot" ) ]
795
+ fn handle_soft_reboot < F > (
796
+ soft_reboot_mode : Option < SoftRebootMode > ,
797
+ entry : Option < & crate :: spec:: BootEntry > ,
798
+ deployment_type : & str ,
799
+ execute_soft_reboot : F ,
800
+ ) -> Result < ( ) >
801
+ where
802
+ F : FnOnce ( ) -> Result < ( ) > ,
803
+ {
804
+ let Some ( mode) = soft_reboot_mode else {
805
+ return Ok ( ( ) ) ;
806
+ } ;
807
+
808
+ let can_soft_reboot = has_soft_reboot_capability ( entry) ;
809
+ match mode {
810
+ SoftRebootMode :: Required => {
811
+ if can_soft_reboot {
812
+ execute_soft_reboot ( ) ?;
813
+ } else {
814
+ anyhow:: bail!(
815
+ "Soft reboot was required but {} deployment is not soft-reboot capable" ,
816
+ deployment_type
817
+ ) ;
818
+ }
819
+ }
820
+ SoftRebootMode :: Auto => {
821
+ if can_soft_reboot {
822
+ execute_soft_reboot ( ) ?;
823
+ }
824
+ }
825
+ }
826
+ Ok ( ( ) )
827
+ }
828
+
784
829
/// Perform a soft reboot for a staged deployment
785
830
#[ context( "Soft reboot staged deployment" ) ]
786
831
fn soft_reboot_staged ( sysroot : & crate :: store:: Storage ) -> Result < ( ) > {
@@ -914,11 +959,12 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
914
959
. unwrap_or_default ( ) ;
915
960
if staged_unchanged {
916
961
println ! ( "Staged update present, not changed." ) ;
917
- if opts. queue_soft_reboot {
918
- if has_soft_reboot_capability ( host. status . staged . as_ref ( ) ) {
919
- soft_reboot_staged ( sysroot) ?;
920
- }
921
- }
962
+ handle_soft_reboot (
963
+ opts. soft_reboot ,
964
+ host. status . staged . as_ref ( ) ,
965
+ "staged" ,
966
+ || soft_reboot_staged ( sysroot) ,
967
+ ) ?;
922
968
if opts. apply {
923
969
crate :: reboot:: reboot ( ) ?;
924
970
}
@@ -940,13 +986,16 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
940
986
if changed {
941
987
sysroot. update_mtime ( ) ?;
942
988
943
- if opts. queue_soft_reboot {
989
+ if opts. soft_reboot . is_some ( ) {
944
990
// At this point we have new staged deployment and the host definition has changed.
945
991
// We need the updated host status before we check if we can prepare the soft-reboot.
946
992
let updated_host = crate :: status:: get_status ( sysroot, Some ( & booted_deployment) ) ?. 1 ;
947
- if has_soft_reboot_capability ( updated_host. status . staged . as_ref ( ) ) {
948
- soft_reboot_staged ( sysroot) ?;
949
- }
993
+ handle_soft_reboot (
994
+ opts. soft_reboot ,
995
+ updated_host. status . staged . as_ref ( ) ,
996
+ "staged" ,
997
+ || soft_reboot_staged ( sysroot) ,
998
+ ) ?;
950
999
}
951
1000
952
1001
if opts. apply {
@@ -1024,13 +1073,16 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
1024
1073
1025
1074
sysroot. update_mtime ( ) ?;
1026
1075
1027
- if opts. queue_soft_reboot {
1076
+ if opts. soft_reboot . is_some ( ) {
1028
1077
// At this point we have staged the deployment and the host definition has changed.
1029
1078
// We need the updated host status before we check if we can prepare the soft-reboot.
1030
1079
let updated_host = crate :: status:: get_status ( sysroot, Some ( & booted_deployment) ) ?. 1 ;
1031
- if has_soft_reboot_capability ( updated_host. status . staged . as_ref ( ) ) {
1032
- soft_reboot_staged ( sysroot) ?;
1033
- }
1080
+ handle_soft_reboot (
1081
+ opts. soft_reboot ,
1082
+ updated_host. status . staged . as_ref ( ) ,
1083
+ "staged" ,
1084
+ || soft_reboot_staged ( sysroot) ,
1085
+ ) ?;
1034
1086
}
1035
1087
1036
1088
if opts. apply {
@@ -1046,20 +1098,25 @@ async fn rollback(opts: RollbackOpts) -> Result<()> {
1046
1098
let sysroot = & get_storage ( ) . await ?;
1047
1099
crate :: deploy:: rollback ( sysroot) . await ?;
1048
1100
1049
- if opts. queue_soft_reboot {
1101
+ if opts. soft_reboot . is_some ( ) {
1050
1102
// Get status of rollback deployment to check soft-reboot capability
1051
1103
let host = crate :: status:: get_status_require_booted ( sysroot) ?. 2 ;
1052
1104
1053
- if has_soft_reboot_capability ( host. status . rollback . as_ref ( ) ) {
1054
- println ! ( "Rollback deployment is soft-reboot capable, preparing for soft-reboot..." ) ;
1055
-
1056
- let deployments_list = sysroot. deployments ( ) ;
1057
- let target_deployment = deployments_list
1058
- . first ( )
1059
- . ok_or_else ( || anyhow:: anyhow!( "No rollback deployment found!" ) ) ?;
1060
-
1061
- prepare_soft_reboot ( sysroot, target_deployment) ?;
1062
- }
1105
+ handle_soft_reboot (
1106
+ opts. soft_reboot ,
1107
+ host. status . rollback . as_ref ( ) ,
1108
+ "rollback" ,
1109
+ || {
1110
+ println ! (
1111
+ "Rollback deployment is soft-reboot capable, preparing for soft-reboot..."
1112
+ ) ;
1113
+ let deployments_list = sysroot. deployments ( ) ;
1114
+ let target_deployment = deployments_list
1115
+ . first ( )
1116
+ . ok_or_else ( || anyhow:: anyhow!( "No rollback deployment found!" ) ) ?;
1117
+ prepare_soft_reboot ( sysroot, target_deployment)
1118
+ } ,
1119
+ ) ?;
1063
1120
}
1064
1121
1065
1122
if opts. apply {
0 commit comments