Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: containers/automation
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 3028970f0cd39d165e85ff75a9826408665e1a17
Choose a base ref
..
head repository: containers/automation
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 5948acf506a7cf9eb8d98928917e9462df23083b
Choose a head ref
Showing with 96 additions and 64 deletions.
  1. +1 −1 build-push/README.md
  2. +76 −58 build-push/bin/build-push.sh
  3. +3 −0 build-push/test/fake_buildah.sh
  4. +16 −5 build-push/test/testbin-build-push.sh
2 changes: 1 addition & 1 deletion build-push/README.md
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ and push multi-arch container images for that project.
## VM Environment Requirements

* The `build-push.sh` script is installed using the automation installer.
* Executables for `jq`, `podman`, `buildah`, and `skopeo` are available.
* Executables for `jq`, `podman` and `buildah` are available.
* The kernel is configured to use QEMU emulation for non-native binary execution.
* Fedora container images for all target architectures are present. The
version (tag) of these cached images correspond to the host platform version.
134 changes: 76 additions & 58 deletions build-push/bin/build-push.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
#!/bin/bash

# This is a simple wrapper around buildah/podman image build, followed
# by an optional registry server push. It's goal is to provide an
# abstraction layer for additional automation. Though it may be useful
# on it's own, this is not it's primary purpose.

# NOTE: This requires buildah 1.23 or later!
# This is a wrapper around buildah bud, coupled with automatic tagging
# capibility, and post-build image modification, and registry server push.
# It's goal is to provide an abstraction layer for by additional build
# automation. Though it may be useful on it's own, this is not it's
# primary purpose.

# Requirements:
# * jq
# * compiled 'platform' binary
# * buildah 1.23 or later

set -eo pipefail

@@ -15,19 +18,8 @@ set -eo pipefail
AUTOMATION_LIB_PATH="${AUTOMATION_LIB_PATH:-$(dirname $(realpath ${BASH_SOURCE[0]}))/../../common/lib}"
source $AUTOMATION_LIB_PATH/common_lib.sh

# Useful for non-standard installations
RUNTIME="${RUNTIME:-$(type -P buildah)}"
PODMAN="${PODMAN:-$(type -P podman)}"

# Used with --tagcmd
ENTRYARG="${ENTRYARG:-/bin/bash}"

# Not likely overridden, but keep the possibility open
PARALLEL_JOBS="${PARALLEL_JOBS:-$(egrep '^processor' /proc/cpuinfo | wc -l)}"
PLATFORMOS="${PLATFORMOS:-linux}"

# List of variable names to export for --modcmd
_MODCMD_ENV="RUNTIME ENTRYARG PLATFORMOS FQIN CONTEXT NOPUSH ARCHES TAGCMD BUILD_ARGS REGSERVER NAMESPACE IMGNAME NAMESPACE_USERNAME NAMESPACE_PASSWORD TAGCMDVAL BUILDIID"
# Useful for non-standard installations & testing
RUNTIME="${RUNTIME:-$(type -P buildah||echo /bin/true)}" # see check_dependencies()

# Simple error-message strings
E_NOREQ="Must specify non-empty values for required arguments."
@@ -38,6 +30,9 @@ E_ONEARCH="Must specify --arches=<value> with '=', and <value> being a CSV list
E_TAGVAL="Must specify --tagcmd=<value> with '=', and <value> being a (quoted) string, not:"
E_MODVAL="Must specify --modcmd=<value> with '=', and <value> being a (quoted) string, not:"
E_USERPASS="When --nopush not specified, must export non-empty value for variable:"
E_NORUNTIME="Unable to find buildah (\$RUNTIME) on path: $PATH"
E_NOGOARCH="Unable to determine the local system architecture, is \$RUNTIME correct:"
E_NOJQ="Unable to find 'jq' executable on path: $PATH"
E_USAGE="
Usage: $(basename ${BASH_SOURCE[0]}) [options] <FQIN> <Context> [extra...]
@@ -57,13 +52,14 @@ Zero or more [options] and [extra...] optional arguments:
--arches=<value> specifies a CSV list containing additional architectures
to build images for. No checks are performed to ensure support by the
base-image manifest. Note: The '=' is required.
base-image manifest. These must be the canonical CPU architecture names
used/supported by golang - 'uname -m' will cause unpredictable results!
Note: The '=' is required.
--tagcmd=<value> specifies a string to execute inside a successfully
built image. When non-empty standard-output is produced, it will be
interpreted as a space-separated list of aditional tags to apply on
<FQIN>:latest Any embedded quoting will be preserved. The $PODMAN
command must be available on the system.
interpreted as a space-separated list of additional tags to apply on
<FQIN>:latest Any embedded quoting will be preserved.
--modcmd=<value> specifies a string to execute on the host after a
successful build, but prior to pushing. It will be passed the full path
@@ -90,15 +86,7 @@ Required Environment Variables
Optional Environment Variables:
\$RUNTIME specifies the complete path to an alternate executable
to use for building. Defaults to the location of 'buildah', but
the script will adjust for building with 'podman'.
\$PODMAN specifies the complete path to an alternate executable
to use for use with --tagcmd.
\$ENTRYARG specifies the value passed to the --entrypoint option
when executing the --tagcmd value inside the built image. Defaults
to '/bin/bash'.
to use for building. Defaults to the location of 'buildah'.
\$PARALLEL_JOBS specifies the number of builds to execute in parallel.
When unspecified, it defaults to the number of processor (threads) on
@@ -112,22 +100,45 @@ die_help() {
die "$err"
}

