Skip to content

Commit 2f3df69

Browse files
cli/composefs: Implement status cmd for compoesfs booted system
This is currently WIP, as it only shows the currently booted image in use and not any staged or rollback deployments. Signed-off-by: Pragyan Poudyal <[email protected]>
1 parent d25c78d commit 2f3df69

File tree

3 files changed

+88
-3
lines changed

3 files changed

+88
-3
lines changed

lib/src/spec.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,15 @@ pub struct BootEntryOstree {
164164
pub deploy_serial: u32,
165165
}
166166

167+
168+
/// A bootable entry
169+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
170+
#[serde(rename_all = "camelCase")]
171+
pub struct BootEntryComposefs {
172+
/// The erofs verity
173+
pub verity: String,
174+
}
175+
167176
/// A bootable entry
168177
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
169178
#[serde(rename_all = "camelCase")]
@@ -181,6 +190,8 @@ pub struct BootEntry {
181190
pub store: Option<Store>,
182191
/// If this boot entry is ostree based, the corresponding state
183192
pub ostree: Option<BootEntryOstree>,
193+
/// If this boot entry is composefs based, the corresponding state
194+
pub composefs: Option<BootEntryComposefs>,
184195
}
185196

186197
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
@@ -520,6 +531,7 @@ mod tests {
520531
pinned: false,
521532
store: None,
522533
ostree: None,
534+
composefs: None,
523535
}
524536
}
525537

lib/src/status.rs

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use fn_error_context::context;
1010
use ostree::glib;
1111
use ostree_container::OstreeImageReference;
1212
use ostree_ext::container as ostree_container;
13+
use ostree_ext::container_utils::composefs_booted;
1314
use ostree_ext::container_utils::ostree_booted;
1415
use ostree_ext::keyfileext::KeyFileExt;
1516
use ostree_ext::oci_spec;
@@ -156,6 +157,7 @@ fn boot_entry_from_deployment(
156157
deploy_serial: deployment.deployserial().try_into().unwrap(),
157158
stateroot: deployment.stateroot().into(),
158159
}),
160+
composefs: None,
159161
};
160162
Ok(r)
161163
}
@@ -292,13 +294,54 @@ pub(crate) async fn status(opts: super::cli::StatusOpts) -> Result<()> {
292294
0 | 1 => {}
293295
o => anyhow::bail!("Unsupported format version: {o}"),
294296
};
295-
let mut host = if !ostree_booted()? {
296-
Default::default()
297-
} else {
297+
let mut host = if ostree_booted()? {
298298
let sysroot = super::cli::get_storage().await?;
299299
let booted_deployment = sysroot.booted_deployment();
300300
let (_deployments, host) = get_status(&sysroot, booted_deployment.as_ref())?;
301301
host
302+
} else if composefs_booted()? {
303+
let dir_contents = std::fs::read_dir("/sysroot/composefs/images")?;
304+
305+
let host_spec = HostSpec {
306+
image: Some(ImageReference {
307+
image: "".into(),
308+
transport: "".into(),
309+
signature: None,
310+
}),
311+
boot_order: BootOrder::Default,
312+
};
313+
314+
let mut host = Host::new(host_spec);
315+
316+
let cmdline = crate::kernel::parse_cmdline()?;
317+
let booted = cmdline.iter().find_map(|x| x.strip_prefix("composefs="));
318+
319+
let Some(booted) = booted else {
320+
anyhow::bail!("Failed to find composefs parameter in kernel cmdline");
321+
};
322+
323+
host.status = HostStatus {
324+
staged: None,
325+
booted: Some(BootEntry {
326+
image: None,
327+
cached_update: None,
328+
incompatible: false,
329+
pinned: false,
330+
store: None,
331+
ostree: None,
332+
composefs: Some(crate::spec::BootEntryComposefs {
333+
verity: booted.into(),
334+
}),
335+
}),
336+
other_deployments: vec![],
337+
rollback: None,
338+
rollback_queued: false,
339+
ty: None,
340+
};
341+
342+
host
343+
} else {
344+
Default::default()
302345
};
303346

304347
// We could support querying the staged or rollback deployments
@@ -506,6 +549,27 @@ fn human_render_slot_ostree(
506549
Ok(())
507550
}
508551

552+
/// Output a rendering of a non-container composefs boot entry.
553+
fn human_render_slot_composefs(
554+
mut out: impl Write,
555+
slot: Slot,
556+
entry: &crate::spec::BootEntry,
557+
erofs_verity: &str,
558+
) -> Result<()> {
559+
// TODO consider rendering more ostree stuff here like rpm-ostree status does
560+
let prefix = match slot {
561+
Slot::Staged => " Staged composefs".into(),
562+
Slot::Booted => format!("{} Booted composefs", crate::glyph::Glyph::BlackCircle),
563+
Slot::Rollback => " Rollback composefs".into(),
564+
};
565+
let prefix_len = prefix.len();
566+
writeln!(out, "{prefix}")?;
567+
write_row_name(&mut out, "Commit", prefix_len)?;
568+
writeln!(out, "{erofs_verity}")?;
569+
tracing::debug!("pinned={}", entry.pinned);
570+
Ok(())
571+
}
572+
509573
fn human_readable_output_booted(mut out: impl Write, host: &Host, verbose: bool) -> Result<()> {
510574
let mut first = true;
511575
for (slot_name, status) in [
@@ -529,6 +593,8 @@ fn human_readable_output_booted(mut out: impl Write, host: &Host, verbose: bool)
529593
&ostree.checksum,
530594
verbose,
531595
)?;
596+
} else if let Some(composefs) = &host_status.composefs {
597+
human_render_slot_composefs(&mut out, slot_name, host_status, &composefs.verity)?;
532598
} else {
533599
writeln!(out, "Current {slot_name} state is unknown")?;
534600
}

ostree-ext/src/container_utils.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ pub fn ostree_booted() -> io::Result<bool> {
7777
Path::new(&format!("/{OSTREE_BOOTED}")).try_exists()
7878
}
7979

80+
81+
/// Returns true if the system appears to have been booted with composefs.
82+
pub fn composefs_booted() -> io::Result<bool> {
83+
let cmdline = std::fs::read_to_string("/proc/cmdline")?;
84+
Ok(cmdline.contains("composefs="))
85+
}
86+
8087
/// Returns true if the target root appears to have been booted via ostree.
8188
pub fn is_ostree_booted_in(rootfs: &Dir) -> io::Result<bool> {
8289
rootfs.try_exists(OSTREE_BOOTED)

0 commit comments

Comments
 (0)