github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/test/apiv2/20-containers.at (about)

     1  # -*- sh -*-
     2  #
     3  # test container-related endpoints
     4  #
     5  
     6  # WORKDIR=/data
     7  ENV_WORKDIR_IMG=quay.io/libpod/testimage:20200929
     8  MultiTagName=localhost/test/testformultitag:tag
     9  
    10  podman pull $IMAGE &>/dev/null
    11  podman tag $IMAGE $MultiTagName
    12  podman pull $ENV_WORKDIR_IMG &>/dev/null
    13  # Unimplemented
    14  #t POST libpod/containers/create '' 201 'sdf'
    15  
    16  # Ensure clean slate
    17  podman rm -a -f &>/dev/null
    18  
    19  t GET "libpod/containers/json (at start: clean slate)" 200 length=0
    20  
    21  # Regression test for #12904 (race condition in logging code)
    22  mytext="hi-there-$(random_string 15)"
    23  podman run --rm -d --replace --name foo $IMAGE sh -c "echo $mytext;sleep 42"
    24  # Logs output is prepended by ^A^X
    25  t POST "containers/foo/attach?logs=true&stream=false" 200 \
    26    $'\001\030'$mytext
    27  t POST "containers/foo/kill" 204
    28  
    29  podman run -v /tmp:/tmp $IMAGE true
    30  
    31  t GET libpod/containers/json 200 length=0
    32  
    33  # bad all input
    34  t GET libpod/containers/json?all='garb1age' 500 \
    35      .cause="schema: error converting value for \"all\""
    36  
    37  t GET libpod/containers/json?all=true 200 \
    38    length=1 \
    39    .[0].Id~[0-9a-f]\\{64\\} \
    40    .[0].Image=$IMAGE \
    41    .[0].Command[0]="true" \
    42    .[0].State~\\\(exited\\\|stopped\\\) \
    43    .[0].ExitCode=0 \
    44    .[0].Mounts~.*/tmp \
    45    .[0].IsInfra=false
    46  
    47  # Test compat API for Network Settings (.Network is N/A when rootless)
    48  network_expect=
    49  if root; then
    50      network_expect='.[0].NetworkSettings.Networks.podman.NetworkID=podman'
    51  fi
    52  t GET /containers/json?all=true 200 \
    53    length=1 \
    54    .[0].Id~[0-9a-f]\\{64\\} \
    55    .[0].Image=$IMAGE \
    56    .[0].Mounts~.*/tmp \
    57    $network_expect
    58  
    59  # compat API imageid with sha256: prefix
    60  t GET containers/json?limit=1 200 \
    61    .[0].ImageID~sha256:[0-9a-f]\\{64\\}
    62  
    63  # Make sure `limit` works.
    64  t GET libpod/containers/json?limit=1 200 \
    65    length=1 \
    66    .[0].Id~[0-9a-f]\\{64\\} \
    67    .[0].Image=$IMAGE \
    68    .[0].Command[0]="true" \
    69    .[0].State~\\\(exited\\\|stopped\\\) \
    70    .[0].ExitCode=0 \
    71    .[0].IsInfra=false
    72  
    73  # Make sure `last` works, which is an alias for `limit`.
    74  # See https://github.com/containers/podman/issues/6413.
    75  t GET libpod/containers/json?last=1 200 \
    76    length=1 \
    77    .[0].Id~[0-9a-f]\\{64\\} \
    78    .[0].Image=$IMAGE \
    79    .[0].Command[0]="true" \
    80    .[0].State~\\\(exited\\\|stopped\\\) \
    81    .[0].ExitCode=0 \
    82    .[0].IsInfra=false
    83  
    84  cid=$(jq -r '.[0].Id' <<<"$output")
    85  
    86  if root; then
    87      t GET libpod/containers/stats?containers='[$cid]' 200
    88  else
    89      if have_cgroupsv2; then
    90          t GET libpod/containers/stats?containers='[$cid]' 200
    91      else
    92          t GET libpod/containers/stats?containers='[$cid]' 409
    93      fi
    94  fi
    95  
    96  t DELETE libpod/containers/$cid 200 .[0].Id=$cid
    97  
    98  # Issue #6799: it should be possible to start a container, even w/o args.
    99  t POST libpod/containers/create?name=test_noargs Image=${IMAGE} 201 \
   100    .Id~[0-9a-f]\\{64\\}
   101  cid=$(jq -r '.Id' <<<"$output")
   102  # Prior to the fix in #6835, this would fail 500 "args must not be empty"
   103  t POST   libpod/containers/${cid}/start 204
   104  # Container should exit almost immediately. Wait for it, confirm successful run
   105  t POST   "libpod/containers/${cid}/wait?condition=stopped&condition=exited"  200 '0'
   106  t GET    libpod/containers/${cid}/json 200 \
   107    .Id=$cid \
   108    .State.Status~\\\(exited\\\|stopped\\\) \
   109    .State.Running=false \
   110    .State.ExitCode=0
   111  t DELETE libpod/containers/$cid 200 .[0].Id=$cid
   112  
   113  CNAME=myfoo
   114  podman run -d --name $CNAME $IMAGE top
   115  t GET libpod/containers/json?all=true 200 \
   116    .[0].Id~[0-9a-f]\\{64\\}
   117  cid=$(jq -r '.[0].Id' <<<"$output")
   118  
   119  # No such container
   120  t POST "libpod/commit?container=nonesuch" 404
   121  
   122  # Comment can only be used with docker format, not OCI
   123  cparam="repo=newrepo&comment=foo&author=bob"
   124  t POST "libpod/commit?container=$CNAME&$cparam"  500 \
   125    .cause="messages are only compatible with the docker image format (-f docker)"
   126  
   127  # Commit a new image from the container
   128  t POST "libpod/commit?container=$CNAME" 200 \
   129    .Id~[0-9a-f]\\{64\\}
   130  iid=$(jq -r '.Id' <<<"$output")
   131  t GET libpod/images/$iid/json 200 \
   132    .RepoTags[0]=null \
   133    .Author="" \
   134    .Comment=""
   135  
   136  # Commit a new image w/o tag
   137  cparam="repo=newrepo&comment=foo&author=bob&format=docker"
   138  t POST "libpod/commit?container=$CNAME&$cparam" 200
   139  t GET libpod/images/newrepo:latest/json 200 \
   140    .RepoTags[0]=localhost/newrepo:latest	\
   141    .Author=bob \
   142    .Comment=foo
   143  
   144  # Commit a new image w/ specified tag and author
   145  cparam="repo=newrepo&tag=v1&author=alice"
   146  t POST "libpod/commit?container=$cid&$cparam&pause=false" 200
   147  t GET libpod/images/newrepo:v1/json 200 \
   148    .RepoTags[0]=localhost/newrepo:v1     \
   149    .Author=alice
   150  
   151  # Commit a new image w/ full parameters
   152  cparam="repo=newrepo&tag=v2&comment=bar&author=eric"
   153  cparam="$cparam&format=docker&changes=CMD=/bin/foo"
   154  t POST "libpod/commit?container=${cid:0:12}&$cparam&pause=true" 200
   155  t GET libpod/images/newrepo:v2/json 200 \
   156    .RepoTags[0]=localhost/newrepo:v2	\
   157    .Author=eric \
   158    .Comment=bar \
   159    .Config.Cmd[-1]="/bin/foo"
   160  
   161  # Create a container for testing the container initializing later
   162  podman create -t -i --name myctr $IMAGE ls
   163  
   164  # Check configuration before initializing
   165  t GET libpod/containers/myctr/json 200 \
   166    .Id~[0-9a-f]\\{64\\} \
   167    .State.Status="created" \
   168    .State.Pid=0 \
   169    .ResolvConfPath="" \
   170    .HostnamePath="" \
   171    .HostsPath="" \
   172    .NetworkSettings.SandboxKey=""
   173  
   174  cpid_file=$(jq -r '.ConmonPidFile' <<<"$output")
   175  userdata_path=$(dirname $cpid_file)
   176  
   177  # Initializing the container
   178  t POST libpod/containers/myctr/init 204
   179  
   180  # Check configuration after initializing
   181  t GET libpod/containers/myctr/json 200 \
   182    .Id~[0-9a-f]\\{64\\} \
   183    .State.Status="initialized" \
   184    .State.Pid~[0-9]\\{1\,8\\} \
   185    .ResolvConfPath=$userdata_path/resolv.conf \
   186    .HostnamePath=$userdata_path/hostname \
   187    .HostsPath=$userdata_path/hosts \
   188    .NetworkSettings.SandboxKey~.*/netns/netns- \
   189    .OCIConfigPath~.*config\.json \
   190    .GraphDriver.Data.MergedDir~.*merged
   191  
   192  # Test TS are in UTC
   193  t GET containers/myctr/json 200 \
   194    .Created~.*Z \
   195    .State.StartedAt~.*Z \
   196    .State.FinishedAt~.*Z
   197  
   198  t DELETE images/localhost/newrepo:latest?force=true 200
   199  t DELETE images/localhost/newrepo:v1?force=true 200
   200  t DELETE images/localhost/newrepo:v2?force=true 200
   201  t DELETE libpod/containers/$cid?force=true 200 .[0].Id=$cid
   202  t DELETE libpod/containers/myctr 200
   203  t DELETE libpod/containers/bogus 404
   204  
   205  
   206  # test apiv2 create container with correct entrypoint and cmd
   207  # --data '{"Image":"quay.io/libpod/alpine_labels:latest","Entrypoint":["echo"],"Cmd":["param1","param2"]}'
   208  t POST containers/create \
   209    Image=$IMAGE \
   210    Entrypoint='["echo"]' \
   211    Cmd='["param1","param2"]' \
   212    201 \
   213    .Id~[0-9a-f]\\{64\\}
   214  cid=$(jq -r '.Id' <<<"$output")
   215  t GET containers/$cid/json 200 \
   216    .Config.Entrypoint[0]="echo" \
   217    .Config.Cmd[0]="param1" \
   218    .Config.Cmd[1]="param2" \
   219    .Path="echo" \
   220    .Args[0]="param1" \
   221    .Args[1]="param2"
   222  t DELETE containers/$cid 204
   223  
   224  # test only set the entrypoint, Cmd should be []
   225  t POST containers/create \
   226    Image=$IMAGE \
   227    Entrypoint='["echo","param1"]' \
   228    201 \
   229    .Id~[0-9a-f]\\{64\\}
   230  cid=$(jq -r '.Id' <<<"$output")
   231  t GET containers/$cid/json 200 \
   232    .Config.Entrypoint[0]="echo" \
   233    .Config.Entrypoint[1]="param1" \
   234    .Config.Cmd='[]' \
   235    .Path="echo" \
   236    .Args[0]="param1"
   237  
   238  # create a running container for after
   239  t POST containers/create Image=$IMAGE Entrypoint='["top"]' 201 \
   240    .Id~[0-9a-f]\\{64\\}
   241  cid_top=$(jq -r '.Id' <<<"$output")
   242  t GET containers/${cid_top}/json 200 \
   243    .Config.Entrypoint[0]="top" \
   244    .Config.Cmd='[]' \
   245    .Path="top" \
   246    .NetworkSettings.Networks.podman.NetworkID=podman
   247  t POST  containers/${cid_top}/start 204
   248  # make sure the container is running
   249  t GET containers/${cid_top}/json 200 \
   250    .State.Status="running"
   251  
   252  # 0 means unlimited, need same with docker
   253  t GET containers/json?limit=0 200 \
   254    .[0].Id~[0-9a-f]\\{64\\}
   255  
   256  t GET 'containers/json?limit=0&all=1' 200 \
   257    .[0].Id~[0-9a-f]\\{64\\} \
   258    .[1].Id~[0-9a-f]\\{64\\}
   259  
   260  t GET containers/json?limit=2 200 length=2
   261  
   262  # Filter with two ids should return both container
   263  t GET containers/json?filters='{"id":["'${cid}'","'${cid_top}'"]}&all=1' 200 length=2
   264  # Filter with two ids and status running should return only 1 container
   265  t GET containers/json?filters='{"id":["'${cid}'","'${cid_top}'"],"status":["running"]}&all=1' 200 \
   266    length=1 \
   267    .[0].Id=${cid_top}
   268  
   269  t POST containers/${cid_top}/stop 204
   270  
   271  t DELETE containers/$cid 204
   272  t DELETE containers/$cid_top 204
   273  
   274  # test the WORKDIR and StopSignal
   275  t POST containers/create \
   276    Image=$ENV_WORKDIR_IMG \
   277    WorkingDir=/dataDir \
   278    StopSignal=\"9\" \
   279    201 \
   280    .Id~[0-9a-f]\\{64\\}
   281  cid=$(jq -r '.Id' <<<"$output")
   282  t GET containers/$cid/json 200 \
   283    .Config.WorkingDir="/dataDir" \
   284    .Config.StopSignal="9"
   285  
   286  t DELETE containers/$cid 204
   287  
   288  # when the image had multi tags, the container's Image should be correct
   289  # Fixes https://github.com/containers/podman/issues/8547
   290  t POST containers/create Image=${MultiTagName} 201 \
   291    .Id~[0-9a-f]\\{64\\}
   292  cid=$(jq -r '.Id' <<<"$output")
   293  t GET containers/$cid/json 200 \
   294    .Image=${MultiTagName}
   295  t DELETE containers/$cid 204
   296  t DELETE images/${MultiTagName} 200
   297  # vim: filetype=sh
   298  
   299  # Test Volumes field adds an anonymous volume
   300  t POST containers/create Image=$IMAGE Volumes='{"/test":{}}' 201 \
   301    .Id~[0-9a-f]\\{64\\}
   302  cid=$(jq -r '.Id' <<<"$output")
   303  t GET containers/$cid/json 200 \
   304    .Mounts[0].Destination="/test"
   305  
   306  t DELETE containers/$cid?v=true 204
   307  
   308  # test port mapping
   309  podman run -d --rm --name bar -p 8080:9090 $IMAGE top
   310  
   311  t GET containers/json 200 \
   312    .[0].Ports[0].PrivatePort=9090 \
   313    .[0].Ports[0].PublicPort=8080 \
   314    .[0].Ports[0].Type="tcp"
   315  
   316  podman stop bar
   317  
   318  #compat api list containers sanity checks
   319  t GET containers/json?filters='garb1age}' 500 \
   320      .cause="invalid character 'g' looking for beginning of value"
   321  t GET containers/json?filters='{"label":["testl' 500 \
   322      .cause="unexpected end of JSON input"
   323  
   324  
   325  #libpod api list containers sanity checks
   326  t GET libpod/containers/json?filters='{"status":["removing"]}' 200 length=0
   327  t GET libpod/containers/json?filters='{"status":["bogus"]}' 500 \
   328      .cause="invalid argument"
   329  t GET libpod/containers/json?filters='garb1age}' 500 \
   330      .cause="invalid character 'g' looking for beginning of value"
   331  t GET libpod/containers/json?filters='{"label":["testl' 500 \
   332      .cause="unexpected end of JSON input"
   333  
   334  # Prune containers - bad filter input
   335  t POST containers/prune?filters='garb1age}' 500 \
   336      .cause="invalid character 'g' looking for beginning of value"
   337  t POST libpod/containers/prune?filters='garb1age}' 500 \
   338      .cause="invalid character 'g' looking for beginning of value"
   339  
   340  # Prune containers with illformed label
   341  t POST containers/prune?filters='{"label":["tes' 500 \
   342      .cause="unexpected end of JSON input"
   343  t POST libpod/containers/prune?filters='{"label":["tes' 500 \
   344      .cause="unexpected end of JSON input"
   345  
   346  t GET libpod/containers/json?filters='{"label":["testlabel"]}' 200 length=0
   347  
   348  # libpod api: do not use list filters for prune
   349  t POST libpod/containers/prune?filters='{"name":["anyname"]}' 500 \
   350      .cause="name is an invalid filter"
   351  t POST libpod/containers/prune?filters='{"id":["anyid"]}' 500 \
   352      .cause="id is an invalid filter"
   353  t POST libpod/containers/prune?filters='{"network":["anynetwork"]}' 500 \
   354      .cause="network is an invalid filter"
   355  
   356  # compat api: do not use list filters for prune
   357  t POST containers/prune?filters='{"name":["anyname"]}' 500 \
   358      .cause="name is an invalid filter"
   359  t POST containers/prune?filters='{"id":["anyid"]}' 500 \
   360      .cause="id is an invalid filter"
   361  t POST containers/prune?filters='{"network":["anynetwork"]}' 500 \
   362      .cause="network is an invalid filter"
   363  
   364  # Test CPU limit (NanoCPUs)
   365  t POST containers/create Image=$IMAGE HostConfig='{"NanoCpus":500000}' 201 \
   366    .Id~[0-9a-f]\\{64\\}
   367  cid=$(jq -r '.Id' <<<"$output")
   368  t GET containers/$cid/json 200 \
   369    .HostConfig.NanoCpus=500000
   370  
   371  t DELETE containers/$cid?v=true 204
   372  
   373  # Test Compat Create with default network mode (#10569)
   374  t POST containers/create Image=$IMAGE HostConfig='{"NetworkMode":"default"}' 201 \
   375    .Id~[0-9a-f]\\{64\\}
   376  cid=$(jq -r '.Id' <<<"$output")
   377  t GET containers/$cid/json 200 \
   378    .HostConfig.NetworkMode="bridge"
   379  
   380  t DELETE containers/$cid?v=true 204
   381  
   382  # Test Compat Create with healthcheck, check default values
   383  t POST containers/create Image=$IMAGE Cmd='["top"]' Healthcheck='{"Test":["true"]}' 201 \
   384    .Id~[0-9a-f]\\{64\\}
   385  cid=$(jq -r '.Id' <<<"$output")
   386  t GET containers/$cid/json 200 \
   387    .Config.Healthcheck.Interval=30000000000 \
   388    .Config.Healthcheck.Timeout=30000000000 \
   389    .Config.Healthcheck.Retries=3
   390  
   391  # compat api: Test for mount options support
   392  # Sigh, JSON can't handle octal. 0755(octal) = 493(decimal)
   393  payload='{"Mounts":[{"Type":"tmpfs","Target":"/mnt/scratch","TmpfsOptions":{"SizeBytes":1024,"Mode":493}}]}'
   394  t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\}
   395  cid=$(jq -r '.Id' <<<"$output")
   396  t GET containers/$cid/json 200 \
   397      .HostConfig.Tmpfs['"/mnt/scratch"']~.*size=1024.* \
   398      .HostConfig.Tmpfs['"/mnt/scratch"']~.*mode=755.*
   399  
   400  t DELETE containers/$cid?v=true 204
   401  
   402  # compat api: tmpfs without mount options
   403  payload='{"Mounts":[{"Type":"tmpfs","Target":"/mnt/scratch"}]}'
   404  t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\}
   405  cid=$(jq -r '.Id' <<<"$output")
   406  t GET containers/$cid/json 200 \
   407      .HostConfig.Tmpfs['"/mnt/scratch"']~.*tmpcopyup.* \
   408  
   409  t DELETE containers/$cid?v=true 204
   410  
   411  # compat api: bind mount without mount options
   412  payload='{"Mounts":[{"Type":"bind","Source":"/tmp","Target":"/mnt"}]}'
   413  t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\}
   414  cid=$(jq -r '.Id' <<<"$output")
   415  t GET containers/$cid/json 200 \
   416      .HostConfig.Binds[0]~/tmp:/mnt:.* \
   417  
   418  t DELETE containers/$cid?v=true 204
   419  
   420  # test apiv2 create/commit
   421  t POST containers/create \
   422    Image=$IMAGE \
   423    Entrypoint='["echo"]' \
   424    Cmd='["param1","param2"]' \
   425    201 \
   426    .Id~[0-9a-f]\\{64\\}
   427  cid=$(jq -r '.Id' <<<"$output")
   428  
   429  # No such container
   430  t POST "commit?container=nonesuch" 404
   431  
   432  cparam="repo=newrepo&tag=v3&comment=abcd&author=eric"
   433  cparam="$cparam&format=docker&changes=CMD%20/bin/bar%0aEXPOSE%209090"
   434  t POST "commit?container=${cid:0:12}&$cparam" 201 \
   435    .Id~[0-9a-f]\\{64\\}
   436  iid=$(jq -r '.Id' <<<"$output")
   437  t GET images/$iid/json 200 \
   438    .RepoTags[0]=docker.io/library/newrepo:v3 \
   439    .Config.ExposedPorts~.*"9090/tcp" \
   440    .Config.Cmd~.*"/bin/bar" \
   441    .Comment="abcd"
   442  
   443  t DELETE containers/$cid 204
   444  t DELETE images/docker.io/library/newrepo:v3?force=false 200
   445  
   446  # test create without default no_hosts
   447  t POST containers/create \
   448    Image=$IMAGE \
   449    201 \
   450    .Id~[0-9a-f]\\{64\\}
   451  cid=$(jq -r '.Id' <<<"$output")
   452  
   453  t POST libpod/containers/$cid/init 204
   454  
   455  t GET libpod/containers/$cid/json 200
   456  
   457  cpid_file=$(jq -r '.ConmonPidFile' <<<"$output")
   458  userdata_path=$(dirname $cpid_file)
   459  
   460  t GET libpod/containers/$cid/json 200 \
   461    .HostsPath=$userdata_path/hosts
   462  
   463  t DELETE containers/$cid 204
   464  
   465  # test create with default no_hosts=true
   466  stop_service
   467  
   468  CONTAINERS_CONF=$TESTS_DIR/containers.no_hosts.conf start_service
   469  
   470  # check docker and libpod endpoint
   471  for endpoint in containers/create libpod/containers/create; do
   472    t POST $endpoint \
   473      Image=$IMAGE \
   474      201 \
   475      .Id~[0-9a-f]\\{64\\}
   476    cid=$(jq -r '.Id' <<<"$output")
   477  
   478    t POST libpod/containers/$cid/init 204
   479  
   480    t GET libpod/containers/$cid/json 200
   481  
   482    t DELETE containers/$cid 204
   483  done
   484  
   485  stop_service
   486  start_service