Skip to content

Commit

Permalink
buildsys: extend external-files to vendor go modules
Browse files Browse the repository at this point in the history
oci-add-hooks: use new buildsys go module support
hotdog: use new buildsys go module support

Co-authored-by: John McBride <[email protected]>
Co-authored-by: Samuel Karp <[email protected]>
Signed-off-by: John McBride <[email protected]>
  • Loading branch information
jpmcb and samuelkarp committed Aug 25, 2022
1 parent ad3fa44 commit 0a3d118
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 89 deletions.
21 changes: 3 additions & 18 deletions packages/hotdog/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,9 @@ path = "pkg.rs"
[[package.metadata.build-package.external-files]]
url = "https://github.com/bottlerocket-os/hotdog/archive/b85b75576adbbd7e133b54d71ebc11a28acf40db/hotdog-b85b755.tar.gz"
sha512 = "9b2d5cb0e25d774d11dd6eb577e07af85f36fcd6e816b9df88d7ca1da273695f15ce6831026d28e68355512a07d0ac673b5ce9771d969f1c5ca4f14bc631deb8"

[[package.metadata.build-package.external-files]]
url = "https://github.com/opencontainers/runtime-spec/archive/v1.0.2/runtime-spec-1.0.2.tar.gz"
sha512 = "96676b702d02409d33a5c81886c4db4bf45283c628933c6f0f4c2ed0d7cc44fafe95249151d7dc2d1fc5225944d172cdb45fc2f2f5f9bb87531e93421933b664"

[[package.metadata.build-package.external-files]]
url = "https://github.com/golang/sys/archive/8c9f86f7a55f5af45a9080f6ed3ac915382d369c/sys-8c9f86f.tar.gz"
sha512 = "054dfba40563e2537dffcd8464debf44bcb71d5790603f21a324ec940d7018d8161d50d535471f5ffeada9647ef390d599d567dd0515eeaa677103c60e502b40"

[[package.metadata.build-package.external-files]]
path = "go-selinux-v1.10.1.tar.gz"
url = "https://github.com/opencontainers/selinux/archive/refs/tags/v1.10.1.tar.gz"
sha512 = "f79af22c28ac14b3ca93c1c60fc6f986ec6b22c0f2d77fc4192b95e0a497798acfe9be48f4e162e0a31c7e4c3c78470bdee6faab1c06f8688b51a0c20331b77a"

[[package.metadata.build-package.external-files]]
path = "libcap-v1.2.63.tar.gz"
url = "https://git.kernel.org/pub/scm/libs/libcap/libcap.git/snapshot/libcap-cap/v1.2.63.tar.gz"
sha512 = "f88f85ce5849c0c6a519c3f269a5b221a66b98d30abfa15a69a760ba85d84b5cf89f41ad1912fc0643a5533b44f0b2d09597229b61f4d08473ad6124e40bc864"
bundle-modules = [ "go" ]
bundle-path = "hotdog-b85b75576adbbd7e133b54d71ebc11a28acf40db"
bundle-output-path = "hotdog-b85b755-bundled.tar.gz"

[build-dependencies]
glibc = { path = "../glibc" }
Expand Down
50 changes: 9 additions & 41 deletions packages/hotdog/hotdog.spec
Original file line number Diff line number Diff line change
Expand Up @@ -10,67 +10,32 @@
%global gitrev b85b75576adbbd7e133b54d71ebc11a28acf40db
%global shortrev %(c=%{gitrev}; echo ${c:0:7})

%global gosysrev 8c9f86f7a55f5af45a9080f6ed3ac915382d369c
%global gosysrevshort %(c=%{gosysrev}; echo ${c:0:7})

%global runtimespec 1.0.2

%global goselinux 1.10.1

%global libcap 1.2.63

Name: %{_cross_os}hotdog
Version: 1.0.1
Release: 1%{?dist}
Summary: Tool with OCI hooks to run the Log4j Hot Patch in containers
License: Apache-2.0
URL: https://github.com/bottlerocket-os/hotdog
Source0: https://%{goimport}/archive/%{gorev}/%{gorepo}-%{shortrev}.tar.gz
Source1: https://github.com/opencontainers/runtime-spec/archive/v%{runtimespec}/runtime-spec-%{runtimespec}.tar.gz
Source2: https://github.com/golang/sys/archive/%{gosysrev}/sys-%{gosysrevshort}.tar.gz
Source3: https://github.com/opencontainers/selinux/archive/refs/tags/v%{goselinux}.tar.gz#/go-selinux-v%{goselinux}.tar.gz
Source4: https://git.kernel.org/pub/scm/libs/libcap/libcap.git/snapshot/libcap-cap/v%{libcap}.tar.gz#/libcap-v%{libcap}.tar.gz