# Argument definitions - parsing function follows
FQIN="" # required (fully-qualified-image-name)
CONTEXT="" # required (directory path)
NOPUSH=1 # optional (1 means push, 0 means do not)
declare -a ARCHES
# Can't use $(uname -m) because (for example) "x86_64" != "amd64" in registries
ARCHES=($(go env GOARCH)) # optional (Native architecture always first|only item)
TAGCMD="" # optional
MODCMD="" # optional
declare -a BUILD_ARGS
BUILD_ARGS=() # optional
REGSERVER="" # parsed out of FQIN
NAMESPACE="" # parsed out of FQIN
IMGNAME="" # parsed out of FQIN
unset NAMESPACE_USERNAME # lookup based on $NAMESPACE when $NOPUSH=1
unset NAMESPACE_PASSWORD # lookup based on $NAMESPACE when $NOPUSH=1
check_dependencies() {
if [[ "$RUNTIME" =~ true ]]; then
die_help "$E_NORUNTIME"
elif [[ -z "$NATIVE_GOARCH" ]]; then
die_help "$E_NOGOARCH '$RUNTIME'"
elif ! type -P jq &>/dev/null; then
die_help "$E_NOJQ"
fi
}

init() {
# Can't use $(uname -m) because (for example) "x86_64" != "amd64" in registries
# This will be verified, see check_dependencies()
NATIVE_GOARCH="${NATIVE_GOARCH:-$($RUNTIME info --format='{{.host.arch}}')}"
PARALLEL_JOBS="${PARALLEL_JOBS:-$($RUNTIME info --format='{{.host.cpus}}')}"

# Not likely overridden, but keep the possibility open
PLATFORMOS="${PLATFORMOS:-linux}"

# Env. vars set by parse_args()
FQIN="" # required (fully-qualified-image-name)
CONTEXT="" # required (directory path)
NOPUSH=1 # optional (1 means push, 0 means do not)
declare -a ARCHES
ARCHES=("$NATIVE_GOARCH") # optional (Native architecture always first|only item)
TAGCMD="" # optional
MODCMD="" # optional
declare -a BUILD_ARGS
BUILD_ARGS=() # optional
REGSERVER="" # parsed out of FQIN
NAMESPACE="" # parsed out of FQIN
IMGNAME="" # parsed out of FQIN
unset NAMESPACE_USERNAME # lookup based on $NAMESPACE when $NOPUSH=1
unset NAMESPACE_PASSWORD # lookup based on $NAMESPACE when $NOPUSH=1

# List of variable names to export for --modcmd
_MODCMD_ENV="RUNTIME PLATFORMOS FQIN CONTEXT NOPUSH ARCHES TAGCMD BUILD_ARGS REGSERVER NAMESPACE IMGNAME TAGCMDVAL BUILDIID"
}

