Skip to content

Commit

Permalink
fix: Use built-in image inspection for podman and docker
Browse files Browse the repository at this point in the history
  • Loading branch information
gmpinder committed Oct 4, 2024
1 parent 566380a commit 4e0ab37
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 79 deletions.
6 changes: 2 additions & 4 deletions process/drivers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ use self::{
docker_driver::DockerDriver,
github_driver::GithubDriver,
gitlab_driver::GitlabDriver,
image_metadata::ImageMetadata,
local_driver::LocalDriver,
opts::{
BuildOpts, BuildTagPushOpts, CheckKeyPairOpts, GenerateKeyPairOpts, GetMetadataOpts,
Expand All @@ -44,8 +43,8 @@ use self::{
podman_driver::PodmanDriver,
skopeo_driver::SkopeoDriver,
types::{
BuildDriverType, CiDriverType, DetermineDriver, InspectDriverType, RunDriverType,
SigningDriverType,
BuildDriverType, CiDriverType, DetermineDriver, ImageMetadata, InspectDriverType,
RunDriverType, SigningDriverType,
},
};

Expand All @@ -57,7 +56,6 @@ mod docker_driver;
mod functions;
mod github_driver;
mod gitlab_driver;
pub mod image_metadata;
mod local_driver;
pub mod opts;
mod podman_driver;
Expand Down
114 changes: 90 additions & 24 deletions process/drivers/docker_driver.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::{
collections::HashMap,
env,
io::Write,
path::Path,
Expand All @@ -9,35 +10,79 @@ use std::{

use blue_build_utils::{
cmd,
constants::{BB_BUILDKIT_CACHE_GHA, CONTAINER_FILE, DOCKER_HOST, SKOPEO_IMAGE},
constants::{BB_BUILDKIT_CACHE_GHA, CONTAINER_FILE, DOCKER_HOST},
credentials::Credentials,
string_vec,
traits::IntoCollector,
};
use colored::Colorize;
use indicatif::{ProgressBar, ProgressStyle};
use log::{debug, info, trace, warn};
use miette::{bail, IntoDiagnostic, Result};
use miette::{bail, miette, IntoDiagnostic, Report, Result};
use oci_distribution::Reference;
use once_cell::sync::Lazy;
use semver::Version;
use serde::Deserialize;
use tempdir::TempDir;

use crate::{
drivers::{
image_metadata::ImageMetadata,
opts::{RunOptsEnv, RunOptsVolume},
types::Platform,
types::{InspectDriverType, Platform},
Driver,
},
logging::{CommandLogging, Logger},
signal_handler::{add_cid, remove_cid, ContainerId, ContainerRuntime},
};

use super::{
opts::{BuildOpts, BuildTagPushOpts, GetMetadataOpts, PushOpts, RunOpts, TagOpts},
types::ImageMetadata,
BuildDriver, DriverVersion, InspectDriver, RunDriver,
};

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "PascalCase")]
struct DockerImageMetadata {
config: DockerImageMetadataConfig,
repo_digests: Vec<String>,
}

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "PascalCase")]
struct DockerImageMetadataConfig {
labels: HashMap<String, serde_json::Value>,
}

impl TryFrom<Vec<DockerImageMetadata>> for ImageMetadata {
type Error = Report;

fn try_from(mut value: Vec<DockerImageMetadata>) -> Result<Self> {
if value.is_empty() {
bail!("Need at least one metadata entry:\n{value:?}");
}

let mut value = value.swap_remove(0);
if value.repo_digests.is_empty() {
bail!("Metadata requires at least 1 digest:\n{value:#?}");
}

let digest: Reference = value
.repo_digests
.swap_remove(0)
.parse()
.into_diagnostic()?;
let digest = digest
.digest()
.ok_or_else(|| miette!("Unable to read digest from {digest}"))?
.to_string();

Ok(Self {
labels: value.config.labels,
digest,
})
}
}