Source0: %{gorepo}-%{shortrev}-bundled.tar.gz
BuildRequires: %{_cross_os}glibc-devel
Requires: %{_cross_os}log4j2-hotpatch

%description
%{summary}.

%prep
%autosetup -Sgit -n %{gorepo}-%{gitrev} -p1
%cross_go_setup %{gorepo}-%{gitrev} %{goproject} %{goimport}

# We need to manage these third-party dependencies because the hotdog
# "release" that we use doesn't include the `vendor` directory, unlike our other
# go third party dependencies
mkdir -p GOPATH/src/github.com/opencontainers/runtime-spec
tar -C GOPATH/src/github.com/opencontainers/runtime-spec -xzf %{SOURCE1} --strip 1
cp GOPATH/src/github.com/opencontainers/runtime-spec/LICENSE LICENSE.runtime-spec

mkdir -p GOPATH/src/golang.org/x/sys
tar -C GOPATH/src/golang.org/x/sys -xzf %{SOURCE2} --strip 1
cp GOPATH/src/golang.org/x/sys/LICENSE LICENSE.golang-sys

mkdir -p GOPATH/src/github.com/opencontainers/selinux
tar -C GOPATH/src/github.com/opencontainers/selinux -xzf %{SOURCE3} --strip 1
cp GOPATH/src/github.com/opencontainers/selinux/LICENSE LICENSE.go-selinux

mkdir -p GOPATH/src/kernel.org/pub/linux/libs/security/libcap
tar -C GOPATH/src/kernel.org/pub/linux/libs/security/libcap -xzf %{SOURCE4} --strip 2
cp GOPATH/src/kernel.org/pub/linux/libs/security/libcap/License LICENSE.libcap
%setup -q -n %{gorepo}-%{gitrev}

%build
%cross_go_configure %{goimport}
%set_cross_go_flags

# Set CGO_ENABLED=0 to statically link hotdog-hotpath, since it runs inside containers that
# may not have the glibc version used to compile it
# Set `GO111MODULE=off` to force golang to look for the dependencies in the GOPATH
CGO_ENABLED=0 GO111MODULE=off go build -installsuffix cgo -a -ldflags "-s" -o hotdog-hotpatch ./cmd/hotdog-hotpatch
CGO_ENABLED=0 go build ${GOFLAGS} -installsuffix cgo -a -ldflags "-s" -o hotdog-hotpatch ./cmd/hotdog-hotpatch

# The oci hooks commands can be compiled as we usually compile golang packages
for cmd in hotdog-cc-hook hotdog-poststart-hook; do
GO111MODULE=off go build -buildmode=pie -ldflags "${GOLDFLAGS}" -o $cmd ./cmd/$cmd
go build ${GOFLAGS} -buildmode=pie -ldflags "${GOLDFLAGS}" -o $cmd ./cmd/$cmd
done

%install
Expand All @@ -83,9 +48,12 @@ for cmd in hotdog-cc-hook hotdog-poststart-hook; do
install -p -m 0755 $cmd %{buildroot}%{_cross_libexecdir}/hotdog
done

%cross_scan_attribution go-vendor vendor

%files
%license LICENSE LICENSE.runtime-spec LICENSE.golang-sys LICENSE.go-selinux LICENSE.libcap
%license LICENSE
%{_cross_attribution_file}
%{_cross_attribution_vendor_dir}
%dir %{_cross_libexecdir}/hotdog
%dir %{_cross_datadir}/hotdog
%{_cross_libexecdir}/hotdog/hotdog-cc-hook
Expand Down
11 changes: 3 additions & 8 deletions packages/oci-add-hooks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,9 @@ path = "pkg.rs"
[[package.metadata.build-package.external-files]]
url = "https://github.com/awslabs/oci-add-hooks/archive/ef29fe312d2e1858d5eb28ab0abe0cbee298a165/oci-add-hooks-ef29fe3.tar.gz"
sha512 = "018b561f838172e768a70acdeb2c27939f931391ced019a23c5193eee6b8970bc02a3e5fa05917010ca2064d1876649ef139d7657700c42a3ddd6e2c174f27dc"

[[package.metadata.build-package.external-files]]
url = "https://github.com/bitly/go-simplejson/archive/v0.5.0/go-simplejson-0.5.0.tar.gz"
sha512 = "39c0d85d6ee06a8a795c1e344f0669f5ae8371d1122f09a1b13e5ff7629dd7faf633f9fcb449e19aadab9ad3e42e93143205781a822a29f27758872cf7e09e18"

