5
@test "podman images - basic output" {
6
headings="REPOSITORY *TAG *IMAGE ID *CREATED *SIZE"
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"
12
# 'podman images' should emit headings even if there are no images
13
# (but --root only works locally)
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"
20
@test "podman images - custom formats" {
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
29
defer-assertion-failures
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")
36
run_podman images --format "{{.ID}}" --no-trunc
37
is "$output" "sha256:[0-9a-f]\\{64\\}\$" "podman images --no-trunc"
40
@test "podman images - json" {
41
# 'created': podman includes fractional seconds, podman-remote does not
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
48
Labels.created_by | test/system/build-testimage
49
Labels.created_at | 20[0-9-]\\\+T[0-9:]\\\+Z
52
run_podman images -a --format json
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")
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
68
run_podman images my-test-image --format '{{ .History }}'
69
is "$output" "localhost/my-test-image:latest" "image history with initial name"
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)"
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"
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"
88
run_podman rmi my-test-image
89
run_podman rm my-container
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
97
run_podman images --noheading --filter=after=$iid
98
is "$output" "" "baseline: empty results from filter (after)"
100
run_podman images --noheading --filter=before=$iid
101
is "$output" "" "baseline: empty results from filter (before)"
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
109
# (refactor common options for legibility)
110
opts='--noheading --no-trunc --format={{.ID}}--{{.Repository}}:{{.Tag}}'
112
run_podman images ${opts} --filter=after=$iid
113
is "$output" "sha256:$new_iid--localhost/mynewimage:latest" "filter: after"
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"
119
run_podman images ${opts} --filter=before=mynewimage
120
is "$output" "sha256:$iid--$IMAGE" "filter: before"
123
run_podman rmi mynewimage
124
run_podman rm mytinycontainer
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
134
# Get a baseline for 'images -a'
136
local images_baseline="$output"
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
143
run_podman inspect --format '{{.Digest}}' $iid
146
local imgbase="${PODMAN_TEST_IMAGE_REGISTRY}/${PODMAN_TEST_IMAGE_USER}/${PODMAN_TEST_IMAGE_NAME}"
147
local fqin="${imgbase}@$sha"
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"
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)
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.
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.
172
is "$output" "$images_baseline" "images -a, after pull: same as before"
174
# Clean up: this should simply untag, not remove
176
is "$output" "Untagged: $fqin" "podman rmi untags, does not remove"
178
# ...and now we should still have our same image.
180
is "$output" "$images_baseline" "after podman rmi @sha, still the same"
183
# Tests #7199 (Restore "table" --format from V1)
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'.
192
local zzz_name=zzzzzzzzzz.yyyyyyyyy/xxxxxxxxx
193
local zzz_tag=$(random_string 15)
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() {
203
is "${lines[$lineno]}" \
204
"$(printf '%-*s %-*s %s' ${#zzz_name} ${name} ${#zzz_tag} ${tag} $iid)" \
205
"podman images, $testname, line $lineno"
208
function _run_format_test() {
212
run_podman images --sort repository --format "$format"
215
if [[ $format == table* ]]; then
216
# skip headers from table command
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}
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}
229
# Get the image ID, used to verify output below (all images share same IID)
230
run_podman inspect --format '{{.ID}}' $IMAGE
233
# Run the test: this will output three column-aligned rows. Test them.
234
_run_format_test 'table' 'table {{.Repository}} {{.Tag}} {{.ID}}'
237
run_podman rmi ${aaa_name}:${aaa_tag} ${zzz_name}:${zzz_tag}
240
@test "podman images - rmi -af removes all containers and pods" {
241
pname=$(random_string)
242
run_podman create --pod new:$pname $IMAGE
244
run_podman inspect --format '{{.ID}}' $IMAGE
247
pauseImage=$(pause_image)
248
run_podman inspect --format '{{.ID}}' $pauseImage
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"
257
is "$output" "Untagged: $IMAGE
260
Deleted: $pauseID" "infra images gets removed as well"
262
run_podman images --noheading
264
run_podman ps --all --noheading
266
run_podman pod ps --noheading
269
run_podman create --pod new:$pname $IMAGE
271
run_podman rm "${lines[-1]}"
273
run_podman rmi $pauseImage
276
@test "podman images - rmi -f can remove infra images" {
277
pname=$(random_string)
278
run_podman create --pod new:$pname $IMAGE
280
pauseImage=$(pause_image)
281
run_podman inspect --format '{{.ID}}' $pauseImage
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"
287
run_podman rmi -f $pauseImage
288
is "$output" "Untagged: $pauseImage
291
# Force-removing the infra container removes the pod and all its containers.
292
run_podman ps --all --noheading
294
run_podman pod ps --noheading
297
# Other images are still present.
298
run_podman image exists $IMAGE
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
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"
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"
323
assert "$output" !~ "$random_image_name" "image must be removed"
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"
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
334
assert "$output" =~ "Getting image.*Writing manif" \
335
"Without -q, verbose output"
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"
343
run_podman rmi my-test-image1 my-test-image2
344
run_podman rm my-container --force -t 0
347
@test "podman pull image with additional store" {
348
skip_if_remote "only works on local"
351
local storagedriver="$(podman_storage_driver)"
353
local imstore=$PODMAN_TMPDIR/imagestore
354
local sconf=$PODMAN_TMPDIR/storage.conf
357
driver="$storagedriver"
360
additionalimagestores = [ "$imstore/root" ]
363
skopeo copy containers-storage:$IMAGE \
364
containers-storage:\[${storagedriver}@${imstore}/root+${imstore}/runroot\]$IMAGE
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"
373
CONTAINERS_STORAGE_CONF=$sconf run_podman images -a -n --format "{{.Id}}"
376
CONTAINERS_STORAGE_CONF=$sconf run_podman pull -q $IMAGE
377
is "$output" "$id" "pull -q $IMAGE, using storage.conf"
379
run_podman --root $imstore/root rmi --all
382
@test "podman images with concurrent removal" {
383
skip_if_remote "following test is not supported for remote clients"
386
# First build $count images
387
for i in $(seq --format '%02g' 1 $count); do
388
cat >$PODMAN_TMPDIR/Containerfile <<EOF
392
run_podman build -q -t i$i $PODMAN_TMPDIR
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 \
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"
412
if [[ $tries -eq 0 ]]; then
413
die "Timed out waiting for images to be removed"