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