Skip to content

Commit 9a8fee3

Browse files
committed
feat(status): display pinned deployments
Part of #904 Displays pinned deployments as part of "bootc status". Includes unit tests to ensure correct parsing of the pinned deployments, and that they are displayed in human readable formats correctly. Signed-off-by: Robert Sturla <robertsturla@outlook.com>
1 parent 93b22f4 commit 9a8fee3

File tree

3 files changed

+113
-13
lines changed

3 files changed

+113
-13
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
apiVersion: org.containers.bootc/v1alpha1
2+
kind: BootcHost
3+
metadata:
4+
name: host
5+
spec:
6+
image:
7+
image: quay.io/centos-bootc/centos-bootc:stream9
8+
transport: registry
9+
bootOrder: default
10+
status:
11+
staged: null
12+
booted:
13+
image:
14+
image:
15+
image: quay.io/centos-bootc/centos-bootc:stream9
16+
transport: registry
17+
architecture: arm64
18+
version: stream9.20240807.0
19+
timestamp: null
20+
imageDigest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38
21+
cachedUpdate: null
22+
incompatible: false
23+
pinned: true
24+
ostree:
25+
checksum: 439f6bd2e2361bee292c1f31840d798c5ac5ba76483b8021dc9f7b0164ac0f48
26+
deploySerial: 0
27+
otherDeployments:
28+
- image:
29+
image:
30+
image: quay.io/centos-bootc/centos-bootc:stream9
31+
transport: registry
32+
version: stream9.20240807.0
33+
timestamp: null
34+
imageDigest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b37
35+
architecture: arm64
36+
cachedUpdate: null
37+
incompatible: false
38+
pinned: true
39+
ostree:
40+
checksum: 99b2cc3b6edce9ebaef6a6076effa5ee3e1dcff3523016ffc94a1b27c6c67e12
41+
deploySerial: 0
42+
rollback: null
43+
rollbackQueued: false
44+
type: bootcHost

lib/src/spec.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ pub struct HostStatus {
154154
pub booted: Option<BootEntry>,
155155
/// The previously booted image
156156
pub rollback: Option<BootEntry>,
157+
/// Other deployments (i.e. pinned)
158+
#[serde(skip_serializing_if = "Vec::is_empty")]
159+
#[serde(default)]
160+
pub other_deployments: Vec<BootEntry>,
157161
/// Set to true if the rollback entry is queued for the next boot.
158162
#[serde(default)]
159163
pub rollback_queued: bool,

lib/src/status.rs

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,12 @@ pub(crate) fn get_status(
253253
.map(|d| boot_entry_from_deployment(sysroot, d))
254254
.transpose()
255255
.context("Rollback deployment")?;
256+
let other_deployments = deployments
257+
.other
258+
.iter()
259+
.map(|d| boot_entry_from_deployment(sysroot, d))
260+
.collect::<Result<Vec<_>>>()
261+
.context("Other deployments")?;
256262
let spec = staged
257263
.as_ref()
258264
.or(booted.as_ref())
@@ -279,6 +285,7 @@ pub(crate) fn get_status(
279285
staged,
280286
booted,
281287
rollback,
288+
other_deployments,
282289
rollback_queued,
283290
ty,
284291
};
@@ -361,7 +368,7 @@ fn write_row_name(mut out: impl Write, s: &str, prefix_len: usize) -> Result<()>
361368
/// Write the data for a container image based status.
362369
fn human_render_slot(
363370
mut out: impl Write,
364-
slot: Slot,
371+
slot: Option<Slot>,
365372
entry: &crate::spec::BootEntry,
366373
image: &crate::spec::ImageStatus,
367374
) -> Result<()> {
@@ -375,9 +382,10 @@ fn human_render_slot(
375382
Cow::Owned(format!("{transport}:{imagename}"))
376383
};
377384
let prefix = match slot {
378-
Slot::Staged => " Staged image".into(),
379-
Slot::Booted => format!("{} Booted image", crate::glyph::Glyph::BlackCircle),
380-
Slot::Rollback => " Rollback image".into(),
385+
Some(Slot::Staged) => " Staged image".into(),
386+
Some(Slot::Booted) => format!("{} Booted image", crate::glyph::Glyph::BlackCircle),
387+
Some(Slot::Rollback) => " Rollback image".into(),
388+
_ => " Other image".into(),
381389
};
382390
let prefix_len = prefix.chars().count();
383391
writeln!(out, "{prefix}: {imageref}")?;
@@ -408,6 +416,11 @@ fn human_render_slot(
408416
writeln!(out, "{timestamp}")?;
409417
}
410418

419+
if entry.pinned {
420+
write_row_name(&mut out, "Pinned", prefix_len)?;
421+
writeln!(out, "yes")?;
422+
}
423+
411424
tracing::debug!("pinned={}", entry.pinned);
412425

413426
Ok(())
@@ -416,20 +429,27 @@ fn human_render_slot(
416429
/// Output a rendering of a non-container boot entry.
417430
fn human_render_slot_ostree(
418431
mut out: impl Write,
419-
slot: Slot,
432+
slot: Option<Slot>,
420433
entry: &crate::spec::BootEntry,
421434
ostree_commit: &str,
422435
) -> Result<()> {
423436
// TODO consider rendering more ostree stuff here like rpm-ostree status does
424437
let prefix = match slot {
425-
Slot::Staged => " Staged ostree".into(),
426-
Slot::Booted => format!("{} Booted ostree", crate::glyph::Glyph::BlackCircle),
427-
Slot::Rollback => " Rollback ostree".into(),
438+
Some(Slot::Staged) => " Staged ostree".into(),
439+
Some(Slot::Booted) => format!("{} Booted ostree", crate::glyph::Glyph::BlackCircle),
440+
Some(Slot::Rollback) => " Rollback ostree".into(),
441+
_ => " Other ostree".into(),
428442
};
429443
let prefix_len = prefix.len();
430444
writeln!(out, "{prefix}")?;
431445
write_row_name(&mut out, "Commit", prefix_len)?;
432446
writeln!(out, "{ostree_commit}")?;
447+
448+
if entry.pinned {
449+
write_row_name(&mut out, "Pinned", prefix_len)?;
450+
writeln!(out, "yes")?;
451+
}
452+
433453
tracing::debug!("pinned={}", entry.pinned);
434454
Ok(())
435455
}
@@ -448,14 +468,27 @@ fn human_readable_output_booted(mut out: impl Write, host: &Host) -> Result<()>
448468
writeln!(out)?;
449469
}
450470
if let Some(image) = &host_status.image {
451-
human_render_slot(&mut out, slot_name, host_status, image)?;
471+
human_render_slot(&mut out, Some(slot_name), host_status, image)?;
452472
} else if let Some(ostree) = host_status.ostree.as_ref() {
453-
human_render_slot_ostree(&mut out, slot_name, host_status, &ostree.checksum)?;
473+
human_render_slot_ostree(&mut out, Some(slot_name), host_status, &ostree.checksum)?;
454474
} else {
455475
writeln!(out, "Current {slot_name} state is unknown")?;
456476
}
457477
}
458478
}
479+
480+
if !host.status.other_deployments.is_empty() {
481+
for entry in &host.status.other_deployments {
482+
writeln!(out)?;
483+
484+
if let Some(image) = &entry.image {
485+
human_render_slot(&mut out, None, entry, image)?;
486+
} else if let Some(ostree) = entry.ostree.as_ref() {
487+
human_render_slot_ostree(&mut out, None, entry, &ostree.checksum)?;
488+
}
489+
}
490+
}
491+
459492
Ok(())
460493
}
461494

