Skip to content

Commit

Permalink
Add build-push VM image build automation
Browse files Browse the repository at this point in the history
Signed-off-by: Chris Evich <[email protected]>
  • Loading branch information
cevich committed Mar 23, 2022
1 parent cc1e499 commit 551b32a
Show file tree
Hide file tree
Showing 9 changed files with 392 additions and 10 deletions.
4 changes: 4 additions & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,9 @@ cache_images_task:
- <<: *cache_image
env:
PACKER_BUILDS: "ubuntu"
- <<: *cache_image
env:
PACKER_BUILDS: "build-push"
env:
GAC_JSON: ENCRYPTED[7fba7fb26ab568ae39f799ab58a476123206576b0135b3d1019117c6d682391370c801e149f29324ff4b50133012aed9]
script: "ci/make_cache_images.sh"
Expand Down Expand Up @@ -238,6 +241,7 @@ imgts_task:
fedora-netavark-c${IMG_SFX}
fedora-podman-py-c${IMG_SFX}
ubuntu-c${IMG_SFX}
build-push-c${IMG_SFX}
clone_script: &noop mkdir -p "${CIRRUS_WORKING_DIR}" # source is not needed
script: "/usr/local/bin/entrypoint.sh"

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ see step 4 below.
* The bulk of the packaging work occurs next, from the `cache_images/*_packaging.sh`
scripts. **This is most likely what you want to modify.**

* Unlike the Fedora and Ubuntu scripts, the `build-push` scripts (and VM image)
is not for general-purpose use. It's tightly-coupled with `build-push` scripts
in the
[containers/automation repository](https://github.com/containers/automation).
Chances are good that's what you want to change, not the VM image or scripts.

* Some non-packaged/source-based tooling is installed using the
`cache_images/podman_tooling.sh` script. These are slightly fragile, as
they always come from upstream (master) podman. Avoid adding/changing
Expand Down
139 changes: 139 additions & 0 deletions build-push/bin/main.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#!/bin/bash

# This script is not intended for humans. It should be run by automation
# at the branch-level in automation for the skopeo, buildah, and podman
# repositories. It's purpose is to produce a multi-arch container image
# based on the contents of context subdirectory. At runtime, $PWD is assumed
# to be the root of the cloned git repository.
#
# The first argument to the script, should be the URL of the git repository
# in question. Though at this time, this is only used for labeling the
# resulting image.
#
# The second argument to this script is the relative path to the build context
# subdirectory. The basename of this subdirectory indicates the
# type of image being built (i.e. `upstream`, `testing`, or `stable`).
# Depending on this value, the image may be pushed to multiple container
# registries.

set -eo pipefail

if [[ -r "/etc/automation_environment" ]]; then
source /etc/automation_environment # defines AUTOMATION_LIB_PATH
#shellcheck disable=SC1090,SC2154
source "$AUTOMATION_LIB_PATH/common_lib.sh"
else
echo "Expecting to find automation common library installed."
exit 1
fi

if [[ -z $(type -P build-push.sh) ]]; then
die "It does not appear that build-push.sh is installed properly"
fi

if ! [[ -d "$PWD/.git" ]]; then
die "The current directory ($PWD) does not appear to be the root of a git repo."
fi

# Assume transitive debugging state for build-push.sh if set
export DEBUG

# Arches to build by default - may be overridden for testing
ARCHES="${ARCHES:-amd64,ppc64le,s390x,arm64}"

# First arg (REPO_URL) is the clone URL for repository for informational purposes
REPO_URL="$1"
REPO_NAME=$(basename "${REPO_URL%.git}")
# Second arg (CTX_SUB) is the context subdirectory relative to the clone path
CTX_SUB="$2"
# Basename of second arg names the image contents
CTX_NAME=$(basename "$CTX_SUB")
_REG="quay.io"
if [[ "$REPO_NAME" =~ testing ]]; then
_REG="example.com"
fi
REPO_FQIN="$_REG/$REPO_NAME/$CTX_NAME"
req_env_vars REPO_URL REPO_NAME CTX_SUB CTX_NAME

# Common library defines SCRIPT_FILENAME
# shellcheck disable=SC2154
dbg "$SCRIPT_FILENAME operating constants:
REPO_URL=$REPO_URL
REPO_NAME=$REPO_NAME
CTX_SUB=$CTX_SUB
CTX_NAME=$CTX_NAME
REPO_FQIN=$REPO_FQIN
"

# Set non-zero to avoid actually executing build-push, simply print
# the command-line that would have been executed
DRYRUN=${DRYRUN:-0}
_DRNOPUSH=""
if ((DRYRUN)); then
_DRNOPUSH="--nopush"
warn "Operating in dry-run mode with $_DRNOPUSH"
fi

### MAIN

head_sha=$(git rev-parse HEAD)
dbg "HEAD is $head_sha"
# Labels to add to all images
# N/B: These won't show up in the manifest-list itself, only it's constituents.
lblargs="\
--label=org.opencontainers.image.source=$REPO_URL \
--label=org.opencontainers.image.revision=$head_sha \
--label=org.opencontainers.image.created=$(date -u --iso-8601=seconds)"
dbg "lblargs=$lblargs"

# tag_version.sh is sensitive to this value if set
export img_cmd_version=""

# For stable images, the version number of the command is needed for tagging.
if [[ "$CTX_NAME" == "stable" ]]; then
# only native arch is needed to extract the version
dbg "Building local-arch image to extract stable version number"
podman build -t $REPO_FQIN ./$CTX_SUB

case "$REPO_NAME" in
skopeo) version_cmd="--version" ;;
buildah) version_cmd="buildah --version" ;;
podman) version_cmd="podman --version" ;;
testing) version_cmd="cat FAKE_VERSION" ;;
*) die "Unknown/unsupported repo '$REPO_NAME'" ;;
esac

