Skip to content

Commit

Permalink
Merge pull request #738 from jmarrero/human-readable
Browse files Browse the repository at this point in the history
cli: Add a human readable format to status
  • Loading branch information
djach7 committed Sep 18, 2024
2 parents 3d36c9b + bc20565 commit ecabb89
Show file tree
Hide file tree
Showing 7 changed files with 312 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ pub(crate) struct EditOpts {
#[derive(Debug, Clone, ValueEnum, PartialEq, Eq)]
#[clap(rename_all = "lowercase")]
pub(crate) enum OutputFormat {
/// Output in Human Readable format.
HumanReadable,
/// Output in YAML format.
Yaml,
/// Output in JSON format.
Expand Down
28 changes: 28 additions & 0 deletions lib/src/fixtures/spec-only-booted.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: org.containers.bootc/v1alpha1
kind: BootcHost
metadata:
name: host
spec:
image:
image: quay.io/centos-bootc/centos-bootc:stream9
transport: registry
bootOrder: default
status:
staged: null
booted:
image:
image:
image: quay.io/centos-bootc/centos-bootc:stream9
transport: registry
version: stream9.20240807.0
timestamp: null
imageDigest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38
cachedUpdate: null
incompatible: false
pinned: false
ostree:
checksum: 439f6bd2e2361bee292c1f31840d798c5ac5ba76483b8021dc9f7b0164ac0f48
deploySerial: 0
rollback: null
rollbackQueued: false
type: bootcHost
37 changes: 37 additions & 0 deletions lib/src/fixtures/spec-ostree-to-bootc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
apiVersion: org.containers.bootc/v1alpha1
kind: BootcHost
metadata:
name: host
spec:
image:
image: quay.io/centos-bootc/centos-bootc:stream9
transport: registry
bootOrder: default
status:
staged:
image:
image:
image: quay.io/centos-bootc/centos-bootc:stream9
transport: registry
version: stream9.20240807.0
timestamp: null
imageDigest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38
cachedUpdate: null
incompatible: false
pinned: false
store: ostreeContainer
ostree:
checksum: 05cbf6dcae32e7a1c5a0774a648a073a5834a305ca92204b53fb6c281fe49db1
deploySerial: 0
booted:
image: null
cachedUpdate: null
incompatible: false
pinned: false
store: null
ostree:
checksum: f9fa3a553ceaaaf30cf85bfe7eed46a822f7b8fd7e14c1e3389cbc3f6d27f791
deploySerial: 0
rollback: null
rollbackQueued: false
type: null
29 changes: 29 additions & 0 deletions lib/src/fixtures/spec-rfe-ostree-deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
apiVersion: org.containers.bootc/v1alpha1
kind: BootcHost
metadata:
name: host
spec:
image: null
bootOrder: default
status:
staged:
image: null
cachedUpdate: null
incompatible: true
pinned: false
store: null
ostree:
checksum: 1c24260fdd1be20f72a4a97a75c582834ee3431fbb0fa8e4f482bb219d633a45
deploySerial: 0
booted:
image: null
cachedUpdate: null
incompatible: false
pinned: false
store: null
ostree:
checksum: f9fa3a553ceaaaf30cf85bfe7eed46a822f7b8fd7e14c1e3389cbc3f6d27f791
deploySerial: 0
rollback: null
rollbackQueued: false
type: null
40 changes: 40 additions & 0 deletions lib/src/fixtures/spec-staged-booted.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
apiVersion: org.containers.bootc/v1alpha1
kind: BootcHost
metadata:
name: host
spec:
image:
image: quay.io/example/someimage:latest
transport: registry
signature: insecure
status:
staged:
image:
image:
image: quay.io/example/someimage:latest
transport: registry
signature: insecure
version: nightly
timestamp: 2023-10-14T19:22:15Z
imageDigest: sha256:16dc2b6256b4ff0d2ec18d2dbfb06d117904010c8cf9732cdb022818cf7a7566
incompatible: false
pinned: false
ostree:
checksum: 3c6dad657109522e0b2e49bf44b5420f16f0b438b5b9357e5132211cfbad135d
deploySerial: 0
booted:
image:
image:
image: quay.io/example/someimage:latest
transport: registry
signature: insecure
version: nightly
timestamp: 2023-09-30T19:22:16Z
imageDigest: sha256:736b359467c9437c1ac915acaae952aad854e07eb4a16a94999a48af08c83c34
incompatible: false
pinned: false
ostree:
checksum: 26836632adf6228d64ef07a26fd3efaf177104efd1f341a2cf7909a3e4e2c72c
deploySerial: 0
rollback: null
isContainer: false
40 changes: 40 additions & 0 deletions lib/src/fixtures/spec-staged-rollback.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
apiVersion: org.containers.bootc/v1alpha1
kind: BootcHost
metadata:
name: host
spec:
image:
image: quay.io/example/someimage:latest
transport: registry
signature: insecure
status:
staged:
image:
image:
image: quay.io/example/someimage:latest
transport: registry
signature: insecure
version: nightly
timestamp: 2023-10-14T19:22:15Z
imageDigest: sha256:16dc2b6256b4ff0d2ec18d2dbfb06d117904010c8cf9732cdb022818cf7a7566
incompatible: false
pinned: false
ostree:
checksum: 3c6dad657109522e0b2e49bf44b5420f16f0b438b5b9357e5132211cfbad135d
deploySerial: 0
booted: null
rollback:
image:
image:
image: quay.io/example/someimage:latest
transport: registry
signature: insecure
version: nightly
timestamp: 2023-09-30T19:22:16Z
imageDigest: sha256:736b359467c9437c1ac915acaae952aad854e07eb4a16a94999a48af08c83c34
incompatible: false
pinned: false
ostree:
checksum: 26836632adf6228d64ef07a26fd3efaf177104efd1f341a2cf7909a3e4e2c72c
deploySerial: 0
isContainer: false
136 changes: 136 additions & 0 deletions lib/src/status.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::collections::VecDeque;
use std::io::IsTerminal;
use std::io::Write;

use anyhow::{Context, Result};
use camino::Utf8Path;
Expand Down Expand Up @@ -305,19 +307,153 @@ pub(crate) async fn status(opts: super::cli::StatusOpts) -> Result<()> {
let mut out = out.lock();
let legacy_opt = if opts.json {
OutputFormat::Json
} else if std::io::stdout().is_terminal() {
OutputFormat::HumanReadable
} else {
OutputFormat::Yaml
};
let format = opts.format.unwrap_or(legacy_opt);
match format {
OutputFormat::Json => serde_json::to_writer(&mut out, &host).map_err(anyhow::Error::new),
OutputFormat::Yaml => serde_yaml::to_writer(&mut out, &host).map_err(anyhow::Error::new),
OutputFormat::HumanReadable => human_readable_output(&mut out, &host),
}
.context("Writing to stdout")?;

Ok(())
}

fn human_readable_output(mut out: impl Write, host: &Host) -> Result<()> {
for (status_string, status) in [
("staged", &host.status.staged),
("booted", &host.status.booted),
("rollback", &host.status.rollback),
] {
if let Some(host_status) = status {
if let Some(image) = &host_status.image {
writeln!(
out,
"Current {} image: {}",
status_string, image.image.image
)?;

let version = image
.version
.as_deref()
.unwrap_or("No image version defined");
let timestamp = image
.timestamp
.as_ref()
.map(|t| t.to_string())
.unwrap_or_else(|| "No timestamp present".to_owned());
let transport = &image.image.transport;
let digest = &image.image_digest;

writeln!(out, " Image version: {version} ({timestamp})")?;
writeln!(out, " Image transport: {transport}")?;
writeln!(out, " Image digest: {digest}")?;
} else {
writeln!(out, "Current {status_string} state is native ostree")?;
}
} else {
writeln!(out, "No {status_string} image present")?;
}
}
Ok(())
}

fn human_status_from_spec_fixture(spec_fixture: &str) -> Result<String> {
let host: Host = serde_yaml::from_str(spec_fixture).unwrap();
let mut w = Vec::new();
human_readable_output(&mut w, &host).unwrap();
let w = String::from_utf8(w).unwrap();
Ok(w)
}

#[test]
fn test_human_readable_base_spec() {
// Tests Staged and Booted, null Rollback
let w = human_status_from_spec_fixture(include_str!("fixtures/spec-staged-booted.yaml"))
.expect("No spec found");
let expected = indoc::indoc! { r"
Current staged image: quay.io/example/someimage:latest
Image version: nightly (2023-10-14 19:22:15 UTC)
Image transport: registry
Image digest: sha256:16dc2b6256b4ff0d2ec18d2dbfb06d117904010c8cf9732cdb022818cf7a7566
Current booted image: quay.io/example/someimage:latest
Image version: nightly (2023-09-30 19:22:16 UTC)
Image transport: registry
Image digest: sha256:736b359467c9437c1ac915acaae952aad854e07eb4a16a94999a48af08c83c34
No rollback image present
"};
similar_asserts::assert_eq!(w, expected);
}

#[test]
fn test_human_readable_rfe_spec() {
// Basic rhel for edge bootc install with nothing
let w =
human_status_from_spec_fixture(include_str!("fixtures/spec-rfe-ostree-deployment.yaml"))
.expect("No spec found");
let expected = indoc::indoc! { r"
Current staged state is native ostree
Current booted state is native ostree
No rollback image present
"};
similar_asserts::assert_eq!(w, expected);
}

#[test]
fn test_human_readable_staged_spec() {
// staged image, no boot/rollback
let w = human_status_from_spec_fixture(include_str!("fixtures/spec-ostree-to-bootc.yaml"))
.expect("No spec found");
let expected = indoc::indoc! { r"
Current staged image: quay.io/centos-bootc/centos-bootc:stream9
Image version: stream9.20240807.0 (No timestamp present)
Image transport: registry
Image digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38
Current booted state is native ostree
No rollback image present
"};
similar_asserts::assert_eq!(w, expected);
}

#[test]
fn test_human_readable_booted_spec() {
// booted image, no staged/rollback
let w = human_status_from_spec_fixture(include_str!("fixtures/spec-only-booted.yaml"))
.expect("No spec found");
let expected = indoc::indoc! { r"
No staged image present
Current booted image: quay.io/centos-bootc/centos-bootc:stream9
Image version: stream9.20240807.0 (No timestamp present)
Image transport: registry
Image digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38
No rollback image present
"};
similar_asserts::assert_eq!(w, expected);
}

#[test]
fn test_human_readable_staged_rollback_spec() {
// staged/rollback image, no booted
let w = human_status_from_spec_fixture(include_str!("fixtures/spec-staged-rollback.yaml"))
.expect("No spec found");
let expected = indoc::indoc! { r"
Current staged image: quay.io/example/someimage:latest
Image version: nightly (2023-10-14 19:22:15 UTC)
Image transport: registry
Image digest: sha256:16dc2b6256b4ff0d2ec18d2dbfb06d117904010c8cf9732cdb022818cf7a7566
No booted image present
Current rollback image: quay.io/example/someimage:latest
Image version: nightly (2023-09-30 19:22:16 UTC)
Image transport: registry
Image digest: sha256:736b359467c9437c1ac915acaae952aad854e07eb4a16a94999a48af08c83c34
"};
similar_asserts::assert_eq!(w, expected);
}

#[test]
fn test_convert_signatures() {
use std::str::FromStr;
Expand Down

0 comments on commit ecabb89

Please sign in to comment.