Skip to content

Commit 5358fda

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 <[email protected]>
1 parent 5c1cb06 commit 5358fda

File tree

3 files changed

+115
-13
lines changed

3 files changed

+115
-13
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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+
stateroot: default
28+
otherDeployments:
29+
- image:
30+
image:
31+
image: quay.io/centos-bootc/centos-bootc:stream9
32+
transport: registry
33+
version: stream9.20240807.0
34+
timestamp: null
35+
imageDigest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b37
36+
architecture: arm64
37+
cachedUpdate: null
38+
incompatible: false
39+
pinned: true
40+
ostree:
41+
checksum: 99b2cc3b6edce9ebaef6a6076effa5ee3e1dcff3523016ffc94a1b27c6c67e12
42+
deploySerial: 0
43+
stateroot: default
44+
rollback: null
45+
rollbackQueued: false
46+
type: bootcHost

lib/src/spec.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ pub struct HostStatus {
203203
pub booted: Option<BootEntry>,
204204
/// The previously booted image
205205
pub rollback: Option<BootEntry>,
206+
/// Other deployments (i.e. pinned)
207+
#[serde(skip_serializing_if = "Vec::is_empty")]
208+
#[serde(default)]
209+
pub other_deployments: Vec<BootEntry>,
206210
/// Set to true if the rollback entry is queued for the next boot.
207211
#[serde(default)]
208212
pub rollback_queued: bool,

lib/src/status.rs

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,12 @@ pub(crate) fn get_status(
254254
.map(|d| boot_entry_from_deployment(sysroot, d))
255255
.transpose()
256256
.context("Rollback deployment")?;
257+
let other_deployments = deployments
258+
.other
259+
.iter()
260+
.map(|d| boot_entry_from_deployment(sysroot, d))
261+
.collect::<Result<Vec<_>>>()
262+
.context("Other deployments")?;
257263
let spec = staged
258264
.as_ref()
259265
.or(booted.as_ref())
@@ -280,6 +286,7 @@ pub(crate) fn get_status(
280286
staged,
281287
booted,
282288
rollback,
289+
other_deployments,
283290
rollback_queued,
284291
ty,
285292
};
@@ -362,7 +369,7 @@ fn write_row_name(mut out: impl Write, s: &str, prefix_len: usize) -> Result<()>
362369
/// Write the data for a container image based status.
363370
fn human_render_slot(
364371
mut out: impl Write,
365-
slot: Slot,
372+
slot: Option<Slot>,
366373
entry: &crate::spec::BootEntry,
367374
image: &crate::spec::ImageStatus,
368375
) -> Result<()> {
@@ -376,9 +383,10 @@ fn human_render_slot(
376383
Cow::Owned(format!("{transport}:{imagename}"))
377384
};
378385
let prefix = match slot {
379-
Slot::Staged => " Staged image".into(),
380-
Slot::Booted => format!("{} Booted image", crate::glyph::Glyph::BlackCircle),
381-
Slot::Rollback => " Rollback image".into(),
386+
Some(Slot::Staged) => " Staged image".into(),
387+
Some(Slot::Booted) => format!("{} Booted image", crate::glyph::Glyph::BlackCircle),
388+
Some(Slot::Rollback) => " Rollback image".into(),
389+
_ => " Other image".into(),
382390
};
383391
let prefix_len = prefix.chars().count();
384392
writeln!(out, "{prefix}: {imageref}")?;
@@ -409,6 +417,11 @@ fn human_render_slot(
409417
writeln!(out, "{timestamp}")?;
410418
}
411419

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

414427
Ok(())
@@ -417,20 +430,27 @@ fn human_render_slot(
417430
/// Output a rendering of a non-container boot entry.
418431
fn human_render_slot_ostree(
419432
mut out: impl Write,
420-
slot: Slot,
433+
slot: Option<Slot>,
421434
entry: &crate::spec::BootEntry,
422435
ostree_commit: &str,
423436
) -> Result<()> {
424437
// TODO consider rendering more ostree stuff here like rpm-ostree status does
425438
let prefix = match slot {
426-
Slot::Staged => " Staged ostree".into(),
427-
Slot::Booted => format!("{} Booted ostree", crate::glyph::Glyph::BlackCircle),
428-
Slot::Rollback => " Rollback ostree".into(),
439+
Some(Slot::Staged) => " Staged ostree".into(),
440+
Some(Slot::Booted) => format!("{} Booted ostree", crate::glyph::Glyph::BlackCircle),
441+
Some(Slot::Rollback) => " Rollback ostree".into(),
442+
_ => " Other ostree".into(),
429443
};
430444
let prefix_len = prefix.len();
431445
writeln!(out, "{prefix}")?;
432446
write_row_name(&mut out, "Commit", prefix_len)?;
433447
writeln!(out, "{ostree_commit}")?;
448+
449+
if entry.pinned {
450+
write_row_name(&mut out, "Pinned", prefix_len)?;
451+
writeln!(out, "yes")?;
452+
}
453+
434454
tracing::debug!("pinned={}", entry.pinned);
435455
Ok(())
436456
}
@@ -449,14 +469,27 @@ fn human_readable_output_booted(mut out: impl Write, host: &Host) -> Result<()>
449469
writeln!(out)?;
450470
}
451471
if let Some(image) = &host_status.image {
452-
human_render_slot(&mut out, slot_name, host_status, image)?;
472+
human_render_slot(&mut out, Some(slot_name), host_status, image)?;
453473
} else if let Some(ostree) = host_status.ostree.as_ref() {
454-
human_render_slot_ostree(&mut out, slot_name, host_status, &ostree.checksum)?;
474+
human_render_slot_ostree(&mut out, Some(slot_name), host_status, &ostree.checksum)?;
455475
} else {
456476
writeln!(out, "Current {slot_name} state is unknown")?;
457477
}
458478
}
459479
}
480+
481+
if !host.status.other_deployments.is_empty() {
482+
for entry in &host.status.other_deployments {
483+
writeln!(out)?;
484+
485+
if let Some(image) = &entry.image {
486+
human_render_slot(&mut out, None, entry, image)?;
487+
} else if let Some(ostree) = entry.ostree.as_ref() {
488+
human_render_slot_ostree(&mut out, None, entry, &ostree.checksum)?;
489+
}
490+
}
491+
}
492+
460493
Ok(())
461494
}
462495

