From 8e438c7a6da833f0a3a80a7ef82c315f465ea3e9 Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Thu, 26 Sep 2019 16:19:13 -0400 Subject: [PATCH] BuildSourceImage: expose "unpack" as subcommand This may be a pattern we can do for some of the more useful functions. But for now, folks can build, push, etc. and once they skopeo copy an image to their host, they can ```bash ./BuildSourceImage unpack ``` and it will be nicely exposed in the container build too Also included, exporting the defaults into the bats test for easier direct running. Perhaps we can move the srpm caching into bats too, so the Makefile target isn't strictly required. Signed-off-by: Vincent Batts --- BuildSourceImage.sh | 45 +++++++++++++++++++++++++++++++++---- Dockerfile | 4 +++- test/02-from_image_ref.bats | 1 + test/03-unpack.bats | 32 ++++++++++++++++++++++++++ test/helpers.bash | 5 +++++ 5 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 test/03-unpack.bats diff --git a/BuildSourceImage.sh b/BuildSourceImage.sh index 6034768..7484776 100755 --- a/BuildSourceImage.sh +++ b/BuildSourceImage.sh @@ -28,6 +28,10 @@ _usage() { echo -e " -D\t\tdebuging output. Can be set via DEBUG env variable" echo -e " -h\t\tthis usage information" echo -e " -v\t\tversion" + echo -e "" + echo -e " Subcommands:" + echo -e " unpack\tUnpack an OCI layout to a rootfs directory" + echo -e "" } # sanity checks on startup @@ -44,6 +48,23 @@ _init() { done } +# enable access to some of functions as subcommands! +_subcommand() { + local command="${1}" + local ret + + shift + + case "${command}" in + unpack) + # (vb) i'd prefer this subcommand directly match the function name, but it isn't as pretty. + unpack_img "${@}" + ret=$? + exit "${ret}" + ;; + esac +} + # _is_sourced tests whether this script is being source, or executed directly _is_sourced() { # https://unix.stackexchange.com/a/215279 @@ -292,6 +313,20 @@ unpack_img() { local unpack_dir="${2}" local ret + while getopts ":h" opts; do + case "${opts}" in + *) + echo "$0 unpack " + return 1 + ;; + esac + done + shift $((OPTIND-1)) + + if [ -z "${image_dir}" ] || [ -z "${unpack_dir}" ] ; then + _error "[unpack_img] blank arguments provided" + fi + if [ -d "${unpack_dir}" ] ; then _rm_rf "${unpack_dir}" fi @@ -336,9 +371,10 @@ unpack_img_bash() { return ${ret} fi - # Since we're landing the reference as an OCI layout, this mediaType is fairly predictable - # TODO don't always assume +gzip - layer_dgsts="$(jq '.layers[] | select(.mediaType == "application/vnd.oci.image.layer.v1.tar+gzip") | .digest' "${image_dir}"/blobs/"${mnfst_dgst/:/\/}" | tr -d \")" + # TODO this will need to be refactored when we start seeing +zstd layers. + # Then it will be better to no just get a list of digests, but maybe to + # iterate on each descriptor independently? + layer_dgsts="$(jq '.layers | map(select(.mediaType == "application/vnd.oci.image.layer.v1.tar+gzip"),select(.mediaType == "application/vnd.oci.image.layer.v1.tar"),select(.mediaType == "application/vnd.docker.image.rootfs.diff.tar.gzip")) | .[] | .digest' "${image_dir}"/blobs/"${mnfst_dgst/:/\/}" | tr -d \")" ret=$? if [ ${ret} -ne 0 ] ; then return ${ret} @@ -1026,8 +1062,9 @@ main() { local work_dir _init "${@}" + _subcommand "${@}" - base_dir="$(pwd)/${ABV_NAME}" + base_dir="${BASE_DIR:-$(pwd)/${ABV_NAME}}" # using the bash builtin to parse while getopts ":hlvDi:c:s:e:o:b:d:p:" opts; do case "${opts}" in diff --git a/Dockerfile b/Dockerfile index 0714352..8c64206 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,4 +4,6 @@ RUN dnf install -y jq skopeo findutils file 'dnf-command(download)' COPY ./BuildSourceImage.sh /usr/local/bin/BuildSourceImage.sh -ENTRYPOINT ["/usr/local/bin/BuildSourceImage.sh", "-b", "/tmp/"] +ENV BASE_DIR=/tmp + +ENTRYPOINT ["/usr/local/bin/BuildSourceImage.sh"] diff --git a/test/02-from_image_ref.bats b/test/02-from_image_ref.bats index 74595d2..b9f1ce3 100644 --- a/test/02-from_image_ref.bats +++ b/test/02-from_image_ref.bats @@ -3,6 +3,7 @@ load helpers @test "Build from image reference" { + #skip "this takes like 20min ..." local d d=$(mktemp -d) echo "temporary directory: ${d}" diff --git a/test/03-unpack.bats b/test/03-unpack.bats new file mode 100644 index 0000000..ee540cf --- /dev/null +++ b/test/03-unpack.bats @@ -0,0 +1,32 @@ +#!/usr/bin/env bats -t + +load helpers + +@test "unpack - no args" { + run_ctr $CTR_IMAGE unpack + [ "$status" -eq 1 ] + [[ ${lines[0]} =~ "[SrcImg][ERROR] [unpack_img] blank arguments provided" ]] +} + +@test "unpack - Help" { + run_ctr $CTR_IMAGE unpack -h + [ "$status" -eq 1 ] + [[ ${lines[0]} =~ "BuildSourceImage.sh unpack " ]] +} + +@test "unpack - from a SRPM build" { + local d + local r + + d=$(mktemp -d) + echo "temporary directories: output - ${d}" + run_ctr -v $(pwd)/.testprep/srpms/:/src:ro --mount type=bind,source=${d},destination=/output $CTR_IMAGE -s /src -o /output + [ "$status" -eq 0 ] + [ -f "${d}/index.json" ] + + r=$(mktemp -d) + echo "temporary directories: unpacked - ${r}" + run_ctr --mount type=bind,source=${d},destination=/output -v ${r}:/unpacked/ $CTR_IMAGE unpack /output/ /unpacked/ + [ "$(find ${r} -type f | wc -l)" -eq 3 ] # regular files + [ "$(find ${r} -type l | wc -l)" -eq 3 ] # and symlinks +} diff --git a/test/helpers.bash b/test/helpers.bash index 67428d9..8dbb1c1 100644 --- a/test/helpers.bash +++ b/test/helpers.bash @@ -1,3 +1,8 @@ +#!/bin/bash + +export CTR_IMAGE="${CTR_IMAGE:-localhost/containers/buildsourceimage}" +export CTR_ENGINE="${CTR_ENGINE:-podman}" + function run_ctr() { run $CTR_ENGINE run --security-opt label=disable --rm "$@" }