[[package.metadata.build-package.external-files]]
url = "https://github.com/joeshaw/json-lossless/archive/e0cd1ca6349bf167e33d44f28c14c728a277205f/json-lossless-e0cd1ca.tar.gz"
sha512 = "b9eb6170f662a396370ae1e170d89e15efc0a96fee6046fbd749c7a65f09f808e08bc2cf91962db65fd86a2aac4dddf428412b568fe1d03a77a7de22ad0690aa"
bundle-modules = [ "go" ]
bundle-path = "oci-add-hooks-ef29fe312d2e1858d5eb28ab0abe0cbee298a165"
bundle-output-path = "oci-add-hooks-ef29fe3-bundled.tar.gz"

[build-dependencies]
glibc = { path = "../glibc" }
31 changes: 9 additions & 22 deletions packages/oci-add-hooks/oci-add-hooks.spec
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,35 @@

%global gitrev ef29fe312d2e1858d5eb28ab0abe0cbee298a165
%global shortrev %(c=%{gitrev}; echo ${c:0:7})
%global gosimplejson 0.5.0
%global jsonlosslessrev e0cd1ca6349bf167e33d44f28c14c728a277205f
%global jsonlosslessshort %(c=%{jsonlosslessrev}; echo ${c:0:7})

Name: %{_cross_os}oci-add-hooks
Version: 1.0.0
Release: 1%{?dist}
Summary: OCI runtime wrapper that injects OCI hooks
License: Apache-2.0 and MIT
URL: https://github.com/awslabs/oci-add-hooks
Source0: https://%{goimport}/archive/%{gorev}/%{gorepo}-%{shortrev}.tar.gz
Source1: https://github.com/bitly/go-simplejson/archive/v%{gosimplejson}/go-simplejson-%{gosimplejson}.tar.gz
Source2: https://github.com/joeshaw/json-lossless/archive/%{jsonlosslessrev}/json-lossless-%{jsonlosslessshort}.tar.gz

Source0: %{gorepo}-%{shortrev}-bundled.tar.gz
BuildRequires: %{_cross_os}glibc-devel

%description
%{summary}.

%prep
%autosetup -n %{gorepo}-%{gitrev}
%cross_go_setup %{gorepo}-%{gitrev} %{goproject} %{goimport}

# We need to manage these third-party dependencies because the oci-add-hooks
# "release" that we use doesn't include the `vendor` directory, unlike our other
# go third party dependencies
mkdir -p GOPATH/src/github.com/bitly/go-simplejson GOPATH/src/github.com/joeshaw/json-lossless
tar -C GOPATH/src/github.com/bitly/go-simplejson -xzf %{SOURCE1} --strip 1
cp GOPATH/src/github.com/bitly/go-simplejson/LICENSE LICENSE.go-simplejson
tar -C GOPATH/src/github.com/joeshaw/json-lossless -xzf %{SOURCE2} --strip 1
cp GOPATH/src/github.com/joeshaw/json-lossless/LICENSE LICENSE.json-lossless
%setup -q -n %{gorepo}-%{gitrev}

%build
%cross_go_configure %{goimport}
# We use `GO111MODULE=off` to force golang to look for the dependencies in the GOPATH
GO111MODULE=off go build -v -x -buildmode=pie -ldflags="${GOLDFLAGS}" -o oci-add-hooks
%set_cross_go_flags
export LD_VERSION="-X main.commit=oci-add-hooks-%{gitrev}"
go build ${GOFLAGS} -v -x -buildmode=pie -ldflags="${GOLDFLAGS} ${LD_VERSION}" -o oci-add-hooks

%install
install -d %{buildroot}%{_cross_bindir}
install -p -m 0755 oci-add-hooks %{buildroot}%{_cross_bindir}

%cross_scan_attribution go-vendor vendor

%files
%license LICENSE NOTICE LICENSE.go-simplejson LICENSE.json-lossless
%license LICENSE NOTICE
%{_cross_attribution_file}
%{_cross_attribution_vendor_dir}
%{_cross_bindir}/oci-add-hooks
176 changes: 176 additions & 0 deletions tools/buildsys/src/gomod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*!
Packages using the Go programming language may have upstream tar archives that
include only the source code of the project, but not the source code of any
dependencies. The Go programming language promotes the use of "modules" for
dependencies and projects adopting modules will provide go.mod and go.sum
files.
This module extends the functionality of `packages.metadata.build-package.external-files`
and provides the ability to retrieve and validate dependencies
declared using Go modules given a tar archive containing a go.mod and go.sum.
The location where dependencies are retrieved from are controlled by the
standard environment variables employed by the Go tool: GOPROXY, GOSUMDB, and
GOPRIVATE.
*/

pub(crate) mod error;
use error::Result;

use super::manifest;
use duct::cmd;
use snafu::{ensure, OptionExt, ResultExt};
use std::env;
use std::path::{Path, PathBuf};
use std::process::Output;

