github.com/containers/podman/v5@v5.1.0-rc1/test/system/070-build.bats (about) 1 #!/usr/bin/env bats -*- bats -*- 2 # shellcheck disable=SC2096 3 # 4 # Tests for podman build 5 # 6 7 load helpers 8 9 # bats test_tags=distro-integration 10 @test "podman build - basic test" { 11 rand_filename=$(random_string 20) 12 rand_content=$(random_string 50) 13 14 tmpdir=$PODMAN_TMPDIR/build-test 15 mkdir -p $tmpdir 16 dockerfile=$tmpdir/Dockerfile 17 cat >$dockerfile <<EOF 18 FROM $IMAGE 19 RUN apk add nginx 20 RUN echo $rand_content > /$rand_filename 21 EOF 22 23 # The 'apk' command can take a long time to fetch files; bump timeout 24 PODMAN_TIMEOUT=240 run_podman build -t build_test --format=docker $tmpdir 25 is "$output" ".*COMMIT" "COMMIT seen in log" 26 27 # $IMAGE is preloaded, so we should never re-pull 28 assert "$output" !~ "Trying to pull" "Default pull policy should be 'missing'" 29 assert "$output" !~ "Writing manifest" "Default pull policy should be 'missing'" 30 31 run_podman run --rm build_test cat /$rand_filename 32 is "$output" "$rand_content" "reading generated file in image" 33 34 run_podman rmi -f build_test 35 } 36 37 @test "podman buildx - basic test" { 38 rand_filename=$(random_string 20) 39 rand_content=$(random_string 50) 40 41 tmpdir=$PODMAN_TMPDIR/build-test 42 mkdir -p $tmpdir 43 dockerfile=$tmpdir/Dockerfile 44 cat >$dockerfile <<EOF 45 FROM $IMAGE 46 RUN echo $rand_content > /$rand_filename 47 VOLUME /a/b/c 48 VOLUME ['/etc/foo', '/etc/bar'] 49 EOF 50 51 run_podman info --format '{{ .Host.BuildahVersion}}' 52 BUILDAH_VERSION=$output 53 54 run_podman buildx version 55 is "$output" "buildah ${BUILDAH_VERSION}" "buildx version contains Buildah version" 56 57 run_podman buildx build --load -t build_test --format=docker $tmpdir 58 is "$output" ".*COMMIT" "COMMIT seen in log" 59 60 run_podman run --rm build_test cat /$rand_filename 61 is "$output" "$rand_content" "reading generated file in image" 62 63 # Make sure the volumes are created at surprising yet Docker-compatible 64 # destinations (see bugzilla.redhat.com/show_bug.cgi?id=2014149). 65 run_podman run --rm build_test find /[ /etc/bar\] -print 66 is "$output" "/\[ 67 /\[/etc 68 /\[/etc/foo, 69 /etc/bar]" "weird VOLUME gets converted to directories with brackets and comma" 70 71 # Now confirm that each volume got a unique device ID 72 run_podman run --rm build_test stat -c '%D' / /a /a/b /a/b/c /\[ /\[/etc /\[/etc/foo, /etc /etc/bar\] 73 # First, the non-volumes should all be the same... 74 assert "${lines[0]}" = "${lines[1]}" "devnum( / ) = devnum( /a )" 75 assert "${lines[0]}" = "${lines[2]}" "devnum( / ) = devnum( /a/b )" 76 assert "${lines[0]}" = "${lines[4]}" "devnum( / ) = devnum( /[ )" 77 assert "${lines[0]}" = "${lines[5]}" "devnum( / ) = devnum( /[etc )" 78 assert "${lines[0]}" = "${lines[7]}" "devnum( / ) = devnum( /etc )" 79 assert "${lines[6]}" = "${lines[8]}" "devnum( /[etc/foo, ) = devnum( /etc/bar] )" 80 # ...then, check volumes; these differ between overlay and vfs. 81 # Under Overlay (usual case), these will be different. On VFS, they're the same. 82 local op="!=" 83 if [[ "$(podman_storage_driver)" == "vfs" ]]; then 84 op="=" 85 fi 86 assert "${lines[0]}" $op "${lines[3]}" "devnum( / ) $op devnum( volume0 )" 87 assert "${lines[0]}" $op "${lines[6]}" "devnum( / ) $op devnum( volume1 )" 88 89 # FIXME: is this expected? I thought /a/b/c and /[etc/foo, would differ 90 assert "${lines[3]}" = "${lines[6]}" "devnum( volume0 ) = devnum( volume1 )" 91 92 run_podman rmi -f build_test 93 } 94 95 @test "podman build test -f -" { 96 rand_filename=$(random_string 20) 97 rand_content=$(random_string 50) 98 99 tmpdir=$PODMAN_TMPDIR/build-test 100 mkdir -p $tmpdir 101 containerfile=$PODMAN_TMPDIR/Containerfile 102 cat >$containerfile <<EOF 103 FROM $IMAGE 104 RUN echo $rand_content > /$rand_filename 105 EOF 106 107 run_podman build -t build_test -f - --format=docker $tmpdir < $containerfile 108 is "$output" ".*COMMIT" "COMMIT seen in log" 109 110 run_podman run --rm build_test cat /$rand_filename 111 is "$output" "$rand_content" "reading generated file in image" 112 113 run_podman rmi -f build_test 114 115 # Now try without specifying a context dir 116 run_podman build -t build_test -f - < $containerfile 117 is "$output" ".*COMMIT" "COMMIT seen in log" 118 119 run_podman rmi -f build_test 120 } 121 122 @test "podman build - global runtime flags test" { 123 skip_if_remote "--runtime-flag flag not supported for remote" 124 125 rand_content=$(random_string 50) 126 127 tmpdir=$PODMAN_TMPDIR/build-test 128 mkdir -p $tmpdir 129 containerfile=$tmpdir/Containerfile 130 cat >$containerfile <<EOF 131 FROM $IMAGE 132 RUN echo $rand_content 133 EOF 134 135 run_podman 1 --runtime-flag invalidflag build -t build_test $tmpdir 136 is "$output" ".*invalidflag" "failed when passing undefined flags to the runtime" 137 } 138 139 @test "podman build - set runtime" { 140 skip_if_remote "--runtime flag not supported for remote" 141 # Test on the CLI and via containers.conf 142 143 tmpdir=$PODMAN_TMPDIR/build-test 144 mkdir -p $tmpdir 145 containerfile=$tmpdir/Containerfile 146 cat >$containerfile <<EOF 147 FROM $IMAGE 148 RUN echo $rand_content 149 EOF 150 151 run_podman 125 --runtime=idonotexist build -t build_test $tmpdir 152 is "$output" ".*\"idonotexist\" not found.*" "failed when passing invalid OCI runtime via CLI" 153 154 containersconf=$tmpdir/containers.conf 155 cat >$containersconf <<EOF 156 [engine] 157 runtime="idonotexist" 158 EOF 159 160 CONTAINERS_CONF="$containersconf" run_podman 125 build -t build_test $tmpdir 161 is "$output" ".*\"idonotexist\" not found.*" \ 162 "failed when passing invalid OCI runtime via \$CONTAINERS_CONF" 163 164 CONTAINERS_CONF_OVERRIDE="$containersconf" run_podman 125 build -t build_test $tmpdir 165 is "$output" ".*\"idonotexist\" not found.*" \ 166 "failed when passing invalid OCI runtime via \$CONTAINERS_CONF_OVERRIDE" 167 } 168 169 # Regression from v1.5.0. This test passes fine in v1.5.0, fails in 1.6 170 @test "podman build - cache (#3920)" { 171 # Make an empty test directory, with a subdirectory used for tar 172 tmpdir=$PODMAN_TMPDIR/build-test 173 mkdir -p $tmpdir/subtest 174 175 echo "This is the ORIGINAL file" > $tmpdir/subtest/myfile1 176 tar -C $tmpdir -cJf $tmpdir/myfile.tar.xz subtest 177 178 cat >$tmpdir/Dockerfile <<EOF 179 FROM $IMAGE 180 ADD myfile.tar.xz / 181 EOF 182 183 # One of: ADD myfile /myfile or COPY . . 184 run_podman build -t build_test -f $tmpdir/Dockerfile $tmpdir 185 is "$output" ".*COMMIT" "COMMIT seen in log" 186 if [[ "$output" =~ "Using cache" ]]; then 187 is "$output" "[no instance of 'Using cache']" "no cache used" 188 fi 189 iid=${lines[-1]} 190 191 run_podman run --rm build_test cat /subtest/myfile1 192 is "$output" "This is the ORIGINAL file" "file contents, first time" 193 194 # Step 2: Recreate the tarfile, with new content. Rerun podman build. 195 echo "This is a NEW file" >| $tmpdir/subtest/myfile2 196 tar -C $tmpdir -cJf $tmpdir/myfile.tar.xz subtest 197 198 run_podman build -t build_test -f $tmpdir/Dockerfile $tmpdir 199 is "$output" ".*COMMIT" "COMMIT seen in log" 200 201 # Since the tarfile is modified, podman SHOULD NOT use a cached layer. 202 if [[ "$output" =~ "Using cache" ]]; then 203 is "$output" "[no instance of 'Using cache']" "no cache used" 204 fi 205 206 # Pre-buildah-1906, this fails with ENOENT because the tarfile was cached 207 run_podman run --rm build_test cat /subtest/myfile2 208 is "$output" "This is a NEW file" "file contents, second time" 209 210 run_podman rmi -f build_test $iid 211 } 212 213 @test "podman build test -f ./relative" { 214 rand_filename=$(random_string 20) 215 rand_content=$(random_string 50) 216 217 tmpdir=$PODMAN_TMPDIR/build-test 218 mkdir -p $tmpdir 219 mkdir -p $PODMAN_TMPDIR/reldir 220 221 containerfile=$PODMAN_TMPDIR/reldir/Containerfile 222 cat >$containerfile <<EOF 223 FROM $IMAGE 224 RUN echo $rand_content > /$rand_filename 225 EOF 226 227 # "TMPDIR=relative-path" tests buildah PR #5084. Prior to that, podman failed in RUN: 228 # error running container: checking permissions on "sub-tmp-dir/buildah2917655141": ENOENT 229 cd $PODMAN_TMPDIR 230 mkdir sub-tmp-dir 231 TMPDIR=sub-tmp-dir run_podman build -t build_test -f ./reldir/Containerfile --format=docker $tmpdir 232 is "$output" ".*COMMIT" "COMMIT seen in log" 233 234 run_podman run --rm build_test cat /$rand_filename 235 is "$output" "$rand_content" "reading generated file in image" 236 237 run_podman rmi -f build_test 238 } 239 240 @test "podman parallel build should not race" { 241 skip_if_remote "following test is not supported for remote clients" 242 243 # Run thirty parallel builds using the same Containerfile 244 cat >$PODMAN_TMPDIR/Containerfile <<EOF 245 FROM $IMAGE 246 RUN echo hi 247 EOF 248 249 local count=30 250 for i in $(seq --format '%02g' 1 $count); do 251 timeout --foreground -v --kill=10 60 \ 252 $PODMAN build -t i$i $PODMAN_TMPDIR &> $PODMAN_TMPDIR/log.$i & 253 done 254 255 # Wait for all background builds to complete. Note that this succeeds 256 # even if some of the individual builds fail! Our actual test is below. 257 wait 258 259 # For debugging, e.g., #21742 260 for log in $PODMAN_TMPDIR/log.*;do 261 echo 262 echo $log ":" 263 cat $log 264 done 265 266 # Now delete all built images. If any image wasn't built, rmi will fail 267 # and test will fail. 268 run_podman rmi $(seq --format 'i%02g' 1 $count) 269 } 270 271 @test "podman build - URLs" { 272 tmpdir=$PODMAN_TMPDIR/build-test 273 mkdir -p $tmpdir 274 275 cat >$tmpdir/Dockerfile <<EOF 276 FROM $IMAGE 277 ADD https://github.com/containers/podman/blob/main/README.md /tmp/ 278 EOF 279 run_podman build -t add_url $tmpdir 280 run_podman run --rm add_url stat /tmp/README.md 281 run_podman rmi -f add_url 282 283 # Now test COPY. That should fail. 284 sed -i -e 's/ADD/COPY/' $tmpdir/Dockerfile 285 run_podman 125 build -t copy_url $tmpdir 286 is "$output" ".* building at STEP .*: source can't be a URL for COPY" 287 } 288 289 290 # bats test_tags=distro-integration 291 @test "podman build - workdir, cmd, env, label" { 292 tmpdir=$PODMAN_TMPDIR/build-test 293 mkdir -p $tmpdir 294 295 # Random workdir, and multiple random strings to verify command & env 296 workdir=/$(random_string 10) 297 s_echo=$(random_string 15) 298 s_env1=$(random_string 20) 299 s_env2=$(random_string 25) 300 s_env3=$(random_string 30) 301 s_env4=$(random_string 40) 302 303 # Label name: make sure it begins with a letter! jq barfs if you 304 # try to ask it for '.foo.<N>xyz', i.e. any string beginning with digit 305 label_name=l$(random_string 8) 306 label_value=$(random_string 12) 307 308 # #8679: Create a secrets directory, and mount it in the container 309 # (can only test locally; podman-remote has no --default-mounts-file opt) 310 MOUNTS_CONF= 311 secret_contents="ceci nest pas un secret" 312 CAT_SECRET="echo $secret_contents" 313 if ! is_remote; then 314 mkdir $tmpdir/secrets 315 echo $tmpdir/secrets:/run/secrets > $tmpdir/mounts.conf 316 317 secret_filename=secretfile-$(random_string 20) 318 secret_contents=shhh-$(random_string 30)-shhh 319 echo $secret_contents >$tmpdir/secrets/$secret_filename 320 321 MOUNTS_CONF=--default-mounts-file=$tmpdir/mounts.conf 322 CAT_SECRET="cat /run/secrets/$secret_filename" 323 fi 324 325 # For --dns-search: a domain that is unlikely to exist 326 local nosuchdomain=nx$(random_string 10).net 327 328 # Command to run on container startup with no args 329 cat >$tmpdir/mycmd <<EOF 330 #!/bin/sh 331 PATH=/usr/bin:/bin 332 pwd 333 echo "\$1" 334 printenv | grep MYENV | sort | sed -e 's/^MYENV.=//' 335 $CAT_SECRET 336 EOF 337 338 # For overriding with --env-file; using multiple files confirms that 339 # the --env-file option is cumulative, not last-one-wins. 340 cat >$PODMAN_TMPDIR/env-file1 <<EOF 341 MYENV3=$s_env3 342 http_proxy=http-proxy-in-env-file 343 EOF 344 cat >$PODMAN_TMPDIR/env-file2 <<EOF 345 https_proxy=https-proxy-in-env-file 346 EOF 347 348 # Build args: one explicit (foo=bar), one implicit (foo) 349 local arg_implicit_value=implicit_$(random_string 15) 350 local arg_explicit_value=explicit_$(random_string 15) 351 352 # NOTE: it's important to not create the workdir. 353 # Podman will make sure to create a missing workdir 354 # if needed. See #9040. 355 cat >$tmpdir/Containerfile <<EOF 356 FROM $IMAGE 357 ARG arg_explicit 358 ARG arg_implicit 359 LABEL $label_name=$label_value 360 WORKDIR $workdir 361 362 # Test for #7094 - chowning of invalid symlinks 363 RUN mkdir -p /a/b/c 364 RUN ln -s /no/such/nonesuch /a/b/c/badsymlink 365 RUN ln -s /bin/mydefaultcmd /a/b/c/goodsymlink 366 RUN touch /a/b/c/myfile 367 RUN chown -h 1:2 /a/b/c/badsymlink /a/b/c/goodsymlink && chown -h 4:5 /a/b/c/myfile 368 VOLUME /a/b/c 369 370 # Test for environment passing and override 371 ENV MYENV1=$s_env1 372 ENV MYENV2 this-should-be-overridden-by-env-host 373 ENV MYENV3 this-should-be-overridden-by-env-file 374 ENV MYENV4 this-should-be-overridden-by-cmdline 375 ENV http_proxy http-proxy-in-image 376 ENV ftp_proxy ftp-proxy-in-image 377 ADD mycmd /bin/mydefaultcmd 378 RUN chmod 755 /bin/mydefaultcmd 379 RUN chown 2:3 /bin/mydefaultcmd 380 381 RUN $CAT_SECRET 382 383 RUN echo explicit-build-arg=\$arg_explicit 384 RUN echo implicit-build-arg=\$arg_implicit 385 386 CMD ["/bin/mydefaultcmd","$s_echo"] 387 RUN cat /etc/resolv.conf 388 EOF 389 390 # The goal is to test that a missing value will be inherited from 391 # environment - but that can't work with remote, so for simplicity 392 # just make it explicit in that case too. 393 local build_arg_implicit="--build-arg arg_implicit" 394 if is_remote; then 395 build_arg_implicit+="=$arg_implicit_value" 396 fi 397 398 # cd to the dir, so we test relative paths (important for podman-remote) 399 cd $PODMAN_TMPDIR 400 export arg_explicit="THIS SHOULD BE OVERRIDDEN BY COMMAND LINE!" 401 export arg_implicit=${arg_implicit_value} 402 run_podman ${MOUNTS_CONF} build \ 403 --build-arg arg_explicit=${arg_explicit_value} \ 404 $build_arg_implicit \ 405 --dns-search $nosuchdomain \ 406 -t build_test -f build-test/Containerfile build-test 407 local iid="${lines[-1]}" 408 409 assert "$output" !~ "missing.*build.argument" \ 410 "podman did not see the given --build-arg(s)" 411 412 # Make sure 'podman build' had the secret mounted 413 is "$output" ".*$secret_contents.*" "podman build has /run/secrets mounted" 414 415 # --build-arg should be set, both via 'foo=bar' and via just 'foo' ($foo) 416 is "$output" ".*explicit-build-arg=${arg_explicit_value}" \ 417 "--build-arg arg_explicit=explicit-value works" 418 is "$output" ".*implicit-build-arg=${arg_implicit_value}" \ 419 "--build-arg arg_implicit works (inheriting from environment)" 420 is "$output" ".*search $nosuchdomain" \ 421 "--dns-search added to /etc/resolv.conf" 422 423 if is_remote; then 424 ENVHOST="" 425 else 426 ENVHOST="--env-host" 427 fi 428 429 # Run without args - should run the above script. Verify its output. 430 export MYENV2="$s_env2" 431 export MYENV3="env-file-should-override-env-host!" 432 run_podman ${MOUNTS_CONF} run --rm \ 433 --env-file=$PODMAN_TMPDIR/env-file1 \ 434 --env-file=$PODMAN_TMPDIR/env-file2 \ 435 ${ENVHOST} \ 436 -e MYENV4="$s_env4" \ 437 build_test 438 is "${lines[0]}" "$workdir" "container default command: pwd" 439 is "${lines[1]}" "$s_echo" "container default command: output from echo" 440 441 is "${lines[2]}" "$s_env1" "container default command: env1" 442 443 if is_remote; then 444 is "${lines[3]}" "this-should-be-overridden-by-env-host" "podman-remote does not send local environment" 445 else 446 is "${lines[3]}" "$s_env2" "container default command: env2" 447 fi 448 449 is "${lines[4]}" "$s_env3" "container default command: env3 (from envfile)" 450 is "${lines[5]}" "$s_env4" "container default command: env4 (from cmdline)" 451 452 is "${lines[6]}" "$secret_contents" \ 453 "Contents of /run/secrets/$secret_filename in container" 454 455 # Proxies - environment should override container, but not env-file 456 http_proxy=http-proxy-from-env ftp_proxy=ftp-proxy-from-env \ 457 run_podman run --rm \ 458 --env-file=$PODMAN_TMPDIR/env-file1 \ 459 --env-file=$PODMAN_TMPDIR/env-file2 \ 460 build_test \ 461 printenv http_proxy https_proxy ftp_proxy 462 is "${lines[0]}" "http-proxy-in-env-file" "env-file overrides env" 463 is "${lines[1]}" "https-proxy-in-env-file" "env-file sets proxy var" 464 465 if is_remote; then 466 is "${lines[2]}" "ftp-proxy-in-image" "podman-remote does not send local environment" 467 else 468 is "${lines[2]}" "ftp-proxy-from-env" "ftp-proxy is passed through" 469 fi 470 471 # test that workdir is set for command-line commands also 472 run_podman run --rm build_test pwd 473 is "$output" "$workdir" "pwd command in container" 474 475 # Determine buildah version, so we can confirm it gets into Labels 476 # Multiple --format options confirm command-line override (last one wins) 477 run_podman info --format '{{.Ignore}}' --format '{{ .Host.BuildahVersion }}' 478 is "$output" "[1-9][0-9.-]\+" ".Host.BuildahVersion is reasonable" 479 buildah_version=$output 480 481 # Confirm that 'podman inspect' shows the expected values 482 # FIXME: can we rely on .Env[0] being PATH, and the rest being in order?? 483 run_podman image inspect build_test 484 485 # (Assert that output is formatted, not a one-line blob: #8011) 486 assert "${#lines[*]}" -ge 10 "Output from 'image inspect'; see #8011" 487 488 tests=" 489 Env[1] | MYENV1=$s_env1 490 Env[2] | MYENV2=this-should-be-overridden-by-env-host 491 Env[3] | MYENV3=this-should-be-overridden-by-env-file 492 Env[4] | MYENV4=this-should-be-overridden-by-cmdline 493 Cmd[0] | /bin/mydefaultcmd 494 Cmd[1] | $s_echo 495 WorkingDir | $workdir 496 Labels.$label_name | $label_value 497 " 498 # FIXME: 2021-02-24: Fixed in buildah #3036; re-enable this once podman 499 # vendors in a newer buildah! 500 # Labels.\"io.buildah.version\" | $buildah_version 501 502 parse_table "$tests" | while read field expect; do 503 actual=$(jq -r ".[0].Config.$field" <<<"$output") 504 dprint "# actual=<$actual> expect=<$expect}>" 505 is "$actual" "$expect" "jq .Config.$field" 506 done 507 508 # Bad symlink in volume. Prior to #7094, well, we wouldn't actually 509 # get here because any 'podman run' on a volume that had symlinks, 510 # be they dangling or valid, would barf with 511 # Error: chown <mountpath>/_data/symlink: ENOENT 512 run_podman run --rm build_test stat -c'%u:%g:%N' /a/b/c/badsymlink 513 is "$output" "1:2:'/a/b/c/badsymlink' -> '/no/such/nonesuch'" \ 514 "bad symlink to nonexistent file is chowned and preserved" 515 516 run_podman run --rm build_test stat -c'%u:%g:%N' /a/b/c/goodsymlink 517 is "$output" "1:2:'/a/b/c/goodsymlink' -> '/bin/mydefaultcmd'" \ 518 "good symlink to existing file is chowned and preserved" 519 520 run_podman run --rm build_test stat -c'%u:%g' /bin/mydefaultcmd 521 is "$output" "2:3" "target of symlink is not chowned" 522 523 run_podman run --rm build_test stat -c'%u:%g:%N' /a/b/c/myfile 524 is "$output" "4:5:/a/b/c/myfile" "file in volume is chowned" 525 526 # Hey, as long as we have an image with lots of layers, let's 527 # confirm that 'image tree' works as expected 528 run_podman image tree build_test 529 is "${lines[0]}" "Image ID: ${iid:0:12}" \ 530 "image tree: first line" 531 is "${lines[1]}" "Tags: \[localhost/build_test:latest]" \ 532 "image tree: second line" 533 is "${lines[2]}" "Size: [0-9.]\+[kM]B" \ 534 "image tree: third line" 535 is "${lines[3]}" "Image Layers" \ 536 "image tree: fourth line" 537 # FIXME: if #14536 is ever fixed, rebuild testimage & s/5/4/ below. 538 # Summary: this should be ${lines[4]}, not [5], and prior to 2022-06-15 539 # it was. Unfortunately, a nightmarish bug interaction makes it impossible 540 # for us to use --squash-all on our testimage. Unless/until that bug is 541 # fixed, we have an extra layer that all we can do is ignore. 542 is "${lines[5]}" ".* ID: [0-9a-f]\{12\} Size: .* Top Layer of: \[$IMAGE]" \ 543 "image tree: first layer line" 544 is "${lines[-1]}" ".* ID: [0-9a-f]\{12\} Size: .* Top Layer of: \[localhost/build_test:latest]" \ 545 "image tree: last layer line" 546 547 # FIXME: 'image tree --whatrequires' does not work via remote 548 if ! is_remote; then 549 run_podman image tree --whatrequires $IMAGE 550 is "${lines[-1]}" \ 551 ".*ID: .* Top Layer of: \\[localhost/build_test:latest\\]" \ 552 "'image tree --whatrequires' shows our built image" 553 fi 554 555 # Clean up 556 run_podman rmi -f build_test 557 } 558 559 @test "podman build - COPY with ignore" { 560 local tmpdir=$PODMAN_TMPDIR/build-test-$(random_string 10) 561 mkdir -p $tmpdir/subdir{1,2} 562 563 # Create a bunch of files. Declare this as an array to avoid duplication 564 # because we iterate over that list below, checking for each file. 565 # A leading "-" indicates that the file SHOULD NOT exist in the built image 566 # 567 # Weird side effect of Buildah 3486, relating to subdirectories and 568 # wildcard patterns. See that PR for details, it's way too confusing 569 # to explain in a comment. 570 local -a files=( 571 -test1 -test1.txt 572 test2 test2.txt 573 subdir1/sub1 subdir1/sub1.txt 574 -subdir1/sub2 -subdir1/sub2.txt 575 subdir1/sub3 subdir1/sub3.txt 576 -subdir2/sub1 -subdir2/sub1.txt 577 -subdir2/sub2 -subdir2/sub2.txt 578 -subdir2/sub3 -subdir2/sub3.txt 579 this-file-does-not-match-anything-in-ignore-file 580 comment 581 ) 582 for f in "${files[@]}"; do 583 # The magic '##-' strips off the '-' prefix 584 echo "$f" > $tmpdir/${f##-} 585 done 586 587 # Directory that doesn't exist in the image; COPY should create it 588 local newdir=/newdir-$(random_string 12) 589 cat >$tmpdir/Containerfile <<EOF 590 FROM $IMAGE 591 COPY ./ $newdir/ 592 EOF 593 594 # Run twice: first with a custom --ignorefile, then with a default one. 595 # This ordering is deliberate: if we were to run with .dockerignore 596 # first, and forget to rm it, and then run with --ignorefile, _and_ 597 # there was a bug in podman where --ignorefile was a NOP (eg #9570), 598 # the test might pass because of the existence of .dockerfile. 599 for ignorefile in ignoreme-$(random_string 5) .dockerignore; do 600 # Patterns to ignore. Mostly copied from buildah/tests/bud/dockerignore 601 cat >$tmpdir/$ignorefile <<EOF 602 # comment 603 test* 604 !test2* 605 subdir1 606 subdir2 607 !*/sub1* 608 !subdir1/sub3* 609 EOF 610 611 # Build an image. For .dockerignore 612 local -a ignoreflag 613 unset ignoreflag 614 if [[ $ignorefile != ".dockerignore" ]]; then 615 ignoreflag="--ignorefile $tmpdir/$ignorefile" 616 fi 617 run_podman build -t build_test ${ignoreflag} $tmpdir 618 619 # Delete the ignore file! Otherwise, in the next iteration of the loop, 620 # we could end up with an existing .dockerignore that invisibly 621 # takes precedence over --ignorefile 622 rm -f $tmpdir/$ignorefile 623 624 # It would be much more readable, and probably safer, to iterate 625 # over each file, running 'podman run ... ls -l $f'. But each podman run 626 # takes a second or so, and we are mindful of each second. 627 run_podman run --rm build_test find $newdir -type f 628 for f in ${files[@]}; do 629 if [[ $f =~ ^- ]]; then 630 f=${f##-} 631 assert "$output" !~ "$f" \ 632 "File '$f' should have been ignored via $ignorefile" 633 else 634 assert "$output" =~ "$newdir/$f" \ 635 "File '$f' should exist in container (no match in $ignorefile)" 636 fi 637 done 638 639 # Clean up 640 run_podman rmi -f build_test 641 done 642 } 643 644 # Regression test for #9867 and #13529 645 # Make sure that if you exclude everything in context dir, that 646 # the Containerfile/Dockerfile in the context dir are used 647 @test "podman build with ignore '*'" { 648 local tmpdir=$PODMAN_TMPDIR/build-test-$(random_string 10) 649 mkdir -p $tmpdir 650 651 cat >$tmpdir/Containerfile <<EOF 652 FROM scratch 653 EOF 654 655 cat >$tmpdir/.dockerignore <<EOF 656 * 657 EOF 658 659 # Prior to the fix for #13529, pod-create would fail with 'error building 660 # at STEP COPY .../catatonit' because of the local .dockerignore file was 661 # used. 662 pushd "${tmpdir}" 663 run_podman pod create 664 run_podman pod rm $output 665 run_podman rmi $(pause_image) 666 popd 667 668 run_podman build -t build_test $tmpdir 669 670 # Rename Containerfile to Dockerfile 671 mv $tmpdir/Containerfile $tmpdir/Dockerfile 672 673 run_podman build -t build_test $tmpdir 674 675 # Rename Dockerfile to foofile 676 mv $tmpdir/Dockerfile $tmpdir/foofile 677 678 run_podman 125 build -t build_test $tmpdir 679 is "$output" "Error: no Containerfile or Dockerfile specified or found in context directory, $tmpdir: no such file or directory" 680 run_podman build -t build_test -f $tmpdir/foofile $tmpdir 681 682 # Clean up 683 run_podman rmi -f build_test 684 } 685 686 # Regression test for #20259 687 @test "podman build with ignore '*' and containerfile outside of build context" { 688 local tmpdir=$PODMAN_TMPDIR/build-test-$(random_string 10) 689 mkdir -p $tmpdir 690 mkdir -p $tmpdir/context 691 692 cat >$tmpdir/Containerfile <<EOF 693 FROM scratch 694 EOF 695 696 cat >$tmpdir/context/.containerignore <<EOF 697 * 698 EOF 699 run_podman build -t build_test -f $tmpdir/Containerfile $tmpdir/context 700 701 # Clean up 702 run_podman rmi -f build_test 703 } 704 705 @test "podman build - stdin test" { 706 # Random workdir, and random string to verify build output 707 workdir=/$(random_string 10) 708 random_echo=$(random_string 15) 709 PODMAN_TIMEOUT=240 run_podman build -t build_test - << EOF 710 FROM $IMAGE 711 RUN mkdir $workdir 712 WORKDIR $workdir 713 RUN /bin/echo $random_echo 714 EOF 715 is "$output" ".*COMMIT" "COMMIT seen in log" 716 is "$output" ".*STEP .*: RUN /bin/echo $random_echo" 717 718 run_podman run --rm build_test pwd 719 is "$output" "$workdir" "pwd command in container" 720 721 run_podman rmi -f build_test 722 } 723 724 # #8092 - podman build should not gobble stdin (Fixes: #8066) 725 @test "podman build - does not gobble stdin that does not belong to it" { 726 random1=random1-$(random_string 12) 727 random2=random2-$(random_string 15) 728 random3=random3-$(random_string 12) 729 730 tmpdir=$PODMAN_TMPDIR/build-test 731 mkdir -p $tmpdir 732 cat >$tmpdir/Containerfile <<EOF 733 FROM $IMAGE 734 RUN echo x${random2}y 735 EOF 736 737 # This is a little rococo, bear with me please. #8092 fixed a bug 738 # in which 'podman build' would slurp up any input in the pipeline. 739 # Not a problem in a contrived example such as the one below, but 740 # definitely a problem when running commands in a pipeline to bash: 741 # all commands after 'podman build' would silently be ignored. 742 # In the test below, prior to #8092, the 'sed' would not get 743 # any input, and we would never see $random3 in the output. 744 # And, we use 'sed' to massage $random3 just on the remote 745 # chance that podman itself could pass stdin through. 746 results=$(echo $random3 | ( 747 echo $random1 748 run_podman build -t build_test $tmpdir 749 sed -e 's/^/a/' -e 's/$/z/' 750 )) 751 752 # First simple test: confirm that we see the piped-in string, as 753 # massaged by sed. This fails in 287edd4e2, the commit before #8092. 754 # We do this before the thorough test (below) because, should it 755 # fail, the diagnostic is much clearer and easier to understand. 756 is "$results" ".*a${random3}z" "stdin remains after podman-build" 757 758 # More thorough test: verify all the required strings in order. 759 # This is unlikely to fail, but it costs us nothing and could 760 # catch a regression somewhere else. 761 # FIXME: podman-remote output differs from local: #8342 (spurious ^M) 762 # FIXME: podman-remote output differs from local: #8343 (extra SHA output) 763 remote_extra="" 764 if is_remote; then remote_extra=".*";fi 765 expect="${random1} 766 .* 767 \[[0-9:.]\+\] STEP 1/2: FROM $IMAGE 768 STEP 2/2: RUN echo x${random2}y 769 x${random2}y${remote_extra} 770 COMMIT build_test${remote_extra} 771 --> [0-9a-f]\{12\} 772 Successfully tagged localhost/build_test:latest 773 [0-9a-f]\{64\} 774 a${random3}z" 775 776 is "$results" "$expect" "Full output from 'podman build' pipeline" 777 778 run_podman rmi -f build_test 779 } 780 781 @test "podman build --layers test" { 782 rand_content=$(random_string 50) 783 tmpdir=$PODMAN_TMPDIR/build-test 784 mkdir -p $tmpdir 785 containerfile=$tmpdir/Containerfile 786 cat >$containerfile <<EOF 787 FROM $IMAGE 788 RUN echo $rand_content 789 EOF 790 791 # Build twice to make sure second time uses cache 792 run_podman build -t build_test $tmpdir 793 if [[ "$output" =~ "Using cache" ]]; then 794 is "$output" "[no instance of 'Using cache']" "no cache used" 795 fi 796 797 run_podman build -t build_test $tmpdir 798 is "$output" ".*cache" "used cache" 799 800 run_podman build -t build_test --layers=true $tmpdir 801 is "$output" ".*cache" "used cache" 802 803 run_podman build -t build_test --layers=false $tmpdir 804 if [[ "$output" =~ "Using cache" ]]; then 805 is "$output" "[no instance of 'Using cache']" "no cache used" 806 fi 807 808 BUILDAH_LAYERS=false run_podman build -t build_test $tmpdir 809 if [[ "$output" =~ "Using cache" ]]; then 810 is "$output" "[no instance of 'Using cache']" "no cache used" 811 fi 812 813 BUILDAH_LAYERS=false run_podman build -t build_test --layers=1 $tmpdir 814 is "$output" ".*cache" "used cache" 815 816 BUILDAH_LAYERS=1 run_podman build -t build_test --layers=false $tmpdir 817 if [[ "$output" =~ "Using cache" ]]; then 818 is "$output" "[no instance of 'Using cache']" "no cache used" 819 fi 820 821 run_podman rmi -f build_test 822 } 823 824 # Caveat lector: this test was mostly copy-pasted from buildah in #9275. 825 # It's not entirely clear what it's testing, or if the 'mount' section is 826 # necessary. 827 @test "build with copy-from referencing the base image" { 828 target=derived 829 target_mt=derived-mt 830 tmpdir=$PODMAN_TMPDIR/build-test 831 mkdir -p $tmpdir 832 833 containerfile1=$tmpdir/Containerfile1 834 cat >$containerfile1 <<EOF 835 FROM $IMAGE AS build 836 RUN rm -f /etc/issue 837 USER 1001 838 COPY --from=$IMAGE /etc/issue /test/ 839 EOF 840 841 containerfile2=$tmpdir/Containerfile2 842 cat >$containerfile2 <<EOF 843 FROM $IMAGE AS test 844 RUN rm -f /etc/alpine-release 845 FROM quay.io/libpod/alpine AS final 846 COPY --from=$IMAGE /etc/alpine-release /test/ 847 EOF 848 849 # Before the build, $IMAGE's base image should not be present 850 local base_image=quay.io/libpod/alpine:latest 851 run_podman 1 image exists $base_image 852 853 run_podman build --jobs 1 -t ${target} -f ${containerfile2} ${tmpdir} 854 run_podman build --no-cache --jobs 4 -t ${target_mt} -f ${containerfile2} ${tmpdir} 855 856 # After the build, the base image should exist 857 run_podman image exists $base_image 858 859 # (can only test locally; podman-remote has no image mount command) 860 # (can also only test as root; mounting under rootless podman is too hard) 861 # We perform the test as a conditional, not a 'skip', because there's 862 # value in testing the above 'build' commands even remote & rootless. 863 if ! is_remote && ! is_rootless; then 864 run_podman image mount ${target} 865 root_single_job=$output 866 867 run_podman image mount ${target_mt} 868 root_multi_job=$output 869 870 # Check that both the version with --jobs 1 and --jobs=N have the same number of files 871 nfiles_single=$(find $root_single_job -type f | wc -l) 872 nfiles_multi=$(find $root_multi_job -type f | wc -l) 873 run_podman image umount ${target_mt} 874 run_podman image umount ${target} 875 876 is "$nfiles_single" "$nfiles_multi" \ 877 "Number of files (--jobs=1) == (--jobs=4)" 878 879 # Make sure the number is reasonable 880 test "$nfiles_single" -gt 50 881 fi 882 883 # Clean up 884 run_podman rmi ${target_mt} ${target} ${base_image} 885 run_podman image prune -f 886 } 887 888 @test "podman build --pull-never" { 889 local tmpdir=$PODMAN_TMPDIR/build-test 890 mkdir -p $tmpdir 891 892 # First, confirm that --pull-never is a NOP if image exists locally 893 local random_string=$(random_string 15) 894 895 cat >$tmpdir/Containerfile <<EOF 896 FROM $IMAGE 897 RUN echo $random_string 898 EOF 899 900 run_podman build -t build_test --pull-never $tmpdir 901 is "$output" ".*$random_string" "pull-never is OK if image already exists" 902 run_podman rmi build_test 903 904 # Now try an image that does not exist locally nor remotely 905 cat >$tmpdir/Containerfile <<EOF 906 FROM quay.io/libpod/nosuchimage:nosuchtag 907 RUN echo $random_string 908 EOF 909 910 run_podman 125 build -t build_test --pull-never $tmpdir 911 is "$output" \ 912 ".*Error: creating build container: quay.io/libpod/nosuchimage:nosuchtag: image not known" \ 913 "--pull-never fails with expected error message" 914 } 915 916 @test "podman build --logfile test" { 917 tmpdir=$PODMAN_TMPDIR/build-test 918 mkdir -p $tmpdir 919 tmpbuilddir=$tmpdir/build 920 mkdir -p $tmpbuilddir 921 dockerfile=$tmpbuilddir/Dockerfile 922 cat >$dockerfile <<EOF 923 FROM $IMAGE 924 EOF 925 926 run_podman build -t build_test --format=docker --logfile=$tmpdir/logfile $tmpbuilddir 927 assert "$(< $tmpdir/logfile)" =~ "COMMIT" "COMMIT seen in log" 928 929 run_podman rmi -f build_test 930 } 931 932 @test "podman build check_label" { 933 skip_if_no_selinux 934 tmpdir=$PODMAN_TMPDIR/build-test 935 mkdir -p $tmpdir 936 tmpbuilddir=$tmpdir/build 937 mkdir -p $tmpbuilddir 938 dockerfile=$tmpbuilddir/Dockerfile 939 cat >$dockerfile <<EOF 940 FROM $IMAGE 941 RUN cat /proc/self/attr/current 942 EOF 943 944 run_podman build -t build_test --security-opt label=level:s0:c3,c4 --format=docker $tmpbuilddir 945 is "$output" ".*s0:c3,c4COMMIT" "label setting level" 946 947 run_podman rmi -f build_test 948 } 949 950 @test "podman build check_seccomp_ulimits" { 951 tmpdir=$PODMAN_TMPDIR/build-test 952 mkdir -p $tmpdir 953 tmpbuilddir=$tmpdir/build 954 mkdir -p $tmpbuilddir 955 dockerfile=$tmpbuilddir/Dockerfile 956 cat >$dockerfile <<EOF 957 FROM $IMAGE 958 RUN grep Seccomp: /proc/self/status |awk '{ print \$1\$2 }' 959 RUN grep "Max open files" /proc/self/limits |awk '{ print \$4":"\$5 }' 960 EOF 961 962 run_podman build --ulimit nofile=101:102 -t build_test $tmpbuilddir 963 is "$output" ".*Seccomp:2" "setting seccomp" 964 is "$output" ".*101:102" "setting ulimits" 965 run_podman rmi -f build_test 966 967 run_podman build -t build_test --security-opt seccomp=unconfined $tmpbuilddir 968 is "$output" ".*Seccomp:0" "setting seccomp" 969 run_podman rmi -f build_test 970 } 971 972 @test "podman build --authfile bogus test" { 973 run_podman 125 build --authfile=/tmp/bogus - <<< "from scratch" 974 is "$output" ".*/tmp/bogus: no such file or directory" 975 } 976 977 @test "podman build COPY hardlinks " { 978 local build_dir=$PODMAN_TMPDIR/build-test 979 980 mkdir -p $build_dir 981 dockerfile=$build_dir/Dockerfile 982 cat >$dockerfile <<EOF 983 FROM $IMAGE 984 COPY . /test 985 EOF 986 987 # Create all our hardlinks, including their parent directories 988 local -a linkfiles=(hardlink1 subdir/hardlink2 subdir/subsubdir/hardlink3) 989 for l in "${linkfiles[@]}"; do 990 mkdir -p $(dirname $build_dir/$l) 991 ln $dockerfile $build_dir/$l 992 done 993 994 run_podman build -t build_test $build_dir 995 996 # Stat() all files in one fell swoop, because it seems impossible 997 # for inode numbers to change within the scope of one exec, but 998 # maybe they do across different runs?? fuse-overlay maybe?? #17979 999 run_podman run --rm build_test \ 1000 stat -c '%i %n' /test/Dockerfile "${linkfiles[@]/#//test/}" 1001 1002 # First output line is the inode of our reference file and its filename. 1003 # Slash-replacement strips off everything after the space. 1004 local dinode="${lines[0]/ */}" 1005 1006 # All subsequent inodes must match the first one. We check filename (%n) 1007 # simply out of unwarranted paranoia. 1008 local i=1 1009 for l in "${linkfiles[@]}"; do 1010 assert "${lines[$i]}" = "$dinode /test/$l" "line $i: inode of $l" 1011 i=$((i + 1)) 1012 done 1013 1014 run_podman rmi -f build_test 1015 } 1016 1017 @test "podman build -f test" { 1018 tmpdir=$PODMAN_TMPDIR/build-test 1019 subdir=$tmpdir/subdir 1020 mkdir -p $subdir 1021 1022 containerfile1=$tmpdir/Containerfile1 1023 cat >$containerfile1 <<EOF 1024 FROM scratch 1025 copy . /tmp 1026 EOF 1027 containerfile2=$PODMAN_TMPDIR/Containerfile2 1028 cat >$containerfile2 <<EOF 1029 FROM $IMAGE 1030 EOF 1031 run_podman build -t build_test -f Containerfile1 $tmpdir 1032 run_podman 125 build -t build_test -f Containerfile2 $tmpdir 1033 is "$output" ".*Containerfile2: no such file or directory" "Containerfile2 should not exist" 1034 run_podman build -t build_test -f $containerfile1 $tmpdir 1035 run_podman build -t build_test -f $containerfile2 $tmpdir 1036 run_podman build -t build_test -f $containerfile1 1037 run_podman build -t build_test -f $containerfile2 1038 run_podman build -t build_test -f $containerfile1 -f $containerfile2 $tmpdir 1039 is "$output" ".*$IMAGE" "Containerfile2 is also passed to server" 1040 run_podman rmi -f build_test 1041 } 1042 1043 @test "podman build .dockerignore failure test" { 1044 tmpdir=$PODMAN_TMPDIR/build-test 1045 subdir=$tmpdir/subdir 1046 mkdir -p $subdir 1047 1048 cat >$tmpdir/.dockerignore <<EOF 1049 * 1050 subdir 1051 !*/sub1* 1052 EOF 1053 cat >$tmpdir/Containerfile <<EOF 1054 FROM $IMAGE 1055 COPY ./ ./ 1056 COPY subdir ./ 1057 EOF 1058 run_podman 125 build -t build_test $tmpdir 1059 is "$output" ".*Error: building at STEP \"COPY subdir ./\"" ".dockerignore was ignored" 1060 } 1061 1062 @test "podman build .containerignore and .dockerignore test" { 1063 tmpdir=$PODMAN_TMPDIR/build-test 1064 mkdir -p $tmpdir 1065 touch $tmpdir/test1 $tmpdir/test2 1066 cat >$tmpdir/.containerignore <<EOF 1067 test2* 1068 EOF 1069 cat >$tmpdir/.dockerignore <<EOF 1070 test1* 1071 EOF 1072 cat >$tmpdir/Containerfile <<EOF 1073 FROM $IMAGE 1074 COPY ./ /tmp/test/ 1075 RUN ls /tmp/test/ 1076 EOF 1077 run_podman build -t build_test $tmpdir 1078 is "$output" ".*test1" "test1 should exists in the final image" 1079 } 1080 1081 @test "podman build build context ownership" { 1082 tmpdir=$PODMAN_TMPDIR/build-test 1083 subdir=$tmpdir/subdir 1084 mkdir -p $subdir 1085 1086 touch $tmpdir/empty-file.txt 1087 if is_remote && ! is_rootless ; then 1088 # TODO: set this file's owner to a UID:GID that will not be mapped 1089 # in the context where the remote server is running, which generally 1090 # requires us to be root (or running with more mapped IDs) on the 1091 # client, but not root (or running with fewer mapped IDs) on the 1092 # remote server 1093 # 4294967292:4294967292 (0xfffffffc:0xfffffffc) isn't that, but 1094 # it will catch errors where a remote server doesn't apply the right 1095 # default as it copies content into the container 1096 chown 4294967292:4294967292 $tmpdir/empty-file.txt 1097 fi 1098 cat >$tmpdir/Dockerfile <<EOF 1099 FROM $IMAGE 1100 COPY empty-file.txt . 1101 RUN echo 0:0 | tee expected.txt 1102 RUN stat -c "%u:%g" empty-file.txt | tee actual.txt 1103 RUN cmp expected.txt actual.txt 1104 EOF 1105 run_podman build -t build_test $tmpdir 1106 } 1107 1108 @test "podman build build context is a symlink to a directory" { 1109 tmpdir=$PODMAN_TMPDIR/build-test 1110 mkdir -p $tmpdir/target 1111 ln -s target $tmpdir/link 1112 echo FROM $IMAGE > $tmpdir/link/Dockerfile 1113 echo RUN echo hello >> $tmpdir/link/Dockerfile 1114 run_podman build -t build_test $tmpdir/link 1115 } 1116 1117 @test "podman build --volumes-from conflict" { 1118 rand_content=$(random_string 50) 1119 1120 tmpdir=$PODMAN_TMPDIR/build-test 1121 mkdir -p $tmpdir 1122 dockerfile=$tmpdir/Dockerfile 1123 cat >$dockerfile <<EOF 1124 FROM $IMAGE 1125 VOLUME /vol 1126 EOF 1127 1128 run_podman build -t build_test $tmpdir 1129 is "$output" ".*COMMIT" "COMMIT seen in log" 1130 1131 run_podman run -d --name test_ctr build_test top 1132 run_podman run --rm --volumes-from test_ctr $IMAGE echo $rand_content 1133 is "$output" "$rand_content" "No error should be thrown about volume in use" 1134 1135 run_podman rmi -f build_test 1136 } 1137 1138 @test "podman build empty context dir" { 1139 buildcontextdir=$PODMAN_TMPDIR/emptydir 1140 mkdir -p $buildcontextdir 1141 containerfile=$PODMAN_TMPDIR/Containerfile 1142 echo FROM scratch >$containerfile 1143 1144 run_podman build -t build_test -f $containerfile $buildcontextdir 1145 assert "$output" !~ "EOF" "output should not contain EOF error" 1146 1147 run_podman rmi -f build_test 1148 } 1149 1150 @test "podman build --file=https" { 1151 run_podman build -t build_test --file=https://raw.githubusercontent.com/containers/podman/main/test/build/from-scratch/Dockerfile $PODMAN_TMPDIR 1152 1153 run_podman rmi -f build_test 1154 } 1155 1156 function teardown() { 1157 # A timeout or other error in 'build' can leave behind stale images 1158 # that podman can't even see and which will cascade into subsequent 1159 # test failures. Try a last-ditch force-rm in cleanup, ignoring errors. 1160 run_podman '?' rm -t 0 -a -f 1161 run_podman '?' rmi -f build_test 1162 1163 # Many of the tests above leave interim layers behind. Clean them up. 1164 run_podman '?' image prune -f 1165 1166 basic_teardown 1167 } 1168 1169 # vim: filetype=sh