Skip to content

Commit b377c86

Browse files
committed
wip --soft-reboot=required
1 parent 3f2f38a commit b377c86

File tree

2 files changed

+98
-41
lines changed

2 files changed

+98
-41
lines changed

crates/lib/src/cli.rs

Lines changed: 96 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,12 @@ pub(crate) struct UpgradeOpts {
8080
#[clap(long, conflicts_with = "check")]
8181
pub(crate) apply: bool,
8282

83-
/// Queue a soft reboot after staging the deployment.
83+
/// Configure soft reboot behavior.
8484
///
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>,
8989

9090
#[clap(flatten)]
9191
pub(crate) progress: ProgressOptions,
@@ -106,12 +106,12 @@ pub(crate) struct SwitchOpts {
106106
#[clap(long)]
107107
pub(crate) apply: bool,
108108

109-
/// Queue a soft reboot after staging the deployment.
109+
/// Configure soft reboot behavior.
110110
///
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>,
115115

116116
/// The transport; e.g. oci, oci-archive, containers-storage. Defaults to `registry`.
117117
#[clap(long, default_value = "registry")]
@@ -157,12 +157,12 @@ pub(crate) struct RollbackOpts {
157157
#[clap(long)]
158158
pub(crate) apply: bool,
159159

160-
/// Queue a soft reboot after performing the rollback.
160+
/// Configure soft reboot behavior.
161161
///
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>,
166166
}
167167

168168
/// Perform an edit operation
@@ -188,6 +188,15 @@ pub(crate) enum OutputFormat {
188188
Json,
189189
}
190190

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+
191200
/// Perform an status operation
192201
#[derive(Debug, Parser, PartialEq, Eq)]
193202
pub(crate) struct StatusOpts {
@@ -781,6 +790,42 @@ fn prepare_soft_reboot(
781790
Ok(())
782791
}
783792

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+
784829
/// Perform a soft reboot for a staged deployment
785830
#[context("Soft reboot staged deployment")]
786831
fn soft_reboot_staged(sysroot: &crate::store::Storage) -> Result<()> {
@@ -914,11 +959,12 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
914959
.unwrap_or_default();
915960
if staged_unchanged {
916961
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+
)?;
922968
if opts.apply {
923969
crate::reboot::reboot()?;
924970
}
@@ -940,13 +986,16 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
940986
if changed {
941987
sysroot.update_mtime()?;
942988

943-
if opts.queue_soft_reboot {
989+
if opts.soft_reboot.is_some() {
944990
// At this point we have new staged deployment and the host definition has changed.
945991
// We need the updated host status before we check if we can prepare the soft-reboot.
946992
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+
)?;
950999
}
9511000

9521001
if opts.apply {
@@ -1024,13 +1073,16 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
10241073

10251074
sysroot.update_mtime()?;
10261075

1027-
if opts.queue_soft_reboot {
1076+
if opts.soft_reboot.is_some() {
10281077
// At this point we have staged the deployment and the host definition has changed.
10291078
// We need the updated host status before we check if we can prepare the soft-reboot.
10301079
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+
)?;
10341086
}
10351087

10361088
if opts.apply {
@@ -1046,20 +1098,25 @@ async fn rollback(opts: RollbackOpts) -> Result<()> {
10461098
let sysroot = &get_storage().await?;
10471099
crate::deploy::rollback(sysroot).await?;
10481100

1049-
if opts.queue_soft_reboot {
1101+
if opts.soft_reboot.is_some() {
10501102
// Get status of rollback deployment to check soft-reboot capability
10511103
let host = crate::status::get_status_require_booted(sysroot)?.2;
10521104

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+
)?;
10631120
}
10641121

10651122
if opts.apply {

tmt/tests/booted/test-soft-reboot.nu

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ RUN echo test content > /usr/share/testfile-for-soft-reboot.txt
3030

3131
assert (not ("/run/nextroot" | path exists))
3232

33-
bootc switch --queue-soft-reboot --transport containers-storage localhost/bootc-derived
33+
bootc switch --soft-reboot=auto --transport containers-storage localhost/bootc-derived
3434
let st = bootc status --json | from json
3535
assert $st.status.staged.softRebootCapable
3636

@@ -58,7 +58,7 @@ RUN echo 'kargs = ["foo1=bar2"]' | tee /usr/lib/bootc/kargs.d/00-foo1bar2.toml >
5858
# Build it
5959
podman build -t localhost/bootc-derived .
6060

61-
bootc update --queue-soft-reboot
61+
bootc upgrade --soft-reboot=auto
6262
let st = bootc status --json | from json
6363
# Should not be soft-reboot capable because of kargs diff
6464
assert (not $st.status.staged.softRebootCapable)

0 commit comments

Comments
 (0)