@@ -491,7 +524,7 @@ mod tests {
491524
Staged image: quay.io/example/someimage:latest
492525
Digest: sha256:16dc2b6256b4ff0d2ec18d2dbfb06d117904010c8cf9732cdb022818cf7a7566 (arm64)
493526
Version: nightly (2023-10-14T19:22:15Z)
494-
527+
495528
● Booted image: quay.io/example/someimage:latest
496529
Digest: sha256:736b359467c9437c1ac915acaae952aad854e07eb4a16a94999a48af08c83c34 (arm64)
497530
Version: nightly (2023-09-30T19:22:16Z)
@@ -509,7 +542,7 @@ mod tests {
509542
let expected = indoc::indoc! { r"
510543
Staged ostree
511544
Commit: 1c24260fdd1be20f72a4a97a75c582834ee3431fbb0fa8e4f482bb219d633a45
512-
545+
513546
● Booted ostree
514547
Commit: f9fa3a553ceaaaf30cf85bfe7eed46a822f7b8fd7e14c1e3389cbc3f6d27f791
515548
"};
@@ -525,7 +558,7 @@ mod tests {
525558
Staged image: quay.io/centos-bootc/centos-bootc:stream9
526559
Digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38 (s390x)
527560
Version: stream9.20240807.0
528-
561+
529562
● Booted ostree
530563
Commit: f9fa3a553ceaaaf30cf85bfe7eed46a822f7b8fd7e14c1e3389cbc3f6d27f791
531564
"};
@@ -589,4 +622,23 @@ mod tests {
589622
Some(ImageSignature::OstreeRemote("fedora".into()))
590623
);
591624
}
625+
626+
#[test]
627+
fn test_human_readable_booted_pinned_spec() {
628+
// booted image, no staged/rollback
629+
let w = human_status_from_spec_fixture(include_str!("fixtures/spec-booted-pinned.yaml"))
630+
.expect("No spec found");
631+
let expected = indoc::indoc! { r"
632+
● Booted image: quay.io/centos-bootc/centos-bootc:stream9
633+
Digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38 (arm64)
634+
Version: stream9.20240807.0
635+
Pinned: yes
636+
637+
Other image: quay.io/centos-bootc/centos-bootc:stream9
638+
Digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b37 (arm64)
639+
Version: stream9.20240807.0
640+
Pinned: yes
641+
"};
642+
similar_asserts::assert_eq!(w, expected);
643+
}
592644
}

0 commit comments

Comments
 (0)