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
This commit is contained in:
parent
2c525854c9
commit
3a0be4099a
65 changed files with 2991 additions and 1857 deletions
|
|
@ -10,7 +10,7 @@ use std::{
|
|||
borrow::Borrow,
|
||||
fmt::Debug,
|
||||
process::{ExitStatus, Output},
|
||||
sync::{Mutex, RwLock},
|
||||
sync::{LazyLock, RwLock, atomic::AtomicBool},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
|
|
@ -24,12 +24,13 @@ use log::{info, trace, warn};
|
|||
use miette::{Result, miette};
|
||||
use oci_distribution::Reference;
|
||||
use opts::{
|
||||
BuildOpts, BuildTagPushOpts, CheckKeyPairOpts, CreateContainerOpts, GenerateImageNameOpts,
|
||||
GenerateKeyPairOpts, GenerateTagsOpts, GetMetadataOpts, PushOpts, RemoveContainerOpts,
|
||||
RemoveImageOpts, RunOpts, SignOpts, TagOpts, VerifyOpts,
|
||||
BuildOpts, BuildTagPushOpts, CheckKeyPairOpts, ContainerOpts, CopyOciDirOpts,
|
||||
CreateContainerOpts, GenerateImageNameOpts, GenerateKeyPairOpts, GenerateTagsOpts,
|
||||
GetMetadataOpts, PruneOpts, PushOpts, RechunkOpts, RemoveContainerOpts, RemoveImageOpts,
|
||||
RunOpts, SignOpts, SwitchOpts, TagOpts, VerifyOpts, VolumeOpts,
|
||||
};
|
||||
use types::{
|
||||
BuildDriverType, CiDriverType, DetermineDriver, ImageMetadata, InspectDriverType, Platform,
|
||||
BootDriverType, BuildDriverType, CiDriverType, ImageMetadata, InspectDriverType, Platform,
|
||||
RunDriverType, SigningDriverType,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
|
@ -39,10 +40,15 @@ use crate::logging::Logger;
|
|||
pub use self::{
|
||||
buildah_driver::BuildahDriver, cosign_driver::CosignDriver, docker_driver::DockerDriver,
|
||||
github_driver::GithubDriver, gitlab_driver::GitlabDriver, local_driver::LocalDriver,
|
||||
podman_driver::PodmanDriver, sigstore_driver::SigstoreDriver, skopeo_driver::SkopeoDriver,
|
||||
traits::*,
|
||||
podman_driver::PodmanDriver, rpm_ostree_driver::RpmOstreeDriver,
|
||||
sigstore_driver::SigstoreDriver, skopeo_driver::SkopeoDriver, traits::*,
|
||||
};
|
||||
|
||||
#[cfg(feature = "bootc")]
|
||||
pub use bootc_driver::BootcDriver;
|
||||
|
||||
#[cfg(feature = "bootc")]
|
||||
mod bootc_driver;
|
||||
mod buildah_driver;
|
||||
mod cosign_driver;
|
||||
mod docker_driver;
|
||||
|
|
@ -52,22 +58,25 @@ mod gitlab_driver;
|
|||
mod local_driver;
|
||||
pub mod opts;
|
||||
mod podman_driver;
|
||||
mod rpm_ostree_driver;
|
||||
mod sigstore_driver;
|
||||
mod skopeo_driver;
|
||||
mod traits;
|
||||
pub mod types;
|
||||
|
||||
static INIT: std::sync::LazyLock<Mutex<bool>> = std::sync::LazyLock::new(|| Mutex::new(false));
|
||||
static SELECTED_BUILD_DRIVER: std::sync::LazyLock<RwLock<Option<BuildDriverType>>> =
|
||||
std::sync::LazyLock::new(|| RwLock::new(None));
|
||||
static SELECTED_INSPECT_DRIVER: std::sync::LazyLock<RwLock<Option<InspectDriverType>>> =
|
||||
std::sync::LazyLock::new(|| RwLock::new(None));
|
||||
static SELECTED_RUN_DRIVER: std::sync::LazyLock<RwLock<Option<RunDriverType>>> =
|
||||
std::sync::LazyLock::new(|| RwLock::new(None));
|
||||
static SELECTED_SIGNING_DRIVER: std::sync::LazyLock<RwLock<Option<SigningDriverType>>> =
|
||||
std::sync::LazyLock::new(|| RwLock::new(None));
|
||||
static SELECTED_CI_DRIVER: std::sync::LazyLock<RwLock<Option<CiDriverType>>> =
|
||||
std::sync::LazyLock::new(|| RwLock::new(None));
|
||||
static INIT: AtomicBool = AtomicBool::new(false);
|
||||
static SELECTED_BUILD_DRIVER: LazyLock<RwLock<Option<BuildDriverType>>> =
|
||||
LazyLock::new(|| RwLock::new(None));
|
||||
static SELECTED_INSPECT_DRIVER: LazyLock<RwLock<Option<InspectDriverType>>> =
|
||||
LazyLock::new(|| RwLock::new(None));
|
||||
static SELECTED_RUN_DRIVER: LazyLock<RwLock<Option<RunDriverType>>> =
|
||||
LazyLock::new(|| RwLock::new(None));
|
||||
static SELECTED_SIGNING_DRIVER: LazyLock<RwLock<Option<SigningDriverType>>> =
|
||||
LazyLock::new(|| RwLock::new(None));
|
||||
static SELECTED_CI_DRIVER: LazyLock<RwLock<Option<CiDriverType>>> =
|
||||
LazyLock::new(|| RwLock::new(None));
|
||||
static SELECTED_BOOT_DRIVER: LazyLock<RwLock<Option<BootDriverType>>> =
|
||||
LazyLock::new(|| RwLock::new(None));
|
||||
|
||||
/// Args for selecting the various drivers to use for runtime.
|
||||
///
|
||||
|
|
@ -95,6 +104,9 @@ pub struct DriverArgs {
|
|||
/// containers.
|
||||
#[arg(short = 'R', long)]
|
||||
run_driver: Option<RunDriverType>,
|
||||
|
||||
#[arg(short = 'T', long)]
|
||||
boot_driver: Option<BootDriverType>,
|
||||
}
|
||||
|
||||
macro_rules! impl_driver_type {
|
||||
|
|
@ -108,12 +120,13 @@ macro_rules! impl_driver_init {
|
|||
(@) => { };
|
||||
($init:ident; $($tail:tt)*) => {
|
||||
{
|
||||
let mut initialized = $init.lock().expect("Must lock INIT");
|
||||
|
||||
if !*initialized {
|
||||
if $init.compare_exchange(
|
||||
false,
|
||||
true,
|
||||
std::sync::atomic::Ordering::AcqRel,
|
||||
std::sync::atomic::Ordering::Acquire
|
||||
).is_ok() {
|
||||
impl_driver_init!(@ $($tail)*);
|
||||
|
||||
*initialized = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -162,6 +175,7 @@ impl Driver {
|
|||
args.inspect_driver => SELECTED_INSPECT_DRIVER;
|
||||
args.run_driver => SELECTED_RUN_DRIVER;
|
||||
args.signing_driver => SELECTED_SIGNING_DRIVER;
|
||||
args.boot_driver => SELECTED_BOOT_DRIVER;
|
||||
default => SELECTED_CI_DRIVER;
|
||||
}
|
||||
}
|
||||
|
|
@ -206,7 +220,7 @@ impl Driver {
|
|||
info!("Retrieving OS version from {oci_ref}");
|
||||
|
||||
let os_version = Self::get_metadata(
|
||||
&GetMetadataOpts::builder()
|
||||
GetMetadataOpts::builder()
|
||||
.image(oci_ref)
|
||||
.maybe_platform(platform)
|
||||
.build(),
|
||||
|
|
@ -247,6 +261,10 @@ impl Driver {
|
|||
pub fn get_ci_driver() -> CiDriverType {
|
||||
impl_driver_type!(SELECTED_CI_DRIVER)
|
||||
}
|
||||
|
||||
pub fn get_boot_driver() -> BootDriverType {
|
||||
impl_driver_type!(SELECTED_BOOT_DRIVER)
|
||||
}
|
||||
}
|
||||
|
||||
#[cached(
|
||||
|
|
@ -278,9 +296,9 @@ fn get_version_run_image(oci_ref: &Reference) -> Result<u64> {
|
|||
};
|
||||
|
||||
let output = Driver::run_output(
|
||||
&RunOpts::builder()
|
||||
.image(oci_ref.to_string())
|
||||
.args(bon::vec![
|
||||
RunOpts::builder()
|
||||
.image(&oci_ref.to_string())
|
||||
.args(&bon::vec![
|
||||
"/bin/bash",
|
||||
"-c",
|
||||
r#"awk -F= '/^VERSION_ID=/ {gsub(/"/, "", $2); print $2}' /usr/lib/os-release"#,
|
||||
|
|
@ -291,7 +309,7 @@ fn get_version_run_image(oci_ref: &Reference) -> Result<u64> {
|
|||
)?;
|
||||
|
||||
if should_remove {
|
||||
Driver::remove_image(&RemoveImageOpts::builder().image(oci_ref).build())?;
|
||||
Driver::remove_image(RemoveImageOpts::builder().image(oci_ref).build())?;
|
||||
}
|
||||
|
||||
progress.finish_and_clear();
|
||||
|
|
@ -314,15 +332,15 @@ macro_rules! impl_build_driver {
|
|||
}
|
||||
|
||||
impl BuildDriver for Driver {
|
||||
fn build(opts: &BuildOpts) -> Result<()> {
|
||||
fn build(opts: BuildOpts) -> Result<()> {
|
||||
impl_build_driver!(build(opts))
|
||||
}
|
||||
|
||||
fn tag(opts: &TagOpts) -> Result<()> {
|
||||
fn tag(opts: TagOpts) -> Result<()> {
|
||||
impl_build_driver!(tag(opts))
|
||||
}
|
||||
|
||||
fn push(opts: &PushOpts) -> Result<()> {
|
||||
fn push(opts: PushOpts) -> Result<()> {
|
||||
impl_build_driver!(push(opts))
|
||||
}
|
||||
|
||||
|
|
@ -330,11 +348,11 @@ impl BuildDriver for Driver {
|
|||
impl_build_driver!(login())
|
||||
}
|
||||
|
||||
fn prune(opts: &opts::PruneOpts) -> Result<()> {
|
||||
fn prune(opts: PruneOpts) -> Result<()> {
|
||||
impl_build_driver!(prune(opts))
|
||||
}
|
||||
|
||||
fn build_tag_push(opts: &BuildTagPushOpts) -> Result<Vec<String>> {
|
||||
fn build_tag_push(opts: BuildTagPushOpts) -> Result<Vec<String>> {
|
||||
impl_build_driver!(build_tag_push(opts))
|
||||
}
|
||||
}
|
||||
|
|
@ -349,19 +367,19 @@ macro_rules! impl_signing_driver {
|
|||
}
|
||||
|
||||
impl SigningDriver for Driver {
|
||||
fn generate_key_pair(opts: &GenerateKeyPairOpts) -> Result<()> {
|
||||
fn generate_key_pair(opts: GenerateKeyPairOpts) -> Result<()> {
|
||||
impl_signing_driver!(generate_key_pair(opts))
|
||||
}
|
||||
|
||||
fn check_signing_files(opts: &CheckKeyPairOpts) -> Result<()> {
|
||||
fn check_signing_files(opts: CheckKeyPairOpts) -> Result<()> {
|
||||
impl_signing_driver!(check_signing_files(opts))
|
||||
}
|
||||
|
||||
fn sign(opts: &SignOpts) -> Result<()> {
|
||||
fn sign(opts: SignOpts) -> Result<()> {
|
||||
impl_signing_driver!(sign(opts))
|
||||
}
|
||||
|
||||
fn verify(opts: &VerifyOpts) -> Result<()> {
|
||||
fn verify(opts: VerifyOpts) -> Result<()> {
|
||||
impl_signing_driver!(verify(opts))
|
||||
}
|
||||
|
||||
|
|
@ -381,7 +399,7 @@ macro_rules! impl_inspect_driver {
|
|||
}
|
||||
|
||||
impl InspectDriver for Driver {
|
||||
fn get_metadata(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
|
||||
fn get_metadata(opts: GetMetadataOpts) -> Result<ImageMetadata> {
|
||||
impl_inspect_driver!(get_metadata(opts))
|
||||
}
|
||||
}
|
||||
|
|
@ -396,23 +414,23 @@ macro_rules! impl_run_driver {
|
|||
}
|
||||
|
||||
impl RunDriver for Driver {
|
||||
fn run(opts: &RunOpts) -> Result<ExitStatus> {
|
||||
fn run(opts: RunOpts) -> Result<ExitStatus> {
|
||||
impl_run_driver!(run(opts))
|
||||
}
|
||||
|
||||
fn run_output(opts: &RunOpts) -> Result<Output> {
|
||||
fn run_output(opts: RunOpts) -> Result<Output> {
|
||||
impl_run_driver!(run_output(opts))
|
||||
}
|
||||
|
||||
fn create_container(opts: &CreateContainerOpts) -> Result<types::ContainerId> {
|
||||
fn create_container(opts: CreateContainerOpts) -> Result<types::ContainerId> {
|
||||
impl_run_driver!(create_container(opts))
|
||||
}
|
||||
|
||||
fn remove_container(opts: &RemoveContainerOpts) -> Result<()> {
|
||||
fn remove_container(opts: RemoveContainerOpts) -> Result<()> {
|
||||
impl_run_driver!(remove_container(opts))
|
||||
}
|
||||
|
||||
fn remove_image(opts: &RemoveImageOpts) -> Result<()> {
|
||||
fn remove_image(opts: RemoveImageOpts) -> Result<()> {
|
||||
impl_run_driver!(remove_image(opts))
|
||||
}
|
||||
|
||||
|
|
@ -444,7 +462,7 @@ impl CiDriver for Driver {
|
|||
impl_ci_driver!(oidc_provider())
|
||||
}
|
||||
|
||||
fn generate_tags(opts: &GenerateTagsOpts) -> Result<Vec<String>> {
|
||||
fn generate_tags(opts: GenerateTagsOpts) -> Result<Vec<String>> {
|
||||
impl_ci_driver!(generate_tags(opts))
|
||||
}
|
||||
|
||||
|
|
@ -469,27 +487,52 @@ impl CiDriver for Driver {
|
|||
}
|
||||
|
||||
impl ContainerMountDriver for Driver {
|
||||
fn mount_container(opts: &opts::ContainerOpts) -> Result<types::MountId> {
|
||||
fn mount_container(opts: ContainerOpts) -> Result<types::MountId> {
|
||||
PodmanDriver::mount_container(opts)
|
||||
}
|
||||
|
||||
fn unmount_container(opts: &opts::ContainerOpts) -> Result<()> {
|
||||
fn unmount_container(opts: ContainerOpts) -> Result<()> {
|
||||
PodmanDriver::unmount_container(opts)
|
||||
}
|
||||
|
||||
fn remove_volume(opts: &opts::VolumeOpts) -> Result<()> {
|
||||
fn remove_volume(opts: VolumeOpts) -> Result<()> {
|
||||
PodmanDriver::remove_volume(opts)
|
||||
}
|
||||
}
|
||||
|
||||
impl OciCopy for Driver {
|
||||
fn copy_oci_dir(opts: &opts::CopyOciDirOpts) -> Result<()> {
|
||||
fn copy_oci_dir(opts: CopyOciDirOpts) -> Result<()> {
|
||||
SkopeoDriver::copy_oci_dir(opts)
|
||||
}
|
||||
}
|
||||
|
||||
impl RechunkDriver for Driver {
|
||||
fn rechunk(opts: &opts::RechunkOpts) -> Result<Vec<String>> {
|
||||
fn rechunk(opts: RechunkOpts) -> Result<Vec<String>> {
|
||||
PodmanDriver::rechunk(opts)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_boot_driver {
|
||||
($func:ident($($args:expr),*)) => {
|
||||
match Self::get_boot_driver() {
|
||||
#[cfg(feature = "bootc")]
|
||||
BootDriverType::Bootc => BootcDriver::$func($($args,)*),
|
||||
BootDriverType::RpmOstree => RpmOstreeDriver::$func($($args,)*),
|
||||
BootDriverType::None => ::miette::bail!("Cannot perform boot operation when no boot driver exists."),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl BootDriver for Driver {
|
||||
fn status() -> Result<Box<dyn BootStatus>> {
|
||||
impl_boot_driver!(status())
|
||||
}
|
||||
|
||||
fn switch(opts: SwitchOpts) -> Result<()> {
|
||||
impl_boot_driver!(switch(opts))
|
||||
}
|
||||
|
||||
fn upgrade(opts: SwitchOpts) -> Result<()> {
|
||||
impl_boot_driver!(upgrade(opts))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue