github.com/containers/podman/v5@v5.1.0-rc1/test/system/010-images.bats (about) 1 #!/usr/bin/env bats 2 3 load helpers 4 5 @test "podman images - basic output" { 6 headings="REPOSITORY *TAG *IMAGE ID *CREATED *SIZE" 7 8 run_podman images -a 9 is "${lines[0]}" "$headings" "header line" 10 is "${lines[1]}" "$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME *$PODMAN_TEST_IMAGE_TAG *[0-9a-f]\+" "podman images output" 11 12 # 'podman images' should emit headings even if there are no images 13 # (but --root only works locally) 14 if ! is_remote; then 15 run_podman --storage-driver=vfs --root ${PODMAN_TMPDIR}/nothing-here-move-along images 16 is "$output" "$headings" "'podman images' emits headings even w/o images" 17 fi 18 } 19 20 @test "podman images - custom formats" { 21 tests=" 22 {{.ID}} | [0-9a-f]\\\{12\\\}\\\$ 23 {{.ID| upper}} | [0-9A-F]\\\{12\\\}\\\$ 24 {{.Repository}}:{{.Tag}} | $PODMAN_TEST_IMAGE_FQN 25 {{.Labels.created_by}} | test/system/build-testimage 26 {{.Labels.created_at}} | 20[0-9-]\\\+T[0-9:]\\\+Z 27 " 28 29 defer-assertion-failures 30 31 while read fmt expect; do 32 run_podman images --format "$fmt" 33 is "$output" "$expect" "podman images --format '$fmt'" 34 done < <(parse_table "$tests") 35 36 run_podman images --format "{{.ID}}" --no-trunc 37 is "$output" "sha256:[0-9a-f]\\{64\\}\$" "podman images --no-trunc" 38 } 39 40 @test "podman images - json" { 41 # 'created': podman includes fractional seconds, podman-remote does not 42 tests=" 43 Names[0] | $PODMAN_TEST_IMAGE_FQN 44 Id | [0-9a-f]\\\{64\\\} 45 Digest | sha256:[0-9a-f]\\\{64\\\} 46 CreatedAt | [0-9-]\\\+T[0-9:.]\\\+Z 47 Size | [0-9]\\\+ 48 Labels.created_by | test/system/build-testimage 49 Labels.created_at | 20[0-9-]\\\+T[0-9:]\\\+Z 50 " 51 52 run_podman images -a --format json 53 54 while read field expect; do 55 actual=$(echo "$output" | jq -r ".[0].$field") 56 dprint "# actual=<$actual> expect=<$expect}>" 57 is "$actual" "$expect" "jq .$field" 58 done < <(parse_table "$tests") 59 } 60 61 @test "podman images - history output" { 62 # podman history is persistent: it permanently alters our base image. 63 # Create a dummy image here so we leave our setup as we found it. 64 # Multiple --name options confirm command-line override (last one wins) 65 run_podman run --name ignore-me --name my-container $IMAGE true 66 run_podman commit my-container my-test-image 67 68 run_podman images my-test-image --format '{{ .History }}' 69 is "$output" "localhost/my-test-image:latest" "image history with initial name" 70 71 # Generate two randomish tags; 'tr' because they must be all lower-case 72 rand_name1="test-image-history-$(random_string 10 | tr A-Z a-z)" 73 rand_name2="test-image-history-$(random_string 10 | tr A-Z a-z)" 74 75 # Tag once, rmi, and make sure the tag name appears in history 76 run_podman tag my-test-image $rand_name1 77 run_podman rmi $rand_name1 78 run_podman images my-test-image --format '{{ .History }}' 79 is "$output" "localhost/my-test-image:latest, localhost/${rand_name1}:latest" "image history after one tag" 80 81 # Repeat with second tag. Now both tags should be in history 82 run_podman tag my-test-image $rand_name2 83 run_podman rmi $rand_name2 84 run_podman images my-test-image --format '{{ .History }}' 85 is "$output" "localhost/my-test-image:latest, localhost/${rand_name2}:latest, localhost/${rand_name1}:latest" \ 86 "image history after two tags" 87 88 run_podman rmi my-test-image 89 run_podman rm my-container 90 } 91 92 @test "podman images - filter" { 93 # Multiple --format options confirm command-line override (last one wins) 94 run_podman inspect --format '{{.XYZ}}' --format '{{.ID}}' $IMAGE 95 iid=$output 96 97 run_podman images --noheading --filter=after=$iid 98 is "$output" "" "baseline: empty results from filter (after)" 99 100 run_podman images --noheading --filter=before=$iid 101 is "$output" "" "baseline: empty results from filter (before)" 102 103 # Create a dummy container, then commit that as an image. We will 104 # now be able to use before/after/since queries 105 run_podman run --name mytinycontainer $IMAGE true 106 run_podman commit -q mytinycontainer mynewimage 107 new_iid=$output 108 109 # (refactor common options for legibility) 110 opts='--noheading --no-trunc --format={{.ID}}--{{.Repository}}:{{.Tag}}' 111 112 run_podman images ${opts} --filter=after=$iid 113 is "$output" "sha256:$new_iid--localhost/mynewimage:latest" "filter: after" 114 115 # Same thing, with 'since' instead of 'after' 116 run_podman images ${opts} --filter=since=$iid 117 is "$output" "sha256:$new_iid--localhost/mynewimage:latest" "filter: since" 118 119 run_podman images ${opts} --filter=before=mynewimage 120 is "$output" "sha256:$iid--$IMAGE" "filter: before" 121 122 # Clean up 123 run_podman rmi mynewimage 124 run_podman rm mytinycontainer 125 } 126 127 # Regression test for https://github.com/containers/podman/issues/7651 128 # in which "podman pull image-with-sha" causes "images -a" to crash 129 @test "podman images -a, after pulling by sha " { 130 # This test requires that $IMAGE be 100% the same as the registry one 131 run_podman rmi -a -f 132 _prefetch $IMAGE 133 134 # Get a baseline for 'images -a' 135 run_podman images -a 136 local images_baseline="$output" 137 138 # Get the digest of our local test image. We need to do this in two steps 139 # because 'podman inspect' only works reliably on *IMAGE ID*, not name. 140 # See https://github.com/containers/podman/issues/3761 141 run_podman inspect --format '{{.Id}}' $IMAGE 142 local iid="$output" 143 run_podman inspect --format '{{.Digest}}' $iid 144 local sha="$output" 145 146 local imgbase="${PODMAN_TEST_IMAGE_REGISTRY}/${PODMAN_TEST_IMAGE_USER}/${PODMAN_TEST_IMAGE_NAME}" 147 local fqin="${imgbase}@$sha" 148 149 # This will always pull, because even though it's the same image we 150 # already have, podman doesn't actually know that. 151 run_podman pull $fqin 152 is "$output" "Trying to pull ${fqin}\.\.\..*" "output of podman pull" 153 154 # Prior to #7654, this would crash and burn. Now podman recognizes it 155 # as the same image and, even though it internally tags it with the 156 # sha, still only shows us one image (which should be our baseline) 157 # 158 # WARNING! If this test fails, we're going to see a lot of failures 159 # in subsequent tests due to 'podman ps' showing the '@sha' tag! 160 # I choose not to add a complicated teardown() (with 'rmi @sha') 161 # because the failure window here is small, and if it fails it 162 # needs attention anyway. So if you see lots of failures, but 163 # start here because this is the first one, fix this problem. 164 # You can (probably) ignore any subsequent failures showing '@sha' 165 # in the error output. 166 # 167 # WARNING! This test is likely to fail for an hour or so after 168 # building a new testimage (via build-testimage script), because 169 # two consecutive 'podman images' may result in a one-minute 170 # difference in the "XX minutes ago" output. This is OK to ignore. 171 run_podman images -a 172 is "$output" "$images_baseline" "images -a, after pull: same as before" 173 174 # Clean up: this should simply untag, not remove 175 run_podman rmi $fqin 176 is "$output" "Untagged: $fqin" "podman rmi untags, does not remove" 177 178 # ...and now we should still have our same image. 179 run_podman images -a 180 is "$output" "$images_baseline" "after podman rmi @sha, still the same" 181 } 182 183 # Tests #7199 (Restore "table" --format from V1) 184 # 185 # Tag our image with different-length strings; confirm table alignment 186 @test "podman images - table format" { 187 # Craft two tags such that they will bracket $IMAGE on either side (above 188 # and below). This assumes that $IMAGE is quay.io or foo.com or simply 189 # not something insane that will sort before 'aaa' or after 'zzz'. 190 local aaa_name=a.b/c 191 local aaa_tag=d 192 local zzz_name=zzzzzzzzzz.yyyyyyyyy/xxxxxxxxx 193 local zzz_tag=$(random_string 15) 194 195 # Helper function to check one line of tabular output; all this does is 196 # generate a line with the given repo/tag, formatted to the width of the 197 # widest image, which is the zzz one. Fields are separated by TWO spaces. 198 function _check_line() { 199 local lineno=$1 200 local name=$2 201 local tag=$3 202 203 is "${lines[$lineno]}" \ 204 "$(printf '%-*s %-*s %s' ${#zzz_name} ${name} ${#zzz_tag} ${tag} $iid)" \ 205 "podman images, $testname, line $lineno" 206 } 207 208 function _run_format_test() { 209 local testname=$1 210 local format=$2 211 212 run_podman images --sort repository --format "$format" 213 214 line_no=0 215 if [[ $format == table* ]]; then 216 # skip headers from table command 217 line_no=1 218 fi 219 220 _check_line $line_no ${aaa_name} ${aaa_tag} 221 _check_line $((line_no+1)) "${PODMAN_TEST_IMAGE_REGISTRY}/${PODMAN_TEST_IMAGE_USER}/${PODMAN_TEST_IMAGE_NAME}" "${PODMAN_TEST_IMAGE_TAG}" 222 _check_line $((line_no+2)) ${zzz_name} ${zzz_tag} 223 } 224 225 # Begin the test: tag $IMAGE with both the given names 226 run_podman tag $IMAGE ${aaa_name}:${aaa_tag} 227 run_podman tag $IMAGE ${zzz_name}:${zzz_tag} 228 229 # Get the image ID, used to verify output below (all images share same IID) 230 run_podman inspect --format '{{.ID}}' $IMAGE 231 iid=${output:0:12} 232 233 # Run the test: this will output three column-aligned rows. Test them. 234 _run_format_test 'table' 'table {{.Repository}} {{.Tag}} {{.ID}}' 235 236 # Clean up. 237 run_podman rmi ${aaa_name}:${aaa_tag} ${zzz_name}:${zzz_tag} 238 } 239 240 @test "podman images - rmi -af removes all containers and pods" { 241 pname=$(random_string) 242 run_podman create --pod new:$pname $IMAGE 243 244 run_podman inspect --format '{{.ID}}' $IMAGE 245 imageID=$output 246 247 pauseImage=$(pause_image) 248 run_podman inspect --format '{{.ID}}' $pauseImage 249 pauseID=$output 250 251 run_podman 2 rmi -a 252 is "$output" "Error: 2 errors occurred: 253 .** image used by .*: image is in use by a container: consider listing external containers and force-removing image 254 .** image used by .*: image is in use by a container: consider listing external containers and force-removing image" 255 256 run_podman rmi -af 257 is "$output" "Untagged: $IMAGE 258 Untagged: $pauseImage 259 Deleted: $imageID 260 Deleted: $pauseID" "infra images gets removed as well" 261 262 run_podman images --noheading 263 is "$output" "" 264 run_podman ps --all --noheading 265 is "$output" "" 266 run_podman pod ps --noheading 267 is "$output" "" 268 269 run_podman create --pod new:$pname $IMAGE 270 # Clean up 271 run_podman rm "${lines[-1]}" 272 run_podman pod rm -a 273 run_podman rmi $pauseImage 274 } 275 276 @test "podman images - rmi -f can remove infra images" { 277 pname=$(random_string) 278 run_podman create --pod new:$pname $IMAGE 279 280 pauseImage=$(pause_image) 281 run_podman inspect --format '{{.ID}}' $pauseImage 282 pauseID=$output 283 284 run_podman 2 rmi $pauseImage 285 is "$output" "Error: image used by .* image is in use by a container: consider listing external containers and force-removing image" 286 287 run_podman rmi -f $pauseImage 288 is "$output" "Untagged: $pauseImage 289 Deleted: $pauseID" 290 291 # Force-removing the infra container removes the pod and all its containers. 292 run_podman ps --all --noheading 293 is "$output" "" 294 run_podman pod ps --noheading 295 is "$output" "" 296 297 # Other images are still present. 298 run_podman image exists $IMAGE 299 } 300 301 @test "podman rmi --ignore" { 302 random_image_name=$(random_string) 303 random_image_name=${random_image_name,,} # name must be lowercase 304 run_podman 1 rmi $random_image_name 305 is "$output" "Error: $random_image_name: image not known.*" 306 run_podman rmi --ignore $random_image_name 307 is "$output" "" 308 } 309 310 @test "podman image rm --force bogus" { 311 run_podman 1 image rm bogus 312 is "$output" "Error: bogus: image not known" "Should print error" 313 run_podman image rm --force bogus 314 is "$output" "" "Should print no output" 315 316 random_image_name=$(random_string) 317 random_image_name=${random_image_name,,} # name must be lowercase 318 run_podman image tag $IMAGE $random_image_name 319 run_podman image rm --force bogus $random_image_name 320 assert "$output" = "Untagged: localhost/$random_image_name:latest" "removed image" 321 322 run_podman images 323 assert "$output" !~ "$random_image_name" "image must be removed" 324 } 325 326 @test "podman images - commit docker with comment" { 327 run_podman run --name my-container -d $IMAGE top 328 run_podman 125 commit -m comment my-container my-test-image 329 assert "$output" == "Error: messages are only compatible with the docker image format (-f docker)" "podman should fail unless docker format" 330 331 # Without -q: verbose output, but only on podman-local, not remote 332 run_podman commit my-container --format docker -m comment my-test-image1 333 if ! is_remote; then 334 assert "$output" =~ "Getting image.*Writing manif" \ 335 "Without -q, verbose output" 336 fi 337 338 # With -q, both local and remote: only an image ID 339 run_podman commit -q my-container --format docker -m comment my-test-image2 340 assert "$output" =~ "^[0-9a-f]{64}\$" \ 341 "With -q, output is a commit ID, no warnings or other output" 342 343 run_podman rmi my-test-image1 my-test-image2 344 run_podman rm my-container --force -t 0 345 } 346 347 @test "podman pull image with additional store" { 348 skip_if_remote "only works on local" 349 350 # overlay or vfs 351 local storagedriver="$(podman_storage_driver)" 352 353 local imstore=$PODMAN_TMPDIR/imagestore 354 local sconf=$PODMAN_TMPDIR/storage.conf 355 cat >$sconf <<EOF 356 [storage] 357 driver="$storagedriver" 358 359 [storage.options] 360 additionalimagestores = [ "$imstore/root" ] 361 EOF 362 363 skopeo copy containers-storage:$IMAGE \ 364 containers-storage:\[${storagedriver}@${imstore}/root+${imstore}/runroot\]$IMAGE 365 366 # IMPORTANT! Use -2/-1 indices, not 0/1, because $SYSTEMD_IMAGE may be 367 # present in store, and if it is it will precede $IMAGE. 368 CONTAINERS_STORAGE_CONF=$sconf run_podman images -a -n --format "{{.Repository}}:{{.Tag}} {{.ReadOnly}}" 369 assert "${#lines[*]}" -ge 2 "at least 2 lines from 'podman images'" 370 is "${lines[-2]}" "$IMAGE false" "image from readonly store" 371 is "${lines[-1]}" "$IMAGE true" "image from readwrite store" 372 373 CONTAINERS_STORAGE_CONF=$sconf run_podman images -a -n --format "{{.Id}}" 374 id=${lines[-1]} 375 376 CONTAINERS_STORAGE_CONF=$sconf run_podman pull -q $IMAGE 377 is "$output" "$id" "pull -q $IMAGE, using storage.conf" 378 379 run_podman --root $imstore/root rmi --all 380 } 381 382 @test "podman images with concurrent removal" { 383 skip_if_remote "following test is not supported for remote clients" 384 local count=5 385 386 # First build $count images 387 for i in $(seq --format '%02g' 1 $count); do 388 cat >$PODMAN_TMPDIR/Containerfile <<EOF 389 FROM $IMAGE 390 RUN echo $i 391 EOF 392 run_podman build -q -t i$i $PODMAN_TMPDIR 393 done 394 395 run_podman images 396 # Now remove all images in parallel and in the background and make sure 397 # that listing all images does not fail (see BZ 2216700). 398 for i in $(seq --format '%02g' 1 $count); do 399 timeout --foreground -v --kill=10 60 \ 400 $PODMAN rmi i$i & 401 done 402 403 tries=100 404 while [[ ${#lines[*]} -gt 1 ]] && [[ $tries -gt 0 ]]; do 405 # Prior to #18980, 'podman images' during rmi could fail with 'image not known' 406 # '0+w' because we sometimes get warnings. 407 run_podman 0+w images --format "{{.ID}} {{.Names}}" 408 allow_warnings "Top layer .* of image .* not found in layer tree" 409 tries=$((tries - 1)) 410 done 411 412 if [[ $tries -eq 0 ]]; then 413 die "Timed out waiting for images to be removed" 414 fi 415 416 wait 417 } 418 419 420 # vim: filetype=sh