Skip to content

Commit

Permalink
Merge pull request #423 from cbgbt/docker-23
Browse files Browse the repository at this point in the history
Require Docker 23, Statically link Krane
  • Loading branch information
cbgbt authored Dec 30, 2024
2 parents 2ae29fa + 5ba62f9 commit cd7e183
Show file tree
Hide file tree
Showing 35 changed files with 1,242 additions and 874 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,4 @@ jobs:
- uses: actions/setup-go@v5
with:
go-version: "^1.18"
# Install `patch`, needed to build `krane-bundle`
- run: sudo apt-get install -y patch
- run: make build
60 changes: 52 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ targets = ["x86_64-unknown-linux-musl", "aarch64-unknown-linux-musl"]

[workspace.metadata.cross.build]
pre-build = [
# install golang and patch for krane-bundle
"apt update && apt --assume-yes install golang-1.22 patch",
# install golang and patch for krane-static
"apt update && apt --assume-yes install golang-1.22",
"update-alternatives --install /usr/bin/go go /usr/lib/go-1.22/bin/go 10",
# give the builder access to the go build and module caches
"mkdir /.cache && chmod a+rw /.cache",
Expand All @@ -51,7 +51,7 @@ bottlerocket-types = { version = "0.0.14", git = "https://github.com/bottlerocke
bottlerocket-variant = { version = "0.1", path = "tools/bottlerocket-variant" }
buildsys = { version = "0.1", path = "tools/buildsys", lib = true, artifact = [ "bin:buildsys" ] }
buildsys-config = { version = "0.1", path = "tools/buildsys-config" }
krane-bundle = { version = "0.1", path = "tools/krane" }
krane-static = { version = "0.1", path = "tools/krane" }
oci-cli-wrapper = { version = "0.1", path = "tools/oci-cli-wrapper" }
parse-datetime = { version = "0.1", path = "tools/parse-datetime" }
pipesys = { version = "0.1", path = "tools/pipesys", lib = true, artifact = [ "bin:pipesys" ] }
Expand Down Expand Up @@ -84,6 +84,7 @@ bytes = "1"
chrono = { version = "0.4", default-features = false }
clap = "4"
coldsnap = { version = "0.6", default-features = false }
ctrlc = "3"
daemonize = "0.5"
duct = "0.13"
env_logger = "0.11"
Expand Down Expand Up @@ -124,6 +125,7 @@ tabled = "0.10"
tar = "0.4"
tempfile = "3"
term_size = "0.3"
test-case = "3"
tinytemplate = "1"
tokio = "1"
tokio-stream = "0.1"
Expand Down
19 changes: 8 additions & 11 deletions tools/attribution/attribution.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,20 @@ echo "Clarifying crate dependency licenses..."
cargo --locked Cargo.toml

# =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^=
# go-containerregistry
pushd /src/tools/krane
../build-cache-fetch hashes/crane
TARBALL=$(grep -oP '\(\K[^\)]*' hashes/crane)
GO_CONTAINERREGISTRY_UNPACK_DIR=$(mktemp -d)
tar --strip-components=1 -xvf "${TARBALL}" -C "${GO_CONTAINERREGISTRY_UNPACK_DIR}"

pushd "${GO_CONTAINERREGISTRY_UNPACK_DIR}/cmd/krane"
# krane-static
echo "Clarifying golang dependencies of krane-static"
KRANE_STATIC_VENDOR_DIR=$(mktemp -d)
cp -r /src/tools/krane/go-src/* "${KRANE_STATIC_VENDOR_DIR}"

pushd "${KRANE_STATIC_VENDOR_DIR}"
go mod vendor
popd

/usr/libexec/tools/bottlerocket-license-scan \
--clarify /src/clarify.toml \
--spdx-data /usr/libexec/tools/spdx-data \
--out-dir ${LICENSEDIR}/krane \
go-vendor "${GO_CONTAINERREGISTRY_UNPACK_DIR}/cmd/krane/vendor"
popd
--out-dir ${LICENSEDIR}/krane-static \
go-vendor "${KRANE_STATIC_VENDOR_DIR}/vendor"

# =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^= =^.^=
# cargo-make (we currently use cargo-make from the SDK, but will ship it in Twoliter in the future)
Expand Down
8 changes: 2 additions & 6 deletions tools/krane/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "krane-bundle"
name = "krane-static"
version = "0.1.0"
authors = ["Sean P. Kelly <[email protected]>"]
license = "Apache-2.0 OR MIT"
Expand All @@ -8,11 +8,7 @@ publish = false

[dependencies]
anyhow.workspace = true
flate2.workspace = true
lazy_static.workspace = true
tempfile.workspace = true
libc.workspace = true

[build-dependencies]
flate2.workspace = true
tar.workspace = true
which.workspace = true
8 changes: 3 additions & 5 deletions tools/krane/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
## krane-bundle
## krane-static

This crate packages the `krane` utility from [google/go-containerregistry].

The utility is compiled by a build script, the output of which is compressed and stored in the Rust
crate as via `include_bytes!`.
At runtime, `krane-bundle` writes the decompressed binary to a temp file, passing the
filepath of that file to any caller.
The program is replicated as static library exposed via C FFI.
Rust bindings are provided which imitate `std::process::Command::output`.

[google/go-containerregistry]: https://github.com/google/go-containerregistry
109 changes: 16 additions & 93 deletions tools/krane/build.rs
Original file line number Diff line number Diff line change
@@ -1,84 +1,38 @@
use flate2::{read::GzDecoder, write::GzEncoder};
use std::fs::File;
use std::io::{self, prelude::*};
use std::path::{Path, PathBuf};
use std::env;
use std::path::PathBuf;
use std::process::Command;
use std::{env, fs};
use tar::Archive;

const CRANE_VERSION: &str = "0.20.1";

const REQUIRED_TOOLS: &[&str] = &["patch", "go"];
const REQUIRED_TOOLS: &[&str] = &["go"];

fn main() {
let script_dir = env::current_dir().unwrap();
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());

println!("cargo::rerun-if-changed=../build-cache-fetch");
println!("cargo::rerun-if-changed=hashes/crane");
println!("cargo::rerun-if-changed=patches");
println!("cargo::rerun-if-changed=go-src");

ensure_required_tools_installed();

// Download and checksum-verify crane
env::set_current_dir(&out_dir).expect("Failed to set current directory");
Command::new(script_dir.join("../build-cache-fetch"))
.arg(script_dir.join("hashes/crane"))
.status()
.expect("Failed to execute build-cache-fetch");

// extract crane sources
let crane_archive = out_dir.join(format!("go-containerregistry-v{CRANE_VERSION}.tar.gz"));
let crane_tgz = File::open(&crane_archive).expect("Failed to open crane archive");
let mut tar_archive = Archive::new(GzDecoder::new(crane_tgz));

let crane_output_dir = out_dir.join(format!("go-containerregistry-v{CRANE_VERSION}"));
tar_archive
.unpack(&crane_output_dir)
.expect("Failed to extract crane sources");

// Perform any local modifications
let crane_source_dir = crane_output_dir.join(format!("go-containerregistry-{CRANE_VERSION}"));
apply_source_patches(&crane_source_dir, script_dir.join("patches"));

// build krane
let build_output_loc = out_dir.join("krane");
Command::new("go")
.arg("build")
// build krane FFI wrapper
let build_output_loc = out_dir.join("libkrane.a");
let exit_status = Command::new("go")
.env("GOOS", get_goos())
.env("GOARCH", get_goarch())
.arg("build")
.arg("-buildmode=c-archive")
.arg("-o")
.arg(&build_output_loc)
.current_dir(crane_source_dir.join("cmd/krane"))
.arg("main.go")
.current_dir(script_dir.join("go-src"))
.status()
.expect("Failed to build crane");

// compress krane
let krane_gz_path = out_dir.join("krane.gz");
let compressed_output_file =
File::create(&krane_gz_path).expect("Failed to crate krane.gz file");

let krane_binary = File::open(&build_output_loc).expect("Failed to open krane binary");
let mut reader = io::BufReader::new(&krane_binary);
let mut encoder = GzEncoder::new(&compressed_output_file, flate2::Compression::best());

let mut buffer = Vec::with_capacity(
krane_binary
.metadata()
.expect("Failed to get krane binary metadata")
.len() as usize,
assert!(
exit_status.success(),
"Failed to build krane -- go compiler exited nonzero"
);
reader
.read_to_end(&mut buffer)
.expect("Failed to read krane binary");
encoder
.write_all(&buffer)
.expect("Failed to write compressed krane binary");
encoder
.finish()
.expect("Failed to finish writing compressed krane binary");

println!("cargo::rustc-env=KRANE_GZ_PATH={}", krane_gz_path.display());
println!("cargo:rustc-link-search=native={}", out_dir.display());
println!("cargo:rustc-link-lib=static=krane");
}

fn ensure_required_tools_installed() {
Expand All @@ -88,42 +42,12 @@ fn ensure_required_tools_installed() {
}
}

fn apply_source_patches(source_path: impl AsRef<Path>, patch_dir: impl AsRef<Path>) {
let source_path = source_path.as_ref();
let patch_dir = patch_dir.as_ref();

let mut patches = fs::read_dir(patch_dir)
.expect("Failed to read patch directory")
.filter_map(|entry| entry.ok())
.map(|entry| entry.path())
.filter(|path| path.extension().map(|ext| ext == "patch").unwrap_or(false))
.collect::<Vec<_>>();
patches.sort();

for patch in patches {
println!("Executing `patch -p1 -i '{}'`", patch.display());

let patch_status = Command::new("patch")
.current_dir(source_path)
.arg("-p1")
.arg("-i")
.arg(patch.as_os_str())
.status()
.expect("Failed to execute patch command");

if !patch_status.success() {
panic!("Failed to apply patch '{}'", patch.display());
}
}
}

fn get_goos() -> &'static str {
let target_os = env::var("CARGO_CFG_TARGET_OS").expect("Failed to read CARGO_CFG_TARGET_OS");
match target_os.as_str() {
"linux" => "linux",
"windows" => "windows",
"macos" => "darwin",
// Add more mappings as needed
other => panic!("Unsupported target OS: {}", other),
}
}
Expand All @@ -137,7 +61,6 @@ fn get_goarch() -> &'static str {
"aarch64" => "arm64",
"arm" => "arm",
"wasm32" => "wasm",
// Add more mappings as needed
other => panic!("Unsupported target architecture: {}", other),
}
}
Loading

0 comments on commit cd7e183

Please sign in to comment.