From dacd6e02e5b5f9ba589e7367e0e178d708cd9925 Mon Sep 17 00:00:00 2001 From: Omer Tuchfeld Date: Tue, 5 Nov 2024 15:57:01 +0100 Subject: [PATCH] DRAFT: List logically bound images For now this is just the implementation, but it does not contain the important bug fix for https://github.com/containers/bootc/issues/846 which is to allow this command to run inside a container and not just on a bootc booted host Signed-off-by: Omer Tuchfeld --- lib/src/cli.rs | 28 ++++++++++++++++++++++++++-- lib/src/image.rs | 48 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/lib/src/cli.rs b/lib/src/cli.rs index 5e19d400e..a5be27da7 100644 --- a/lib/src/cli.rs +++ b/lib/src/cli.rs @@ -21,6 +21,7 @@ use ostree_ext::container as ostree_container; use ostree_ext::keyfileext::KeyFileExt; use ostree_ext::ostree; use schemars::schema_for; +use serde::{Deserialize, Serialize}; use crate::deploy::RequiredHostSpec; use crate::lints; @@ -235,13 +236,36 @@ pub(crate) enum ImageCmdOpts { }, } +#[derive(ValueEnum, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +#[serde(rename_all = "kebab-case")] +pub(crate) enum ImageListType { + /// List all images + #[default] + All, + /// List only logically bound images + Logical, + /// List only host images + Host, +} + +impl std::fmt::Display for ImageListType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.to_possible_value().unwrap().get_name().fmt(f) + } +} + /// Subcommands which operate on images. #[derive(Debug, clap::Subcommand, PartialEq, Eq)] pub(crate) enum ImageOpts { /// List fetched images stored in the bootc storage. /// /// Note that these are distinct from images stored via e.g. `podman`. - List, + List { + /// Type of image to list + #[clap(long)] + #[arg(default_value_t)] + list_type: ImageListType, + }, /// Copy a container image from the bootc storage to `containers-storage:`. /// /// The source and target are both optional; if both are left unspecified, @@ -876,7 +900,7 @@ async fn run_from_opt(opt: Opt) -> Result<()> { } }, Opt::Image(opts) => match opts { - ImageOpts::List => crate::image::list_entrypoint().await, + ImageOpts::List { list_type } => crate::image::list_entrypoint(list_type).await, ImageOpts::CopyToStorage { source, target } => { crate::image::push_entrypoint(source.as_deref(), target.as_deref()).await } diff --git a/lib/src/image.rs b/lib/src/image.rs index eac891a0d..7aee6d049 100644 --- a/lib/src/image.rs +++ b/lib/src/image.rs @@ -7,25 +7,24 @@ use bootc_utils::CommandRunExt; use fn_error_context::context; use ostree_ext::container::{ImageReference, Transport}; -use crate::imgstorage::Storage; +use crate::cli::ImageListType; /// The name of the image we push to containers-storage if nothing is specified. const IMAGE_DEFAULT: &str = "localhost/bootc"; -#[context("Listing images")] -pub(crate) async fn list_entrypoint() -> Result<()> { - let sysroot = crate::cli::get_storage().await?; - let repo = &sysroot.repo(); - - let images = ostree_ext::container::store::list_images(repo).context("Querying images")?; - - println!("# Host images"); +#[context("Listing host images")] +pub(crate) fn list_host_images(sysroot: &crate::store::Storage) -> Result<()> { + let repo = sysroot.repo(); + let images = ostree_ext::container::store::list_images(&repo).context("Querying images")?; for image in images { println!("{image}"); } - println!(); - println!("# Logically bound images"); + Ok(()) +} + +#[context("Listing logical images")] +pub(crate) fn list_logical_images(sysroot: &crate::store::Storage) -> Result<()> { let mut listcmd = sysroot.get_ensure_imgstore()?.new_image_cmd()?; listcmd.arg("list"); listcmd.run()?; @@ -33,6 +32,31 @@ pub(crate) async fn list_entrypoint() -> Result<()> { Ok(()) } +#[context("Listing images")] +pub(crate) async fn list_entrypoint(list_type: ImageListType) -> Result<()> { + // TODO: Get the storage from the container image, not the booted storage + let sysroot: crate::store::Storage = crate::cli::get_storage().await?; + + match list_type { + ImageListType::All => { + println!("# Host images"); + list_host_images(&sysroot)?; + println!(); + + println!("# Logically bound images"); + list_logical_images(&sysroot)?; + } + ImageListType::Host => { + list_host_images(&sysroot)?; + } + ImageListType::Logical => { + list_logical_images(&sysroot)?; + } + } + + Ok(()) +} + /// Implementation of `bootc image push-to-storage`. #[context("Pushing image")] pub(crate) async fn push_entrypoint(source: Option<&str>, target: Option<&str>) -> Result<()> { @@ -79,7 +103,7 @@ pub(crate) async fn push_entrypoint(source: Option<&str>, target: Option<&str>) /// Thin wrapper for invoking `podman image ` but set up for our internal /// image store (as distinct from /var/lib/containers default). pub(crate) async fn imgcmd_entrypoint( - storage: &Storage, + storage: &crate::imgstorage::Storage, arg: &str, args: &[std::ffi::OsString], ) -> std::result::Result<(), anyhow::Error> {