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