@@ -490,7 +523,7 @@ mod tests {
490523
Staged image: quay.io/example/someimage:latest
491524
Digest: sha256:16dc2b6256b4ff0d2ec18d2dbfb06d117904010c8cf9732cdb022818cf7a7566 (arm64)
492525
Version: nightly (2023-10-14T19:22:15Z)
493-
526+
494527
● Booted image: quay.io/example/someimage:latest
495528
Digest: sha256:736b359467c9437c1ac915acaae952aad854e07eb4a16a94999a48af08c83c34 (arm64)
496529
Version: nightly (2023-09-30T19:22:16Z)
@@ -508,7 +541,7 @@ mod tests {
508541
let expected = indoc::indoc! { r"
509542
Staged ostree
510543
Commit: 1c24260fdd1be20f72a4a97a75c582834ee3431fbb0fa8e4f482bb219d633a45
511-
544+
512545
● Booted ostree
513546
Commit: f9fa3a553ceaaaf30cf85bfe7eed46a822f7b8fd7e14c1e3389cbc3f6d27f791
514547
"};
@@ -524,7 +557,7 @@ mod tests {
524557
Staged image: quay.io/centos-bootc/centos-bootc:stream9
525558
Digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38 (s390x)
526559
Version: stream9.20240807.0
527-
560+
528561
● Booted ostree
529562
Commit: f9fa3a553ceaaaf30cf85bfe7eed46a822f7b8fd7e14c1e3389cbc3f6d27f791
530563
"};
@@ -588,4 +621,23 @@ mod tests {
588621
Some(ImageSignature::OstreeRemote("fedora".into()))
589622
);
590623
}
624+
625+
#[test]
626+
fn test_human_readable_booted_pinned_spec() {
627+
// booted image, no staged/rollback
628+
let w = human_status_from_spec_fixture(include_str!("fixtures/spec-booted-pinned.yaml"))
629+
.expect("No spec found");
630+
let expected = indoc::indoc! { r"
631+
● Booted image: quay.io/centos-bootc/centos-bootc:stream9
632+
Digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38 (arm64)
633+
Version: stream9.20240807.0
634+
Pinned: yes
635+
636+
Other image: quay.io/centos-bootc/centos-bootc:stream9
637+
Digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b37 (arm64)
638+
Version: stream9.20240807.0
639+
Pinned: yes
640+
"};
641+
similar_asserts::assert_eq!(w, expected);
642+
}
591643
}

0 commit comments

Comments
 (0)