particle-os-cli/process/drivers/skopeo_driver.rs
Gerald Pinder 3a0be4099a
feat: Add bootc support (#448)
Adds support for using `bootc` as the preferred method for booting from
a locally created image. This new method gets rid of the need to create
a tarball and move it to the correct place and instead it will make use
of `podman scp` which copies the image to the root `containers-storage`
and then has `rpm-ostree` and `bootc` boot from that store.

Closes #418 
Closes #200
2025-08-09 14:05:59 -04:00

118 lines
3.4 KiB
Rust

use std::{process::Stdio, time::Duration};
use cached::proc_macro::cached;
use colored::Colorize;
use comlexr::cmd;
use indicatif::{ProgressBar, ProgressStyle};
use log::{debug, trace};
use miette::{IntoDiagnostic, Result, bail};
use crate::{drivers::types::Platform, logging::Logger};
use super::{
InspectDriver,
opts::{CopyOciDirOpts, GetMetadataOpts},
types::ImageMetadata,
};
#[derive(Debug)]
pub struct SkopeoDriver;
impl InspectDriver for SkopeoDriver {
fn get_metadata(opts: GetMetadataOpts) -> Result<ImageMetadata> {
get_metadata_cache(opts)
}
}
#[cached(
result = true,
key = "String",
convert = r#"{ format!("{}-{:?}", opts.image, opts.platform)}"#,
sync_writes = "by_key"
)]
fn get_metadata_cache(opts: GetMetadataOpts) -> Result<ImageMetadata> {
trace!("SkopeoDriver::get_metadata({opts:#?})");
let image_str = opts.image.to_string();
let progress = Logger::multi_progress().add(
ProgressBar::new_spinner()
.with_style(ProgressStyle::default_spinner())
.with_message(format!("Inspecting metadata for {}", image_str.bold())),
);
progress.enable_steady_tick(Duration::from_millis(100));
let mut command = cmd!(
"skopeo",
if let Some(platform) = opts.platform => [
"--override-arch",
platform.arch(),
],
if let Some(variant) = opts.platform.as_ref().and_then(Platform::variant) => [
"--override-variant",
variant,
],
"inspect",
format!("docker://{image_str}"),
);
command.stderr(Stdio::inherit());
trace!("{command:?}");
let output = command.output().into_diagnostic()?;
progress.finish_and_clear();
Logger::multi_progress().remove(&progress);
if output.status.success() {
debug!("Successfully inspected image {}!", image_str.bold().green());
} else {
bail!("Failed to inspect image {}", image_str.bold().red());
}
serde_json::from_slice(&output.stdout).into_diagnostic()
}
impl super::OciCopy for SkopeoDriver {
fn copy_oci_dir(opts: CopyOciDirOpts) -> Result<()> {
use crate::logging::CommandLogging;
let use_sudo = opts.privileged && !blue_build_utils::running_as_root();
let status = {
let c = cmd!(
if use_sudo {
"sudo"
} else {
"skopeo"
},
if use_sudo && blue_build_utils::has_env_var(blue_build_utils::constants::SUDO_ASKPASS) => [
"-A",
"-p",
format!(
concat!(
"Password is required to copy ",
"OCI directory {dir:?} to remote registry {registry}"
),
dir = opts.oci_dir,
registry = opts.registry,
)
],
if use_sudo => "skopeo",
"copy",
opts.oci_dir,
format!("docker://{}", opts.registry),
);
trace!("{c:?}");
c
}
.build_status(
opts.registry.to_string(),
format!("Copying {} to", opts.oci_dir),
)
.into_diagnostic()?;
if !status.success() {
bail!("Failed to copy {} to {}", opts.oci_dir, opts.registry);
}
Ok(())
}
}