github.com/containers/podman/v5@v5.1.0-rc1/test/apiv2/10-images.at (about)

     1  # -*- sh -*-
     2  #
     3  # Tests for image-related endpoints
     4  #
     5  
     6  # FIXME: API doesn't support pull yet, so use podman
     7  podman pull -q $IMAGE
     8  
     9  t GET libpod/images/json 200 \
    10    .[0].Id~[0-9a-f]\\{64\\}
    11  iid=$(jq -r '.[0].Id' <<<"$output")
    12  
    13  # Create an empty manifest and make sure it is not listed
    14  # in the compat endpoint.
    15  t GET images/json 200 length=1
    16  podman manifest create foo
    17  t GET images/json 200 length=1
    18  t GET libpod/images/json 200 length=2
    19  
    20  t GET libpod/images/$iid/exists                     204
    21  t GET libpod/images/$PODMAN_TEST_IMAGE_NAME/exists  204
    22  t GET libpod/images/${iid}abcdef/exists  404 \
    23    .cause="failed to find image ${iid}abcdef"
    24  
    25  # FIXME: compare to actual podman info
    26  t GET libpod/images/json 200  \
    27    .[0].Id=${iid}
    28  
    29  t GET libpod/images/$iid/json 200 \
    30    .Id=$iid \
    31    .RepoTags[0]=$IMAGE
    32  
    33  # Same thing, but with abbreviated image id
    34  t GET libpod/images/${iid:0:12}/json 200 \
    35    .Id=$iid \
    36    .RepoTags[0]=$IMAGE
    37  
    38  # Docker API V1.24 filter parameter compatibility
    39  t GET images/json?filter=$IMAGE 200 \
    40    length=1 \
    41    .[0].Names[0]=$IMAGE
    42  
    43  # Negative test case
    44  t GET images/json?filter=nonesuch 200 length=0
    45  
    46  # FIXME: docker API incompatibility: libpod returns 'id', docker 'sha256:id'
    47  t GET images/$iid/json 200 \
    48    .Id=sha256:$iid \
    49    .RepoTags[0]=$IMAGE
    50  
    51  t POST "images/create?fromImage=alpine" 200 .error~null .status~".*Download complete.*"
    52  t POST "libpod/images/pull?reference=alpine&compatMode=true" 200 .error~null .status~".*Download complete.*"
    53  
    54  t POST "images/create?fromImage=alpine&tag=latest" 200
    55  
    56  # 10977 - handle platform parameter correctly
    57  t POST "images/create?fromImage=quay.io/libpod/testimage:20240123&platform=linux/arm64" 200
    58  t GET  "images/testimage:20240123/json" 200 \
    59    .Architecture=arm64
    60  
    61  # Make sure that new images are pulled
    62  old_iid=$(podman image inspect --format "{{.ID}}" docker.io/library/alpine:latest)
    63  podman rmi -f docker.io/library/alpine:latest
    64  podman tag $IMAGE docker.io/library/alpine:latest
    65  t POST "images/create?fromImage=alpine" 200 .error~null .status~".*$old_iid.*"
    66  podman untag docker.io/library/alpine:latest
    67  
    68  t POST "images/create?fromImage=quay.io/libpod/alpine&tag=sha256:fa93b01658e3a5a1686dc3ae55f170d8de487006fb53a28efcd12ab0710a2e5f" 200
    69  
    70  # create image from source with tag
    71  # Note the "-" is used to use an empty body and not "{}" which is the default.
    72  t POST "images/create?fromSrc=-&repo=myimage&tag=mytag" - 200
    73  t GET "images/myimage:mytag/json" 200 \
    74    .Id~'^sha256:[0-9a-f]\{64\}$' \
    75    .RepoTags[0]="docker.io/library/myimage:mytag"
    76  t POST /images/create?fromImage=busybox:invalidtag123 404
    77  
    78  # Display the image history
    79  t GET libpod/images/nonesuch/history 404
    80  
    81  for i in $iid ${iid:0:12} $PODMAN_TEST_IMAGE_NAME; do
    82    t GET libpod/images/$i/history 200 \
    83      .[0].Id=$iid \
    84      .[0].Created~[0-9]\\{10\\} \
    85      .[0].Tags[0]="$IMAGE" \
    86      .[0].Size=0 \
    87      .[0].Comment=
    88  done
    89  
    90  for i in $iid ${iid:0:12} $PODMAN_TEST_IMAGE_NAME; do
    91    t GET images/$i/history 200 \
    92      .[0].Id="sha256:"$iid \
    93      .[0].Created~[0-9]\\{10\\} \
    94      .[0].Tags[0]="$IMAGE" \
    95      .[0].Size=0 \
    96      .[0].Comment=
    97  done
    98  
    99  # compat api pull image unauthorized message error
   100  t POST "/images/create?fromImage=quay.io/idonotexist/idonotexist:dummy" 401 \
   101    .message="unauthorized: access to the requested resource is not authorized"
   102  
   103  # Export an image on the local
   104  t GET libpod/images/nonesuch/get 404
   105  t GET libpod/images/$iid/get?format=foo 500
   106  t GET libpod/images/$PODMAN_TEST_IMAGE_NAME/get?compress=bar 400
   107  
   108  for i in $iid ${iid:0:12} $PODMAN_TEST_IMAGE_NAME; do
   109    t GET "libpod/images/$i/get"                200 '[POSIX tar archive]'
   110    t GET "libpod/images/$i/get?compress=true"  200 '[POSIX tar archive]'
   111    t GET "libpod/images/$i/get?compress=false" 200 '[POSIX tar archive]'
   112  done
   113  
   114  #compat api list images sanity checks
   115  t GET images/json?filters='garb1age}' 500 \
   116      .cause="invalid character 'g' looking for beginning of value"
   117  t GET images/json?filters='{"label":["testl' 500 \
   118      .cause="unexpected end of JSON input"
   119  
   120  #libpod api list images sanity checks
   121  t GET libpod/images/json?filters='garb1age}' 500 \
   122      .cause="invalid character 'g' looking for beginning of value"
   123  t GET libpod/images/json?filters='{"label":["testl' 500 \
   124      .cause="unexpected end of JSON input"
   125  
   126  # Prune images - bad all input
   127  t POST libpod/images/prune?all='garb1age' 500 \
   128      .cause="schema: error converting value for \"all\""
   129  
   130  # Prune images - bad filter input
   131  t POST images/prune?filters='garb1age}' 500 \
   132      .cause="invalid character 'g' looking for beginning of value"
   133  t POST libpod/images/prune?filters='garb1age}' 500 \
   134      .cause="invalid character 'g' looking for beginning of value"
   135  
   136  ## Prune images with illformed label
   137  t POST images/prune?filters='{"label":["tes' 500 \
   138      .cause="unexpected end of JSON input"
   139  t POST libpod/images/prune?filters='{"label":["tes' 500 \
   140      .cause="unexpected end of JSON input"
   141  
   142  
   143  #create, list and remove dangling image
   144  podman image build -t test:test -<<EOF
   145  from alpine
   146  RUN >file1
   147  EOF
   148  
   149  podman image build -t test:test --label xyz --label abc -<<EOF
   150  from alpine
   151  RUN >file2
   152  EOF
   153  
   154  t GET images/json?filters='{"dangling":["true"]}' 200 length=1
   155  t POST images/prune?filters='{"dangling":["true"]}' 200
   156  t GET images/json?filters='{"dangling":["true"]}' 200 length=0
   157  
   158  #label filter check in libpod and compat
   159  t GET images/json?filters='{"label":["xyz","abc"]}' 200 length=1
   160  t GET libpod/images/json?filters='{"label":["xyz"]}' 200 length=1
   161  
   162  t DELETE libpod/images/test:test 200
   163  
   164  t GET images/json?filters='{"label":["xyz"]}' 200 length=0
   165  t GET libpod/images/json?filters='{"label":["xyz"]}' 200 length=0
   166  
   167  # Must not error out: #20469
   168  t POST images/prune?filters='{"dangling":["false"]}' 200
   169  
   170  # to be used in prune until filter tests
   171  podman image build -t test1:latest -<<EOF
   172  from alpine
   173  RUN >file3
   174  EOF
   175  
   176  # image should not be deleted
   177  t GET images/json?filters='{"reference":["test1"]}' 200 length=1
   178  t POST images/prune?filters='{"until":["500000"]}' 200
   179  t GET images/json?filters='{"reference":["test1"]}' 200 length=1
   180  
   181  t DELETE libpod/images/test1:latest 200
   182  
   183  # to be used in prune until filter tests
   184  podman image build -t docker.io/library/test1:latest -<<EOF
   185  from alpine
   186  RUN >file4
   187  EOF
   188  podman create --name test1 test1 echo hi
   189  
   190  t DELETE images/test1:latest 409
   191  podman rm test1
   192  t DELETE images/test1:latest 200
   193  
   194  t GET "images/get?names=alpine" 200 '[POSIX tar archive]'
   195  
   196  podman pull busybox
   197  t GET "images/get?names=alpine&names=busybox" 200 '[POSIX tar archive]'
   198  img_cnt=$(tar xf "$WORKDIR/curl.result.out" manifest.json -O | jq "length")
   199  is "$img_cnt" 2 "number of images in tar archive"
   200  
   201  # check build works when uploading container file as a tar, see issue #10660
   202  TMPD=$(mktemp -d podman-apiv2-test.build.XXXXXXXX)
   203  function cleanBuildTest() {
   204      podman rmi -a -f
   205      rm -rf "${TMPD}" &> /dev/null
   206  }
   207  CONTAINERFILE_TAR="${TMPD}/containerfile.tar"
   208  cat > $TMPD/containerfile << EOF
   209  FROM $IMAGE
   210  EOF
   211  tar --format=posix -C $TMPD -cvf ${CONTAINERFILE_TAR} containerfile &> /dev/null
   212  
   213  t POST "libpod/build?dockerfile=containerfile" $CONTAINERFILE_TAR 200 \
   214    .stream~"STEP 1/1: FROM $IMAGE"
   215  
   216  # Newer Docker client sets empty cacheFrom for every build command even if it is not used,
   217  # following commit makes sure we test such use-case. See https://github.com/containers/podman/pull/16380
   218  #TODO: This test should be extended when buildah's cache-from and cache-to functionally supports
   219  # multiple remote-repos
   220  t POST "libpod/build?dockerfile=containerfile&cachefrom=[]" $CONTAINERFILE_TAR 200 \
   221    .stream~"STEP 1/1: FROM $IMAGE"
   222  
   223  # With -q, all we should get is image ID. Test both libpod & compat endpoints.
   224  t POST "libpod/build?dockerfile=containerfile&q=true" $CONTAINERFILE_TAR 200 \
   225    .stream~'^[0-9a-f]\{64\}$'
   226  t POST "build?dockerfile=containerfile&q=true" $CONTAINERFILE_TAR 200 \
   227    .stream~'^[0-9a-f]\{64\}$'
   228  
   229  # Override content-type and confirm that libpod rejects, but compat accepts
   230  t POST "libpod/build?dockerfile=containerfile" $CONTAINERFILE_TAR application/json 400 \
   231    .cause='Content-Type: application/json is not supported. Should be "application/x-tar"'
   232  t POST "build?dockerfile=containerfile" $CONTAINERFILE_TAR application/json 200 \
   233    .stream~"STEP 1/1: FROM $IMAGE"
   234  
   235  # Libpod: allow building from url: https://github.com/alpinelinux/docker-alpine.git and must ignore any provided tar
   236  t POST "libpod/build?remote=https%3A%2F%2Fgithub.com%2Falpinelinux%2Fdocker-alpine.git" $CONTAINERFILE_TAR 200 \
   237    .stream~"STEP 1/5: FROM alpine:"
   238  
   239  # Build api response header must contain Content-type: application/json
   240  t POST "build?dockerfile=containerfile" $CONTAINERFILE_TAR application/json 200
   241  response_headers=$(cat "$WORKDIR/curl.headers.out")
   242  like "$response_headers" ".*application/json.*" "header does not contain application/json"
   243  
   244  # Build api response header must contain Content-type: application/json
   245  t POST "build?dockerfile=containerfile&pull=1" $CONTAINERFILE_TAR application/json 200
   246  response_headers=$(cat "$WORKDIR/curl.headers.out")
   247  like "$response_headers" ".*application/json.*" "header does not contain application/json"
   248  
   249  # PR #12091: output from compat API must now include {"aux":{"ID":"sha..."}}
   250  t POST "build?dockerfile=containerfile" $CONTAINERFILE_TAR 200 \
   251    '.aux|select(has("ID")).ID~^sha256:[0-9a-f]\{64\}$'
   252  
   253  t POST libpod/images/prune 200
   254  t POST libpod/images/prune 200 length=0 []
   255  
   256  # compat api must allow loading tar which contain multiple images
   257  podman pull quay.io/libpod/alpine:latest quay.io/libpod/busybox:latest
   258  podman save -o ${TMPD}/test.tar quay.io/libpod/alpine:latest quay.io/libpod/busybox:latest
   259  t POST "images/load" ${TMPD}/test.tar 200 \
   260    .stream="Loaded image: quay.io/libpod/busybox:latest,quay.io/libpod/alpine:latest"
   261  t GET libpod/images/quay.io/libpod/alpine:latest/exists  204
   262  t GET libpod/images/quay.io/libpod/busybox:latest/exists  204
   263  
   264  CONTAINERFILE_WITH_ERR_TAR="${TMPD}/containerfile.tar"
   265  cat > $TMPD/containerfile << EOF
   266  FROM $IMAGE
   267  RUN echo 'some error' >&2
   268  EOF
   269  tar --format=posix -C $TMPD -cvf ${CONTAINERFILE_WITH_ERR_TAR} containerfile &> /dev/null
   270  t POST "/build?q=1&dockerfile=containerfile" $CONTAINERFILE_WITH_ERR_TAR 200
   271  if [[ $output == *"some error"* ]];then
   272      _show_ok 0 "compat quiet build" "[should not contain 'some error']" "$output"
   273  else
   274      _show_ok 1 "compat quiet build"
   275  fi
   276  
   277  cleanBuildTest
   278  
   279  # compat API vs libpod API event differences:
   280  # on image removal, libpod produces 'remove' events.
   281  # compat produces 'delete' events.
   282  podman image build -t test:test -<<EOF
   283  from $IMAGE
   284  EOF
   285  
   286  START=$(date +%s)
   287  
   288  t DELETE libpod/images/test:test 200
   289  # HACK HACK HACK There is a race around events being added to the journal
   290  # This sleep seems to avoid the race.
   291  # If it fails and begins to flake, investigate a retry loop.
   292  sleep 1
   293  t GET "libpod/events?stream=false&since=$START"  200  \
   294    'select(.status | contains("remove")).Action=remove'
   295  t GET "events?stream=false&since=$START"  200  \
   296    'select(.status | contains("delete")).Action=delete'
   297  
   298  # Test image removal with `noprune={true,false}`
   299  podman create --name c_test1 $IMAGE true
   300  podman commit -q c_test1 i_test1
   301  podman create --name c_test2 i_test1 true
   302  podman commit -q c_test2 i_test2
   303  podman create --name c_test3 i_test2 true
   304  podman commit -q c_test3 i_test3
   305  
   306  t GET libpod/images/i_test1/json 200
   307  iid_test1=$(jq -r '.Id' <<<"$output")
   308  t GET libpod/images/i_test2/json 200
   309  iid_test2=$(jq -r '.Id' <<<"$output")
   310  t GET libpod/images/i_test3/json 200
   311  iid_test3=$(jq -r '.Id' <<<"$output")
   312  
   313  podman untag $iid_test1
   314  podman untag $iid_test2
   315  
   316  podman rm -af
   317  
   318  # Deleting i_test3 with --no-prune must not remove _2 and _1.
   319  t DELETE images/$iid_test3?noprune=true  200
   320  t GET libpod/images/i_test3/exists    404
   321  t GET libpod/images/$iid_test1/exists 204
   322  t GET libpod/images/$iid_test2/exists 204
   323  
   324  t DELETE images/$iid_test2?noprune=false 200
   325  t GET libpod/images/$iid_test1/exists 404
   326  t GET libpod/images/$iid_test2/exists 404
   327  
   328  # If the /resolve tests fail, make sure to use ../registries.conf for the
   329  # podman-service.
   330  
   331  # With an alias, we only get one item back.
   332  t GET libpod/images/podman-desktop-test123:this/resolve 200 \
   333    .Names[0]="florent.fr/will/like:this"
   334  
   335  # If no alias matches, we will get a candidate for each unqualified-search
   336  # registry.
   337  t GET libpod/images/no-alias-for-sure/resolve 200 \
   338    .Names[0]="docker.io/library/no-alias-for-sure:latest" \
   339    .Names[1]="quay.io/no-alias-for-sure:latest" \
   340    .Names[2]="registry.fedoraproject.org/no-alias-for-sure:latest"
   341  
   342  # Test invalid input.
   343  t GET libpod/images/noCAPITALcharAllowed/resolve 400 \
   344    .cause="repository name must be lowercase"
   345  
   346  
   347  START=$(date +%s.%N)
   348  # test pull-error API response
   349  podman pull --retry 0 localhost:5000/idonotexist || true
   350  t GET "libpod/events?stream=false&since=$START"  200  \
   351    .status=pull-error \
   352    .Action=pull-error \
   353    .Actor.Attributes.name="localhost:5000/idonotexist" \
   354    .Actor.Attributes.error~".*connection refused"
   355  
   356  # vim: filetype=sh