parse_args() {
local -a args
local arg
@@ -138,11 +149,7 @@ parse_args() {

dbg "in parse_args()"

# Handle help first before anything else
if grep -q -- '--help' <<<"$@"; then
echo "$E_USAGE" > /dev/stdout # allow grep'ing
exit 0
elif [[ $# -lt 2 ]]; then
if [[ $# -lt 2 ]]; then
die_help "$E_NOREQ"
fi

@@ -198,6 +205,8 @@ parse_args() {
nsp_var="$(tr '[:lower:]' '[:upper:]'<<<${NAMESPACE})_PASSWORD"
NAMESPACE_USERNAME="${!nsu_var}"
NAMESPACE_PASSWORD="${!nsp_var}"
# Leak as little as possible into any child processes
unset "$nsu_var" "$nsu_var"
fi

# validate parsed argument contents
@@ -222,6 +231,7 @@ parse_args() {
fi

dbg "Processed:
RUNTIME='$RUNTIME'
FQIN='$FQIN'
CONTEXT='$CONTEXT'
NOPUSH='$NOPUSH'
@@ -248,9 +258,6 @@ parallel_build() {
req_env_vars FQIN ARCHES CONTEXT REGSERVER NAMESPACE IMGNAME
req_env_vars PARALLEL_JOBS PLATFORMOS RUNTIME

# Support for RUNTIME=podman
if [[ "$(basename $RUNTIME)" != "buildah" ]]; then build=build; fi

for arch in "${ARCHES[@]}"; do
platforms="$platforms --platform=$PLATFORMOS/$arch"
done
@@ -291,11 +298,14 @@ confirm_arches() {

TAGCMDVAL="" # Set non-empty if --tagcmd output is also non-empty
handle_tagcmd() {
local ctr
local output
local _sr
dbg "in handle_tagcmd()"
ctr=$($RUNTIME from $FQIN:latest)
# Expect/assume $TAGCMD to have embedded quoting where appropriate
output=$($PODMAN run --rm --entrypoint="$ENTRYARG" $FQIN:latest $TAGCMD)
output=$($RUNTIME run --rm $ctr $TAGCMD)
$RUNTIME rm $ctr
dbg "Output was: $output"

if ((DEBUG)); then _sr="showrun"; fi
@@ -314,7 +324,7 @@ handle_tagcmd() {
parallel_build &> /dev/null
)
else
warn "Ignoring output from tag-command: '$output'"
warn "Ignoring more/less than one-word output from tag-command: '$output'"
fi
}

@@ -330,6 +340,14 @@ push_images() {

##### MAIN() #####

# Handle requested help first before anything else
if grep -q -- '--help' <<<"$@"; then
echo "$E_USAGE" > /dev/stdout # allow grep'ing
exit 0
fi

check_dependencies
init
parse_args "$@"
parallel_build
confirm_arches
3 changes: 3 additions & 0 deletions build-push/test/fake_buildah.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

echo "$@"
21 changes: 16 additions & 5 deletions build-push/test/testbin-build-push.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
#!/bin/bash

TEST_SOURCE_DIRPATH=$(realpath $(dirname "${BASH_SOURCE[0]}"))

# Load standardized test harness
source $(dirname "${BASH_SOURCE[0]}")/testlib.sh || exit 1
source $TEST_SOURCE_DIRPATH/testlib.sh || exit 1

SUBJ_FILEPATH="$TEST_DIR/$SUBJ_FILENAME"
TEST_CONTEXT="$TEST_DIR/../test/test_context"
TEST_CONTEXT="$TEST_SOURCE_DIRPATH/test_context"
EMPTY_CONTEXT=$(mktemp -d -p '' .tmp_$(basename ${BASH_SOURCE[0]})_XXXX)

EXP_ERR_RX="ERROR: Must.+required arguments."
test_cmd "Verify error when buildah can't be found" \
1 "ERROR:.+find buildah.+/usr/local/bin" \
bash -c "$SUBJ_FILEPATH 2>&1"

# Support basic testing w/o a buildah binary available
export RUNTIME="$TEST_SOURCE_DIRPATH/fake_buildah.sh"
export NATIVE_GOARCH="${NATIVE_GOARCH:-$($RUNTIME info --format='{{.host.arch}}')}"
export PARALLEL_JOBS="${PARALLEL_JOBS:-$($RUNTIME info --format='{{.host.cpus}}')}"

test_cmd "Verify error when executed w/o any arguments" \
1 "$EXP_ERR_RX" \
1 "ERROR: Must.+required arguments." \
bash -c "$SUBJ_FILEPATH 2>&1"

test_cmd "Verify error when specify partial required arguments" \
1 "$EXP_ERR_RX" \
1 "ERROR: Must.+required arguments." \
bash -c "$SUBJ_FILEPATH foo 2>&1"

test_cmd "Verify error when executed bad Containerfile directory" \
@@ -56,6 +66,7 @@ test_cmd "Verify error when --modcmd specified without an '='" \

# A specialized non-container environment required to run these
if [[ -n "$BUILD_PUSH_TEST_BUILDS" ]]; then
unset RUNTIME NATIVE_GOARCH PARALLEL_JOBS
source $(dirname "${BASH_SOURCE[0]}")/testbuilds.sh
else
echo "WARNING: Set \$BUILD_PUSH_TEST_BUILDS non-empty to fully test build_push."