#[derive(Debug, Deserialize)]
struct DockerVerisonJsonClient {
#[serde(alias = "Version")]
Expand Down Expand Up @@ -280,7 +325,14 @@ impl BuildDriver for DockerDriver {
format!(
"type=image,name={first_image},push=true,compression={},oci-mediatypes=true",
opts.compression
)
),
// Load the image to the local image registry
// if the inspect driver is docker so that
// we don't have to pull the image again to inspect.
if matches!(
Driver::get_inspect_driver(),
InspectDriverType::Docker,
) => "--load",
);
} else {
cmd!(command, "--load");
Expand Down Expand Up @@ -318,34 +370,44 @@ impl BuildDriver for DockerDriver {

impl InspectDriver for DockerDriver {
fn get_metadata(opts: &GetMetadataOpts) -> Result<ImageMetadata> {
trace!("DockerDriver::get_labels({opts:#?})");
trace!("DockerDriver::get_metadata({opts:#?})");

let url = opts.tag.as_ref().map_or_else(
|| format!("docker://{}", opts.image),
|tag| format!("docker://{}:{tag}", opts.image),
|| format!("{}", opts.image),
|tag| format!("{}:{tag}", opts.image),
);

let progress = Logger::multi_progress().add(
ProgressBar::new_spinner()
.with_style(ProgressStyle::default_spinner())
.with_message(format!("Inspecting metadata for {}", url.bold())),
.with_message(format!(
"Inspecting metadata for {}, pulling image...",
url.bold()
)),
);
progress.enable_steady_tick(Duration::from_millis(100));

let mut args = Vec::new();
if !matches!(opts.platform, Platform::Native) {
args.extend(["--override-arch", opts.platform.arch()]);
let mut command = cmd!(
"docker",
"pull",
if !matches!(opts.platform, Platform::Native) => [
"--platform",
opts.platform.to_string(),
],
&url,
);
trace!("{command:?}");

let output = command.output().into_diagnostic()?;

if !output.status.success() {
bail!("Failed to pull {} for inspection!", url.bold());
}
args.extend(["inspect", &url]);

let output = Self::run_output(
&RunOpts::builder()
.image(SKOPEO_IMAGE)
.args(args.collect_into_vec())
.remove(true)
.build(),
)
.into_diagnostic()?;

let mut command = cmd!("docker", "image", "inspect", "--format=json", &url);
trace!("{command:?}");

let output = command.output().into_diagnostic()?;

progress.finish_and_clear();
Logger::multi_progress().remove(&progress);
Expand All @@ -356,7 +418,11 @@ impl InspectDriver for DockerDriver {
bail!("Failed to inspect image {url}")
}

serde_json::from_slice(&output.stdout).into_diagnostic()
serde_json::from_slice::<Vec<DockerImageMetadata>>(&output.stdout)
.into_diagnostic()
.inspect(|metadata| trace!("{metadata:#?}"))
.and_then(ImageMetadata::try_from)
.inspect(|metadata| trace!("{metadata:#?}"))
}
}

Expand Down
26 changes: 0 additions & 26 deletions process/drivers/image_metadata.rs

This file was deleted.

96 changes: 75 additions & 21 deletions process/drivers/podman_driver.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
use std::{
collections::HashMap,
io::Write,
path::Path,
process::{Command, ExitStatus, Stdio},
time::Duration,
};

use blue_build_utils::{
cmd, constants::SKOPEO_IMAGE, credentials::Credentials, traits::IntoCollector,
};
use blue_build_utils::{cmd, credentials::Credentials};
use colored::Colorize;
use indicatif::{ProgressBar, ProgressStyle};
use log::{debug, error, info, trace, warn};
use miette::{bail, miette, IntoDiagnostic, Result};
use miette::{bail, miette, IntoDiagnostic, Report, Result};
use oci_distribution::Reference;
use semver::Version;
use serde::Deserialize;
use tempdir::TempDir;

use crate::{
drivers::{
image_metadata::ImageMetadata,
opts::{RunOptsEnv, RunOptsVolume},
types::ImageMetadata,
types::Platform,
},
logging::{CommandLogging, Logger},
Expand All @@ -31,6 +31,46 @@ use super::{
BuildDriver, DriverVersion, InspectDriver, RunDriver,
};

#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "PascalCase")]
struct PodmanImageMetadata {
labels: HashMap<String, serde_json::Value>,
repo_digests: Vec<String>,
}

impl TryFrom<Vec<PodmanImageMetadata>> for ImageMetadata {
type Error = Report;

fn try_from(mut value: Vec<PodmanImageMetadata>) -> std::result::Result<Self, Self::Error> {
if value.is_empty() {
bail!("Podman inspection must have at least one metadata entry:\n{value:?}");
}
if value.is_empty() {
bail!("Need at least one metadata entry:\n{value:?}");
}

let mut value = value.swap_remove(0);
if value.repo_digests.is_empty() {
bail!("Podman Metadata requires at least 1 digest:\n{value:#?}");
}

let digest: Reference = value
.repo_digests
.swap_remove(0)
.parse()
.into_diagnostic()?;
let digest = digest
.digest()
.ok_or_else(|| miette!("Unable to read digest from {digest}"))?
.to_string();

Ok(Self {
labels: value.labels,
digest,
})
}
}

#[derive(Debug, Deserialize)]
struct PodmanVersionJsonClient {
#[serde(alias = "Version")]
Expand Down Expand Up @@ -194,31 +234,41 @@ impl InspectDriver for PodmanDriver {
trace!("PodmanDriver::get_metadata({opts:#?})");

let url = opts.tag.as_deref().map_or_else(
|| format!("docker://{}", opts.image),
|tag| format!("docker://{}:{tag}", opts.image),
|| format!("{}", opts.image),
|tag| format!("{}:{tag}", opts.image),
);

let progress = Logger::multi_progress().add(
ProgressBar::new_spinner()
.with_style(ProgressStyle::default_spinner())
.with_message(format!("Inspecting metadata for {}", url.bold())),
.with_message(format!(
"Inspecting metadata for {}, pulling image...",
url.bold()
)),
);
progress.enable_steady_tick(Duration::from_millis(100));

let mut args = Vec::new();
if !matches!(opts.platform, Platform::Native) {
args.extend(["--override-arch", opts.platform.arch()]);
let mut command = cmd!(
"podman",
"pull",
if !matches!(opts.platform, Platform::Native) => [
"--platform",
opts.platform.to_string(),
],
&url,
);
trace!("{command:?}");

let output = command.output().into_diagnostic()?;

if !output.status.success() {
bail!("Failed to pull {} for inspection!", url.bold());
}
args.extend(["inspect", &url]);

let output = Self::run_output(
&RunOpts::builder()
.image(SKOPEO_IMAGE)
.args(args.collect_into_vec())
.remove(true)
.build(),
)
.into_diagnostic()?;
let mut command = cmd!("podman", "image", "inspect", "--format=json", &url);
trace!("{command:?}");

let output = command.output().into_diagnostic()?;

progress.finish_and_clear();
Logger::multi_progress().remove(&progress);
Expand All @@ -228,7 +278,11 @@ impl InspectDriver for PodmanDriver {
} else {
bail!("Failed to inspect image {url}");
}
serde_json::from_slice(&output.stdout).into_diagnostic()
serde_json::from_slice::<Vec<PodmanImageMetadata>>(&output.stdout)
.into_diagnostic()
.inspect(|metadata| trace!("{metadata:#?}"))
.and_then(TryFrom::try_from)
.inspect(|metadata| trace!("{metadata:#?}"))
}
}

Expand Down
2 changes: 1 addition & 1 deletion process/drivers/skopeo_driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use miette::{bail, IntoDiagnostic, Result};

use crate::{drivers::types::Platform, logging::Logger};

use super::{image_metadata::ImageMetadata, opts::GetMetadataOpts, InspectDriver};
use super::{opts::GetMetadataOpts, types::ImageMetadata, InspectDriver};

#[derive(Debug)]
pub struct SkopeoDriver;
Expand Down
Loading

0 comments on commit 4e0ab37

Please sign in to comment.