Skip to content

Commit

Permalink
Add HostType, change status to always succeed
Browse files Browse the repository at this point in the history
Closes: #242

Basically it'd be useful for folks to be able to run `bootc status --json`
and have that always work - if we're not on a bootc-booted system
then we just output null data.

Specifically we drop the `isContainer` field and replace it
with an optional non-exhaustive enumeration.  For anything we don't
know about we just output `None` i.e. `null` in JSON.

Signed-off-by: Colin Walters <[email protected]>
  • Loading branch information
cgwalters committed Dec 20, 2023
1 parent 95ccd5c commit 69a7f37
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 21 deletions.
5 changes: 3 additions & 2 deletions lib/src/privtests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use fn_error_context::context;
use rustix::fd::AsFd;
use xshell::{cmd, Shell};

use crate::spec::HostType;

use super::cli::TestingOpts;
use super::spec::Host;

Expand Down Expand Up @@ -100,10 +102,9 @@ pub(crate) fn impl_run_host() -> Result<()> {

#[context("Container tests")]
pub(crate) fn impl_run_container() -> Result<()> {
assert!(ostree_ext::container_utils::is_ostree_container()?);
let sh = Shell::new()?;
let host: Host = serde_yaml::from_str(&cmd!(sh, "bootc status").read()?)?;
assert!(host.status.is_container);
assert!(matches!(host.status.ty, None));
println!("ok status");

for c in ["upgrade", "update"] {
Expand Down
27 changes: 23 additions & 4 deletions lib/src/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use crate::k8sapitypes;

const API_VERSION: &str = "org.containers.bootc/v1alpha1";
const KIND: &str = "BootcHost";
/// The default object name we use; there's only one.
pub(crate) const OBJECT_NAME: &str = "host";

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -94,6 +96,16 @@ pub struct BootEntry {
pub ostree: Option<BootEntryOstree>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
/// The detected type of running system. Note that this is not exhaustive
/// and new variants may be added in the future.
pub enum HostType {
/// The current system is deployed in a bootc compatible way.
BootcHost,
}

/// The status of the host system
#[derive(Debug, Clone, Serialize, Default, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "camelCase")]
Expand All @@ -105,15 +117,16 @@ pub struct HostStatus {
/// The previously booted image
pub rollback: Option<BootEntry>,

/// Whether or not the current system state is an ostree-based container
pub is_container: bool,
/// The detected type of system
#[serde(rename = "type")]
pub ty: Option<HostType>,
}

impl Host {
/// Create a new host
pub fn new(name: &str, spec: HostSpec) -> Self {
pub fn new(spec: HostSpec) -> Self {
let metadata = k8sapitypes::ObjectMeta {
name: Some(name.to_owned()),
name: Some(OBJECT_NAME.to_owned()),
..Default::default()
};
Self {
Expand All @@ -128,6 +141,12 @@ impl Host {
}
}

impl Default for Host {
fn default() -> Self {
Self::new(Default::default())
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
33 changes: 18 additions & 15 deletions lib/src/status.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::collections::VecDeque;

use crate::spec::{BootEntry, Host, HostSpec, HostStatus, ImageStatus};
use crate::spec::{BootEntry, Host, HostSpec, HostStatus, HostType, ImageStatus};
use crate::spec::{ImageReference, ImageSignature};
use anyhow::{Context, Result};
use camino::Utf8Path;
use fn_error_context::context;
use ostree::glib;
use ostree_container::OstreeImageReference;
Expand All @@ -12,8 +13,6 @@ use ostree_ext::oci_spec;
use ostree_ext::ostree;
use ostree_ext::sysroot::SysrootLock;

const OBJECT_NAME: &str = "host";

impl From<ostree_container::SignatureSource> for ImageSignature {
fn from(sig: ostree_container::SignatureSource) -> Self {
use ostree_container::SignatureSource;
Expand Down Expand Up @@ -223,8 +222,6 @@ pub(crate) fn get_status(
other,
};

let is_container = ostree_ext::container_utils::is_ostree_container()?;

let staged = deployments
.staged
.as_ref()
Expand All @@ -250,27 +247,33 @@ pub(crate) fn get_status(
image: Some(img.image.clone()),
})
.unwrap_or_default();
let mut host = Host::new(OBJECT_NAME, spec);

let ty = if booted
.as_ref()
.map(|b| b.image.is_some())
.unwrap_or_default()
{
// We're only of type BootcHost if we booted via container image
Some(HostType::BootcHost)
} else {
None
};

let mut host = Host::new(spec);
host.status = HostStatus {
staged,
booted,
rollback,
is_container,
ty,
};
Ok((deployments, host))
}

/// Implementation of the `bootc status` CLI command.
#[context("Status")]
pub(crate) async fn status(opts: super::cli::StatusOpts) -> Result<()> {
let host = if ostree_ext::container_utils::is_ostree_container()? {
let status = HostStatus {
is_container: true,
..Default::default()
};
let mut r = Host::new(OBJECT_NAME, HostSpec { image: None });
r.status = status;
r
let host = if !Utf8Path::new("/run/ostree-booted").try_exists()? {
Default::default()
} else {
crate::cli::require_root()?;
let sysroot = super::cli::get_locked_sysroot().await?;
Expand Down
7 changes: 7 additions & 0 deletions tests/kolainst/basic
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ case "${AUTOPKGTEST_REBOOT_MARK:-}" in
echo "booted into $image"
echo "ok status test"

host_ty=$(jq -r '.status.type' < status.json)
test "${host_ty}" = "bootcHost"
# Now fake things out with an empty /run
unshare -m /bin/sh -c 'mount -t tmpfs tmpfs /run; bootc status --json > status-no-run.json'
host_ty_norun=$(jq -r '.status.type' < status-no-run.json)
test "${host_ty_norun}" = "null"

test "null" = $(jq '.status.staged' < status.json)
# Should be a no-op
bootc update
Expand Down

0 comments on commit 69a7f37

Please sign in to comment.