pub(crate) struct GoMod;

impl GoMod {
pub(crate) fn vendor(
root_dir: &Path,
package_dir: &Path,
gomod: &manifest::ExternalFile,
) -> Result<()> {
let url_file_name = extract_file_name(&gomod.url)?;
let path_arg = &gomod.path.as_ref().unwrap_or(&url_file_name);
ensure!(path_arg.components().count() == 1, error::InputFileSnafu);

let path = package_dir.join(path_arg);
ensure!(path.is_file(), error::InputFileBadSnafu { path });
let mod_dir = gomod.bundle_path.as_ref().context(error::ModDirSnafu)?;
let output_path_arg = gomod
.bundle_output_path
.as_ref()
.context(error::OutputDirSnafu)?;
let output_path = package_dir.join(output_path_arg);

// Return early if the output path exists and is a file, assuming it's already been built
if output_path.exists() && output_path.is_file() {
return Ok(());
}

// Our SDK and toolchain are picked by the external `cargo make` invocation.
let sdk = getenv("BUILDSYS_SDK_IMAGE")?;

// Several Go variables control proxying
let mut goproxy = go_env("GOPROXY").unwrap_or_else(|| "".to_string());
if goproxy.ends_with('\n') {
goproxy.pop();
}
let mut gosumdb = go_env("GOSUMDB").unwrap_or_else(|| "".to_string());
if gosumdb.ends_with('\n') {
gosumdb.pop();
}
let mut goprivate = go_env("GOPRIVATE").unwrap_or_else(|| "".to_string());
if goprivate.ends_with('\n') {
goprivate.pop();
}

let args = DockerGoArgs {
module_path: package_dir,
sdk_image: sdk,
go_mod_cache: &root_dir.join(".gomodcache"),
command: format!(
"tar xf {input} &&
pushd {moddir} &&
export GOPROXY={goproxy} &&
export GOSUMDB={gosumdb} &&
export GOPRIVATE={goprivate} &&
go list -mod=readonly ./... >/dev/null && go mod vendor &&
popd &&
tar czf {output} {moddir} &&
rm -rf {moddir}",
input = path_arg.to_string_lossy(),
moddir = mod_dir.to_string_lossy(),
goproxy = goproxy,
gosumdb = gosumdb,
goprivate = goprivate,
output = output_path_arg.to_string_lossy(),
),
};
docker_go(root_dir, &args)?;

Ok(())
}
}

fn extract_file_name(url: &str) -> Result<PathBuf> {
let parsed = reqwest::Url::parse(url).context(error::InputUrlSnafu { url })?;
let name = parsed
.path_segments()
.context(error::InputFileBadSnafu { path: url })?
.last()
.context(error::InputFileBadSnafu { path: url })?;
Ok(name.into())
}

struct DockerGoArgs<'a> {
module_path: &'a Path,
sdk_image: String,
go_mod_cache: &'a Path,
command: String,
}

/// Run `docker-go` with the specified arguments.
fn docker_go(root_dir: &Path, dg_args: &DockerGoArgs) -> Result<Output> {
let args = vec![
"--module-path",
dg_args
.module_path
.to_str()
.context(error::InputFileSnafu)?,
"--sdk-image",
&dg_args.sdk_image,
"--go-mod-cache",
dg_args
.go_mod_cache
.to_str()
.context(error::InputFileSnafu)?,
"--command",
&dg_args.command,
];
let arg_string = args.join(" ");
let program = root_dir.join("tools/docker-go");
println!("program: {}", program.to_string_lossy());
let output = cmd(program, args)
.stderr_to_stdout()
.stdout_capture()
.unchecked()
.run()
.context(error::CommandStartSnafu)?;

let stdout = String::from_utf8_lossy(&output.stdout);
println!("{}", &stdout);
ensure!(
output.status.success(),
error::DockerExecutionSnafu { args: arg_string }
);
Ok(output)
}

/// Run `go env` with the specified argument.
fn go_env(var: &str) -> Option<String> {
let args = vec!["env", var];
let output = match cmd("go", args)
.stderr_to_stdout()
.stdout_capture()
.unchecked()
.run()
{
Ok(v) => v,
Err(_) => return None,
};
let stdout = String::from_utf8_lossy(&output.stdout);
println!("{}", &stdout);
output.status.success().then(|| stdout.to_string())
}

/// Retrieve a BUILDSYS_* variable that we expect to be set in the environment,
/// and ensure that we track it for changes, since it will directly affect the
/// output.
fn getenv(var: &str) -> Result<String> {
println!("cargo:rerun-if-env-changed={}", var);
env::var(var).context(error::EnvironmentSnafu { var })
}
Loading

0 comments on commit 0a3d118

Please sign in to comment.