pvcmd="podman run -i --rm $REPO_FQIN $version_cmd"
dbg "Extracting version with command: $pvcmd"
version_output=$($pvcmd)
dbg "version output:
$version_output
"
img_cmd_version=$(awk -r -e '/^.+ version /{print $3}' <<<"$version_output")
dbg "parsed version: $img_cmd_version"
test -n "$img_cmd_version"
lblargs="$lblargs --label=org.opencontainers.image.version=$img_cmd_version"
# Prevent temporary build colliding with multi-arch manifest list (built next)
# but preserve image (by ID) for use as cache.
dbg "Un-tagging $REPO_FQIN"
podman untag $REPO_FQIN

# Stable images get pushed to 'containers' namespace as latest & version-tagged
build-push.sh \
$_DRNOPUSH \
--arches=$ARCHES \
--modcmd=tag_version.sh \
$_REG/containers/$REPO_NAME \
./$CTX_SUB \
$lblargs
fi

# All images are pushed to quay.io/<reponame>, both
# latest and version-tagged (if available).
build-push.sh \
$_DRNOPUSH \
--arches=$ARCHES \
--modcmd=tag_version.sh \
$REPO_FQIN \
./$CTX_SUB \
$lblargs
43 changes: 43 additions & 0 deletions build-push/bin/tag_version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/bash

# This script is not intended for humans. It should only be referenced
# as an argument to the build-push.sh `--modcmd` option. It's purpose
# is to ensure stable images are re-tagged with a verison-number
# cooresponding to the included tool's version.

set -eo pipefail

if [[ -r "/etc/automation_environment" ]]; then
source /etc/automation_environment # defines AUTOMATION_LIB_PATH
#shellcheck disable=SC1090,SC2154
source "$AUTOMATION_LIB_PATH/common_lib.sh"
else
echo "Unexpected operating environment"
exit 1
fi

# Vars defined by build-push.sh spec. for mod scripts
req_env_vars SCRIPT_FILEPATH RUNTIME PLATFORMOS FQIN CONTEXT \
PUSH ARCHES REGSERVER NAMESPACE IMGNAME MODCMD

# As in main.sh, the context name comes from subdir basename
# shellcheck disable=SC2154
CTX_NAME=$(basename "$CONTEXT") # upstream, testing, or stable

# shellcheck disable=SC2154
dbg "Mod-command operating on $FQIN in $CTX_NAME context"

if [[ "$CTX_NAME" == "stable" ]]; then
# Stable images must all be tagged with a version number.
# Confirm this value is passed in by shell env. var. since
# retrieving it from the image content is beyond the scope
# of this script.
req_env_vars img_cmd_version
# shellcheck disable=SC2154
msg "Found image command version '$img_cmd_version'"
# shellcheck disable=SC2154
$RUNTIME tag $FQIN:latest $FQIN:$img_cmd_version
msg "Successfully tagged $FQIN:$img_cmd_version"
else
warn "Not tagging '$CTX_NAME' context of '$FQIN'"
fi
105 changes: 105 additions & 0 deletions build-push/stuff_dnf_cache.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/bin/bash

# This script allows stuffing a dnf cache directory with both
# metadata and packages, for a list of architectures. It assumes
# the same Fedora release version as the executing platform unless
# $RELEASE is overriden. It requires the containers/automation
# common libraries are installed and the following env. vars. are
# non-empty:
#
# CACHEDIR - Directory path under which both metadata & packages will
# be stored (under platform specific subdirectory tree).
# ARCHES - Whitespace separated list of architecture names
# PACKAGES - Whitespace separated list of packages to seed in cache

