1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
|
#!/usr/bin/env bash
# Directory in which tests live
TEST_SOURCES=${TEST_SOURCES:-$(dirname ${BASH_SOURCE})}
BUILDAH_BINARY=${BUILDAH_BINARY:-$TEST_SOURCES/../bin/buildah}
IMGTYPE_BINARY=${IMGTYPE_BINARY:-$TEST_SOURCES/../bin/imgtype}
COPY_BINARY=${COPY_BINARY:-$TEST_SOURCES/../bin/copy}
TUTORIAL_BINARY=${TUTORIAL_BINARY:-$TEST_SOURCES/../bin/tutorial}
INET_BINARY=${INET_BINARY:-$TEST_SOURCES/../bin/inet}
STORAGE_DRIVER=${STORAGE_DRIVER:-vfs}
PATH=$(dirname ${BASH_SOURCE})/../bin:${PATH}
OCI=${CI_DESIRED_RUNTIME:-$(${BUILDAH_BINARY} info --format '{{.host.OCIRuntime}}' || command -v runc || command -v crun)}
# Default timeout for a buildah command.
BUILDAH_TIMEOUT=${BUILDAH_TIMEOUT:-300}
# Safe reliable unchanging test image
SAFEIMAGE_REGISTRY=${SAFEIMAGE_REGISTRY:-quay.io}
SAFEIMAGE_USER=${SAFEIMAGE_USER:-libpod}
SAFEIMAGE_NAME=${SAFEIMAGE_NAME:-testimage}
SAFEIMAGE_TAG=${SAFEIMAGE_TAG:-20221018}
SAFEIMAGE="${SAFEIMAGE:-$SAFEIMAGE_REGISTRY/$SAFEIMAGE_USER/$SAFEIMAGE_NAME:$SAFEIMAGE_TAG}"
# Prompt to display when logging buildah commands; distinguish root/rootless
_LOG_PROMPT='$'
if [ $(id -u) -eq 0 ]; then
_LOG_PROMPT='#'
fi
# Shortcut for directory containing Containerfiles for bud.bats
BUDFILES=${TEST_SOURCES}/bud
# Used hundreds of times throughout all the tests
WITH_POLICY_JSON="--signature-policy ${TEST_SOURCES}/policy.json"
# We don't invoke gnupg directly in many places, but this avoids ENOTTY errors
# when we invoke it directly in batch mode, and CI runs us without a terminal
# attached.
export GPG_TTY=/dev/null
function setup(){
setup_tests
}
function setup_tests() {
pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
# $TEST_SCRATCH_DIR is a custom scratch directory for each @test,
# but it is NOT EMPTY! It is the caller's responsibility to make
# empty subdirectories as needed. All of it will be deleted upon
# test completion.
#
# buildah/podman: "repository name must be lowercase".
# me: "but it's a local file path, not a repository name!"
# buildah/podman: "i dont care. no caps anywhere!"
TEST_SCRATCH_DIR=$(mktemp -d --dry-run --tmpdir=${BATS_TMPDIR:-${TMPDIR:-/tmp}} buildah_tests.XXXXXX | tr A-Z a-z)
mkdir --mode=0700 $TEST_SCRATCH_DIR
mkdir -p ${TEST_SCRATCH_DIR}/{root,runroot,sigstore,registries.d}
cat >${TEST_SCRATCH_DIR}/registries.d/default.yaml <<EOF
default-docker:
sigstore-staging: file://${TEST_SCRATCH_DIR}/sigstore
docker:
registry.access.redhat.com:
sigstore: https://access.redhat.com/webassets/docker/content/sigstore
registry.redhat.io:
sigstore: https://registry.redhat.io/containers/sigstore
EOF
# Common options for all buildah and podman invocations
ROOTDIR_OPTS="--root ${TEST_SCRATCH_DIR}/root --runroot ${TEST_SCRATCH_DIR}/runroot --storage-driver ${STORAGE_DRIVER}"
# When running in CI, use a local registry for all image pulls
local cached=
if [[ -n "$CI_USE_REGISTRY_CACHE" ]]; then
cached="-cached"
fi
regconfopt="--registries-conf ${TEST_SOURCES}/registries$cached.conf"
regconfdir="--registries-conf-dir ${TEST_SCRATCH_DIR}/registries.d"
BUILDAH_REGISTRY_OPTS="${regconfopt} ${regconfdir} --short-name-alias-conf ${TEST_SCRATCH_DIR}/cache/shortnames.conf"
COPY_REGISTRY_OPTS="${BUILDAH_REGISTRY_OPTS}"
PODMAN_REGISTRY_OPTS="${regconfopt}"
}
function starthttpd() { # directory [working-directory-or-"" [certfile, keyfile]]
if test -n "$4" ; then
if ! openssl req -newkey rsa:4096 -nodes -sha256 -keyout "$4" -x509 -days 2 -addext "subjectAltName = DNS:localhost" -out "$3" -subj "/CN=localhost" ; then
die error creating new key and certificate
fi
chmod 644 "$3"
chmod 600 "$4"
fi
pushd ${2:-${TEST_SCRATCH_DIR}} > /dev/null
go build -o serve ${TEST_SOURCES}/serve/serve.go
portfile=$(mktemp)
if test -z "${portfile}"; then
echo error creating temporary file
exit 1
fi
pidfile=$(mktemp)
if test -z "${pidfile}"; then
echo error creating temporary file
exit 1
fi
sh -c "./serve ${1:-${BATS_TMPDIR}} 0 \"${portfile}\" \"${3}\" \"${4}\" ${pidfile} &"
waited=0
while ! test -s ${pidfile} ; do
sleep 0.1
if test $((++waited)) -ge 300 ; then
echo test http server did not write pid file within timeout
exit 1
fi
done
HTTP_SERVER_PID=$(cat ${pidfile})
rm -f ${pidfile}
waited=0
while ! test -s ${portfile} ; do
sleep 0.1
if test $((++waited)) -ge 300 ; then
echo test http server did not start listening within timeout
exit 1
fi
done
HTTP_SERVER_PORT=$(cat ${portfile})
rm -f ${portfile}
popd > /dev/null
}
function stophttpd() {
if test -n "$HTTP_SERVER_PID" ; then
kill -HUP ${HTTP_SERVER_PID}
unset HTTP_SERVER_PID
unset HTTP_SERVER_PORT
fi
true
}
function teardown(){
teardown_tests
}
function teardown_tests() {
stophttpd
stop_git_daemon
stop_registry
# Workaround for #1991 - buildah + overlayfs leaks mount points.
# Many tests leave behind /var/tmp/.../root/overlay and sub-mounts;
# let's find those and clean them up, otherwise 'rm -rf' fails.
# 'sort -r' guarantees that we umount deepest subpaths first.
mount |\
awk '$3 ~ testdir { print $3 }' testdir="^${TEST_SCRATCH_DIR}/" |\
sort -r |\
xargs --no-run-if-empty --max-lines=1 umount
rm -fr ${TEST_SCRATCH_DIR}
popd
}
function normalize_image_name() {
for img in "$@"; do
if [[ "${img##*/}" == "$img" ]] ; then
echo -n docker.io/library/"$img"
elif [[ docker.io/"${img##*/}" == "$img" ]] ; then
echo -n docker.io/library/"${img##*/}"
else
echo -n "$img"
fi
done
}
function _prefetch() {
if [ -z "${_BUILDAH_IMAGE_CACHEDIR}" ]; then
export _BUILDAH_IMAGE_CACHEDIR=${BATS_SUITE_TMPDIR}/buildah-image-cache
mkdir -p ${_BUILDAH_IMAGE_CACHEDIR}
# It's 700 by default; that prevents 'unshare' from reading cached images
chmod 711 ${BATS_SUITE_TMPDIR:?is unset} ${BATS_SUITE_TMPDIR}/..
fi
local storage=
for img in "$@"; do
if [[ "$img" =~ '[vfs@' ]] ; then
storage="$img"
continue
fi
img=$(normalize_image_name "$img")
echo "# [checking for: $img]" >&2
fname=$(tr -c a-zA-Z0-9.- - <<< "$img")
( flock --timeout 300 9 || die "Could not flock"; _prefetch_locksafe $img $fname ) 9> $_BUILDAH_IMAGE_CACHEDIR/$fname.lock
done
}
# DO NOT CALL THIS. EVER. This must only be called from _prefetch().
function _prefetch_locksafe() {
local img="$1"
local fname="$2"
if [ -d $_BUILDAH_IMAGE_CACHEDIR/$fname ]; then
echo "# [restoring from cache: $_BUILDAH_IMAGE_CACHEDIR / $img]" >&2
copy dir:$_BUILDAH_IMAGE_CACHEDIR/$fname containers-storage:"$storage""$img"
else
rm -fr ${_BUILDAH_IMAGE_CACHEDIR:?THIS CAN NEVER HAPPEN}/$fname
echo "# [copy docker://$img dir:$_BUILDAH_IMAGE_CACHEDIR/$fname]" >&2
for attempt in $(seq 3) ; do
if copy $COPY_REGISTRY_OPTS docker://"$img" dir:$_BUILDAH_IMAGE_CACHEDIR/$fname ; then
break
else
# Failed. Clean up, so we don't leave incomplete remnants
rm -fr ${_BUILDAH_IMAGE_CACHEDIR:?THIS CAN NEVER HAPPEN EITHER}/$fname
fi
sleep 5
done
echo "# [copy dir:$_BUILDAH_IMAGE_CACHEDIR/$fname containers-storage:$storage$img]" >&2
copy dir:$_BUILDAH_IMAGE_CACHEDIR/$fname containers-storage:"$storage""$img"
fi
}
function createrandom() {
dd if=/dev/urandom bs=1 count=${2:-256} of=${1:-${BATS_TMPDIR}/randomfile} status=none
}
###################
# random_string # Returns a pseudorandom human-readable string
###################
#
# Numeric argument, if present, is desired length of string
#
function random_string() {
local length=${1:-10}
head /dev/urandom | tr -dc a-zA-Z0-9 | head -c$length
}
##############
# safename # Returns a pseudorandom string suitable for container/image/etc names
##############
#
# Name will include the bats test number and a pseudorandom element,
# eg "t123-xyz123". safename() will return the same string across
# multiple invocations within a given test; this makes it easier for
# a maintainer to see common name patterns.
#
# String is lower-case so it can be used as an image name
#
function safename() {
safenamepath=$BATS_SUITE_TMPDIR/.safename.$BATS_SUITE_TEST_NUMBER
if [[ ! -e $safenamepath ]]; then
echo -n "t${BATS_SUITE_TEST_NUMBER}-$(random_string 8 | tr A-Z a-z)" >$safenamepath
fi
cat $safenamepath
}
function buildah() {
${BUILDAH_BINARY} ${BUILDAH_REGISTRY_OPTS} ${ROOTDIR_OPTS} "$@"
}
function imgtype() {
${IMGTYPE_BINARY} ${ROOTDIR_OPTS} "$@"
}
function copy() {
${COPY_BINARY} --max-parallel-downloads=1 ${ROOTDIR_OPTS} ${BUILDAH_REGISTRY_OPTS} "$@"
}
function podman() {
command ${PODMAN_BINARY:-podman} ${PODMAN_REGISTRY_OPTS} ${ROOTDIR_OPTS} "$@"
}
# There are various scenarios where we would like to execute `tests` as rootless user, however certain commands like `buildah mount`
# do not work in rootless session since a normal user cannot mount a filesystem unless they're in a user namespace along with its
# own mount namespace. In order to run such specific commands from a rootless session we must perform `buildah unshare`.
# Following function makes sure that invoked command is triggered inside a `buildah unshare` session if env is rootless.
function run_unshared() {
if is_rootless; then
$BUILDAH_BINARY unshare "$@"
else
command "$@"
fi
}
function mkdir() {
run_unshared mkdir "$@"
}
function touch() {
run_unshared touch "$@"
}
function cp() {
run_unshared cp "$@"
}
function rm() {
run_unshared rm "$@"
}
#################
# run_buildah # Invoke buildah, with timeout, using BATS 'run'
#################
#
# This is the preferred mechanism for invoking buildah:
#
# * we use 'timeout' to abort (with a diagnostic) if something
# takes too long; this is preferable to a CI hang.
# * we log the command run and its output. This doesn't normally
# appear in BATS output, but it will if there's an error.
# * we check exit status. Since the normal desired code is 0,
# that's the default; but the first argument can override:
#
# run_buildah 125 nonexistent-subcommand
# run_buildah '?' some-other-command # let our caller check status
#
# Since we use the BATS 'run' mechanism, $output and $status will be
# defined for our caller.
#
function run_buildah() {
# Number as first argument = expected exit code; default 0
# --retry as first argument = retry 3 times on error (eg registry flakes)
local expected_rc=0
local retry=1
case "$1" in
[0-9]) expected_rc=$1; shift;;
[1-9][0-9]) expected_rc=$1; shift;;
[12][0-9][0-9]) expected_rc=$1; shift;;
'?') expected_rc= ; shift;; # ignore exit code
--retry) retry=3; shift;; # retry network flakes
esac
# Remember command args, for possible use in later diagnostic messages
MOST_RECENT_BUILDAH_COMMAND="buildah $*"
# If session is rootless and `buildah mount` is invoked, perform unshare,
# since normal user cannot mount a filesystem unless they're in a user namespace along with its own mount namespace.
if is_rootless; then
if [[ "$1" =~ mount ]]; then
set "unshare" "$BUILDAH_BINARY" ${BUILDAH_REGISTRY_OPTS} ${ROOTDIR_OPTS} "$@"
fi
fi
while [ $retry -gt 0 ]; do
retry=$(( retry - 1 ))
# stdout is only emitted upon error; this echo is to help a debugger
echo "${_LOG_PROMPT} $BUILDAH_BINARY $*"
run env CONTAINERS_CONF=${CONTAINERS_CONF:-$(dirname ${BASH_SOURCE})/containers.conf} timeout --foreground --kill=10 $BUILDAH_TIMEOUT ${BUILDAH_BINARY} ${BUILDAH_REGISTRY_OPTS} ${ROOTDIR_OPTS} "$@"
# without "quotes", multiple lines are glommed together into one
if [ -n "$output" ]; then
echo "$output"
fi
if [ "$status" -ne 0 ]; then
echo -n "[ rc=$status ";
if [ -n "$expected_rc" ]; then
if [ "$status" -eq "$expected_rc" ]; then
echo -n "(expected) ";
else
echo -n "(** EXPECTED $expected_rc **) ";
fi
fi
echo "]"
fi
if [ "$status" -eq 124 -o "$status" -eq 137 ]; then
# FIXME: 'timeout -v' requires coreutils-8.29; travis seems to have
# an older version. If/when travis updates, please add -v
# to the 'timeout' command above, and un-comment this out:
# if expr "$output" : ".*timeout: sending" >/dev/null; then
echo "*** TIMED OUT ***"
# This does not get the benefit of a retry
false
fi
if [ -n "$expected_rc" ]; then
if [ "$status" -eq "$expected_rc" ]; then
return
elif [ $retry -gt 0 ]; then
echo "[ RETRYING ]" >&2
sleep 30
else
die "exit code is $status; expected $expected_rc"
fi
fi
done
}
#########
# die # Abort with helpful message
#########
function die() {
echo "#/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv" >&2
echo "#| FAIL: $*" >&2
echo "#\\^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" >&2
false
}
############
# assert # Compare actual vs expected string; fail if mismatch
############
#
# Compares string (default: $output) against the given string argument.
# By default we do an exact-match comparison against $output, but there
# are two different ways to invoke us, each with an optional description:
#
# assert "EXPECT" [DESCRIPTION]
# assert "RESULT" "OP" "EXPECT" [DESCRIPTION]
#
# The first form (one or two arguments) does an exact-match comparison
# of "$output" against "EXPECT". The second (three or four args) compares
# the first parameter against EXPECT, using the given OPerator. If present,
# DESCRIPTION will be displayed on test failure.
#
# Examples:
#
# assert "this is exactly what we expect"
# assert "${lines[0]}" =~ "^abc" "first line begins with abc"
#
function assert() {
local actual_string="$output"
local operator='=='
local expect_string="$1"
local testname="$2"
case "${#*}" in
0) die "Internal error: 'assert' requires one or more arguments" ;;
1|2) ;;
3|4) actual_string="$1"
operator="$2"
expect_string="$3"
testname="$4"
;;
*) die "Internal error: too many arguments to 'assert" ;;
esac
# Comparisons.
# Special case: there is no !~ operator, so fake it via '! x =~ y'
local not=
local actual_op="$operator"
if [[ $operator == '!~' ]]; then
not='!'
actual_op='=~'
fi
if [[ $operator == '=' || $operator == '==' ]]; then
# Special case: we can't use '=' or '==' inside [[ ... ]] because
# the right-hand side is treated as a pattern... and '[xy]' will
# not compare literally. There seems to be no way to turn that off.
if [ "$actual_string" = "$expect_string" ]; then
return
fi
elif [[ $operator == '!=' ]]; then
# Same special case as above
if [ "$actual_string" != "$expect_string" ]; then
return
fi
else
if eval "[[ $not \$actual_string $actual_op \$expect_string ]]"; then
return
elif [ $? -gt 1 ]; then
die "Internal error: could not process 'actual' $operator 'expect'"
fi
fi
# Test has failed. Get a descriptive test name.
if [ -z "$testname" ]; then
testname="${MOST_RECENT_BUILDAH_COMMAND:-[no test name given]}"
fi
# Display optimization: the typical case for 'expect' is an
# exact match ('='), but there are also '=~' or '!~' or '-ge'
# and the like. Omit the '=' but show the others; and always
# align subsequent output lines for ease of comparison.
local op=''
local ws=''
if [ "$operator" != '==' ]; then
op="$operator "
ws=$(printf "%*s" ${#op} "")
fi
# This is a multi-line message, which may in turn contain multi-line
# output, so let's format it ourself, readably
local actual_split
IFS=$'\n' read -rd '' -a actual_split <<<"$actual_string" || true
printf "#/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n" >&2
printf "#| FAIL: %s\n" "$testname" >&2
printf "#| expected: %s'%s'\n" "$op" "$expect_string" >&2
printf "#| actual: %s'%s'\n" "$ws" "${actual_split[0]}" >&2
local line
for line in "${actual_split[@]:1}"; do
printf "#| > %s'%s'\n" "$ws" "$line" >&2
done
printf "#\\^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" >&2
false
}
###################
# expect_output # [obsolete; kept for compatibility]
###################
#
# An earlier version of assert().
#
function expect_output() {
# By default we examine $output, the result of run_buildah
local actual="$output"
local operator='=='
# option processing: recognize --from="...", --substring
local opt
for opt; do
local value=$(expr "$opt" : '[^=]*=\(.*\)')
case "$opt" in
--from=*) actual="$value"; shift;;
--substring) operator='=~'; shift;;
--) shift; break;;
-*) die "Invalid option '$opt'" ;;
*) break;;
esac
done
assert "$actual" "$operator" "$@"
}
#######################
# expect_line_count # Check the expected number of output lines
#######################
#
# ...from the most recent run_buildah command
#
function expect_line_count() {
local expect="$1"
local testname="${2:-${MOST_RECENT_BUILDAH_COMMAND:-[no test name given]}}"
local actual="${#lines[@]}"
if [ "$actual" -eq "$expect" ]; then
return
fi
printf "#/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n" >&2
printf "#| FAIL: $testname\n" >&2
printf "#| Expected %d lines of output, got %d\n" $expect $actual >&2
printf "#| Output was:\n" >&2
local line
for line in "${lines[@]}"; do
printf "#| >%s\n" "$line" >&2
done
printf "#\\^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" >&2
false
}
function check_options_flag_err() {
flag="$1"
[ "$status" -eq 125 ]
[[ $output = *"no options ($flag) can be specified after"* ]]
}
#################
# is_rootless # Check if we run as normal user
#################
function is_rootless() {
[ "$(id -u)" -ne 0 ]
}
#################
# has_supplemental_groups # Check that account has additional groups
#################
function has_supplemental_groups() {
[ "$(id -g)" != "$(id -G)" ]
}
#################################
# skip_if_rootless_environment # `mount` or its variant needs unshare
#################################
function skip_if_rootless_environment() {
if is_rootless; then
skip "${1:-test is being invoked from rootless environment and might need unshare}"
fi
}
#################################
# skip_if_root_environment #
#################################
function skip_if_root_environment() {
if ! is_rootless; then
skip "${1:-test is being invoked from root environment}"
fi
}
####################
# skip_if_chroot #
####################
function skip_if_chroot() {
if test "$BUILDAH_ISOLATION" = "chroot"; then
skip "${1:-test does not work when \$BUILDAH_ISOLATION = chroot}"
fi
}
######################
# skip_if_rootless #
######################
function skip_if_rootless() {
if test "$BUILDAH_ISOLATION" = "rootless"; then
skip "${1:-test does not work when \$BUILDAH_ISOLATION = rootless}"
fi
}
##################################
# skip_if_rootless_and_cgroupv1 #
##################################
function skip_if_rootless_and_cgroupv1() {
if test "$BUILDAH_ISOLATION" = "rootless"; then
if ! is_cgroupsv2; then
skip "${1:-test does not work when \$BUILDAH_ISOLATION = rootless} and not cgroupv2"
fi
fi
}
########################
# skip_if_no_runtime # 'buildah run' can't work without a runtime
########################
function skip_if_no_runtime() {
if type -p "${OCI}" &> /dev/null; then
return
fi
skip "runtime \"$OCI\" not found"
}
#######################
# skip_if_no_podman # we need 'podman' to test how we interact with podman
#######################
function skip_if_no_podman() {
run which ${PODMAN_BINARY:-podman}
if [[ $status -ne 0 ]]; then
skip "podman is not installed"
fi
}
##################
# is_cgroupsv2 # Returns true if host system has cgroupsv2 enabled
##################
function is_cgroupsv2() {
local cgroupfs_t=$(stat -f -c %T /sys/fs/cgroup)
test "$cgroupfs_t" = "cgroup2fs"
}
#######################
# skip_if_cgroupsv2 # Some tests don't work with cgroupsv2
#######################
function skip_if_cgroupsv2() {
if is_cgroupsv2; then
skip "${1:-test does not work with cgroups v2}"
fi
}
#######################
# skip_if_cgroupsv1 # Some tests don't work with cgroupsv1
#######################
function skip_if_cgroupsv1() {
if ! is_cgroupsv2; then
skip "${1:-test does not work with cgroups v1}"
fi
}
##########################
# skip_if_in_container #
##########################
function skip_if_in_container() {
if test "$CONTAINER" = "podman"; then
skip "This test is not working inside a container"
fi
}
#######################
# skip_if_no_docker #
#######################
function skip_if_no_docker() {
which docker || skip "docker is not installed"
systemctl -q is-active docker || skip "docker.service is not active"
# Confirm that this is really truly docker, not podman.
docker_version=$(docker --version)
if [[ $docker_version =~ podman ]]; then
skip "this test needs actual docker, not podman-docker"
fi
}
function skip_if_no_unshare() {
run which ${UNSHARE_BINARY:-unshare}
if [[ $status -ne 0 ]]; then
skip "unshare is not installed"
fi
if ! unshare -Ur true ; then
skip "unshare was not able to create a user namespace"
fi
if ! unshare -Urm true ; then
skip "unshare was not able to create a mount namespace"
fi
if ! unshare -Urmpf true ; then
skip "unshare was not able to create a pid namespace"
fi
if ! unshare -U --map-users $(id -u),0,1 true ; then
skip "unshare does not support --map-users"
fi
if ! unshare -Ur --setuid 0 true ; then
skip "unshare does not support --setuid"
fi
}
function start_git_daemon() {
daemondir=${TEST_SCRATCH_DIR}/git-daemon
mkdir -p ${daemondir}/repo
gzip -dc < ${1:-${TEST_SOURCES}/git-daemon/repo.tar.gz} | tar x -C ${daemondir}/repo
# git >=2.45 aborts with "dubious ownership" error if serving other user's files as root
if ! is_rootless; then
chown -R root:root ${daemondir}/repo
fi
${INET_BINARY} -port-file ${TEST_SCRATCH_DIR}/git-daemon/port -pid-file=${TEST_SCRATCH_DIR}/git-daemon/pid -- git daemon --inetd --base-path=${daemondir} ${daemondir} &
local waited=0
while ! test -s ${TEST_SCRATCH_DIR}/git-daemon/pid ; do
sleep 0.1
if test $((++waited)) -ge 300 ; then
echo test git server did not write pid file within timeout
exit 1
fi
done
GITPORT=$(cat ${TEST_SCRATCH_DIR}/git-daemon/port)
}
function stop_git_daemon() {
if test -s ${TEST_SCRATCH_DIR}/git-daemon/pid ; then
kill $(cat ${TEST_SCRATCH_DIR}/git-daemon/pid)
rm -f ${TEST_SCRATCH_DIR}/git-daemon/pid
fi
}
# Bring up a registry server using buildah with vfs and chroot as a cheap
# substitute for podman, accessible only to user $1 using password $2 on the
# local system at a dynamically-allocated port.
# Requires openssl.
# A user name and password can be supplied as the two parameters, or default
# values of "testuser" and "testpassword" will be used.
# Sets REGISTRY_PID, REGISTRY_PORT (to append to "localhost:"), and
# REGISTRY_DIR (where the CA cert can be found) on success.
function start_registry() {
local testuser="${1:-testuser}"
local testpassword="${2:-testpassword}"
local REGISTRY_IMAGE=quay.io/libpod/registry:2.8.2
local config='
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
http:
addr: :0
headers:
X-Content-Type-Options: [nosniff]
tls:
certificate: /etc/docker/registry/localhost.crt
key: /etc/docker/registry/localhost.key
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
auth:
htpasswd:
realm: buildah-realm
path: /etc/docker/registry/htpasswd
'
# roughly equivalent to "htpasswd -nbB testuser testpassword", the registry uses
# the same package this does for verifying passwords against hashes in htpasswd files
htpasswd=${testuser}:$(buildah passwd ${testpassword})
# generate the htpasswd and config.yml files for the registry
mkdir -p "${TEST_SCRATCH_DIR}"/registry/root "${TEST_SCRATCH_DIR}"/registry/run "${TEST_SCRATCH_DIR}"/registry/certs "${TEST_SCRATCH_DIR}"/registry/config
cat > "${TEST_SCRATCH_DIR}"/registry/config/htpasswd <<< "$htpasswd"
cat > "${TEST_SCRATCH_DIR}"/registry/config/config.yml <<< "$config"
chmod 644 "${TEST_SCRATCH_DIR}"/registry/config/htpasswd "${TEST_SCRATCH_DIR}"/registry/config/config.yml
# generate a new key and certificate
if ! openssl req -newkey rsa:4096 -nodes -sha256 -keyout "${TEST_SCRATCH_DIR}"/registry/certs/localhost.key -x509 -days 2 -addext "subjectAltName = DNS:localhost" -out "${TEST_SCRATCH_DIR}"/registry/certs/localhost.crt -subj "/CN=localhost" ; then
die error creating new key and certificate
fi
chmod 644 "${TEST_SCRATCH_DIR}"/registry/certs/localhost.crt
chmod 600 "${TEST_SCRATCH_DIR}"/registry/certs/localhost.key
# use a copy of the server's certificate for validation from a client
cp "${TEST_SCRATCH_DIR}"/registry/certs/localhost.crt "${TEST_SCRATCH_DIR}"/registry/
# create a container in its own storage
_prefetch "[vfs@${TEST_SCRATCH_DIR}/registry/root+${TEST_SCRATCH_DIR}/registry/run]" ${REGISTRY_IMAGE}
ctr=$(${BUILDAH_BINARY} --storage-driver vfs --root "${TEST_SCRATCH_DIR}"/registry/root --runroot "${TEST_SCRATCH_DIR}"/registry/run from --quiet --pull-never ${REGISTRY_IMAGE})
${BUILDAH_BINARY} --storage-driver vfs --root "${TEST_SCRATCH_DIR}"/registry/root --runroot "${TEST_SCRATCH_DIR}"/registry/run copy $ctr "${TEST_SCRATCH_DIR}"/registry/config/htpasswd "${TEST_SCRATCH_DIR}"/registry/config/config.yml "${TEST_SCRATCH_DIR}"/registry/certs/localhost.key "${TEST_SCRATCH_DIR}"/registry/certs/localhost.crt /etc/docker/registry/
# fire it up
coproc ${BUILDAH_BINARY} --storage-driver vfs --root "${TEST_SCRATCH_DIR}"/registry/root --runroot "${TEST_SCRATCH_DIR}"/registry/run run --net host "$ctr" /entrypoint.sh /etc/docker/registry/config.yml 2> "${TEST_SCRATCH_DIR}"/registry/registry.log
# record the coprocess's ID and try to parse the listening port from the log
# we're separating all of this from the storage for any test that might call
# this function and using vfs to minimize the cleanup required
REGISTRY_PID="${COPROC_PID}"
REGISTRY_DIR="${TEST_SCRATCH_DIR}"/registry
REGISTRY_PORT=
local waited=0
while [ -z "${REGISTRY_PORT}" ] ; do
if [ $waited -ge $BUILDAH_TIMEOUT ] ; then
echo Could not determine listening port from log:
sed -e 's/^/ >/' ${TEST_SCRATCH_DIR}/registry/registry.log
stop_registry
false
fi
waited=$((waited+1))
sleep 1
REGISTRY_PORT=$(sed -ne 's^.*listening on.*:\([0-9]\+\),.*^\1^p' ${TEST_SCRATCH_DIR}/registry/registry.log)
done
# push the registry image we just started... to itself, as a confidence check
if ! ${BUILDAH_BINARY} --storage-driver vfs --root "${REGISTRY_DIR}"/root --runroot "${REGISTRY_DIR}"/run push --cert-dir "${REGISTRY_DIR}" --creds "${testuser}":"${testpassword}" "${REGISTRY_IMAGE}" localhost:"${REGISTRY_PORT}"/registry; then
echo error pushing to /registry repository at localhost:$REGISTRY_PORT
stop_registry
false
fi
}
function stop_registry() {
if test -n "${REGISTRY_PID}" ; then
kill "${REGISTRY_PID}"
wait "${REGISTRY_PID}" || true
fi
unset REGISTRY_PID
unset REGISTRY_PORT
if test -n "${REGISTRY_DIR}" ; then
${BUILDAH_BINARY} --storage-driver vfs --root "${REGISTRY_DIR}"/root --runroot "${REGISTRY_DIR}"/run rmi -a -f
rm -fr "${REGISTRY_DIR}"
fi
unset REGISTRY_DIR
}
|