set -ea
[[ -n "$AUTOMATION_LIB_PATH" ]] || source /etc/automation_environment
source $AUTOMATION_LIB_PATH/common_lib.sh
set +a

req_env_vars ARCHES PACKAGES CACHEDIR OS_RELEASE_VER SCRIPT_FILENAME DEBUG

declare -a _ARCHES
# We want to do word-splitting
# shellcheck disable=SC2206
_ARCHES=( $ARCHES )
declare -a _PACKAGES
# shellcheck disable=SC2206
_PACKAGES=( $PACKAGES )

RELEASE="${RELEASE:-$OS_RELEASE_VER}"

# First arg must be name of architecture
# Second arg must be either 'makecache' or 'download'
dnfarch(){
local arch
arch="$1"
shift
local cmd
cmd=$1
[[ -n "$arch" ]] || die "Missing arch arument to dnfarch()"

# Don't download into $PWD
local ddarg
if [[ "$cmd" == "download" ]]; then
# Already checked by req_env_vars()
# shellcheck disable=SC2154
ddarg="--downloaddir=$CACHEDIR"
fi

local mq="-q"
local _showrun
# Vars. already checked by req_env_vars()
# shellcheck disable=SC2154
if ((DEBUG)); then
_showrun="showrun"
mq=""
fi
# Have to put --cachedir option path under here too, otherwise
# metadata gets downloaded every run.
$_showrun dnf --setopt=ignorearch=true --releasever="$RELEASE" \
--setopt=keepcache=true --setopt=cachedir="$CACHEDIR" \
$mq -y --setopt=arch=$arch $ddarg "$@"
}

wait_jobs() {
local job
dbg "Waiting for background jobs to complete."
for job in "$@"; do
dbg "Waiting on job '$job'"
# This isn't perfect, it will miss special-case exit 127 but
# this should be unlikely given the usage of this function.
if ! wait -n $job; then
dbg "Background job $job non-zero exit status"
# This could be hard to debug, but being more verbose
# about the failing command would unacceptably increasse
# the scripts complexity. Rely on dnf's error messages
# being useful.
die "At least one operation failed, bailing out."
fi
dbg "Job '$job' complete"
done
jobs=()
}

for_each_arch() {
local cmd
local arch
local -a jobs
for arch in "${_ARCHES[@]}"; do
# For display, command needs both whitespace and special quote handling.
cmd=$(printf "%q " "dnfarch" "$arch" "$@")
$cmd &
jobs+=($!)
dbg "New job $!: $cmd"
done
wait_jobs "${jobs[@]}"
}

mkdir -p "$CACHEDIR"

msg "Downloading Fedora $RELEASE metadata in parallel"
for_each_arch makecache

msg "Downloading Fedora $RELEASE packages in parallel"
for_each_arch download "${_PACKAGES[@]}"
45 changes: 45 additions & 0 deletions cache_images/build-push_packaging.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/bin/bash

# This script is called from build-push_setup.sh by packer. It's not intended
# to be used outside of those contexts. It assumes the lib.sh library has
# already been sourced, and that all "ground-up" package-related activity
# needs to be done, including repository setup and initial update.

set -e

SCRIPT_FILEPATH=$(realpath "$0")
SCRIPT_DIRPATH=$(dirname "$SCRIPT_FILEPATH")
REPO_DIRPATH=$(realpath "$SCRIPT_DIRPATH/../")

# shellcheck source=./lib.sh
source "$REPO_DIRPATH/lib.sh"

# packer and/or a --build-arg define this envar value uniformly
# for both VM and container image build workflows.
req_env_vars PACKER_BUILD_NAME

msg "Updating/Installing repos and packages for $OS_REL_VER"

bigto ooe.sh $SUDO dnf update -y

INSTALL_PACKAGES=(\
buildah
jq
podman
qemu-user-static
skopeo
)

echo "Installing general build/test dependencies"
bigto $SUDO dnf install -y "${INSTALL_PACKAGES[@]}"

# It was observed in F33, dnf install doesn't always get you the latest/greatest
lilto $SUDO dnf update -y

# Re-install with the 'build-push' component
install_automation_tooling build-push

# Install main scripts into directory on $PATH
set -x
$SUDO cp $REPO_DIRPATH/build-push/bin/* $AUTOMATION_LIB_PATH/../bin/
$SUDO chmod +x $AUTOMATION_LIB_PATH/../bin/*
Loading

0 comments on commit 551b32a

Please sign in to comment.