github.com/containers/podman/v5@v5.1.0-rc1/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:20240123 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 \ 20 "[]" \ 21 length=0 22 # check content type: https://github.com/containers/podman/issues/14647 23 response_headers=$(cat "$WORKDIR/curl.headers.out") 24 like "$response_headers" ".*Content-Type: application/json.*" "header does not contain application/json" 25 26 # Regression test for #12904 (race condition in logging code) 27 mytext="hi-there-$(random_string 15)" 28 podman run --rm -d --replace --name foo $IMAGE sh -c "echo $mytext;sleep 42" 29 # Logs output is prepended by ^A^Y (stdout = 1, length = 25 (with newline)) 30 # Looks like it is missing the required 0 bytes from the message, why? 31 t POST "containers/foo/attach?logs=true&stream=false" 200 \ 32 $'\001\031'$mytext 33 34 # check old docker header 35 response_headers=$(cat "$WORKDIR/curl.headers.out") 36 like "$response_headers" ".*Content-Type: application/vnd\.docker\.raw-stream.*" "vnd.docker.raw-stream docker v1.40" 37 # check new vnd.docker.multiplexed-stream header 38 t POST "/v1.42/containers/foo/attach?logs=true&stream=false" 200 39 response_headers=$(cat "$WORKDIR/curl.headers.out") 40 like "$response_headers" ".*Content-Type: application/vnd\.docker\.multiplexed-stream.*" "vnd.docker.multiplexed-stream docker v1.42" 41 t POST "/v4.6.0/libpod/containers/foo/attach?logs=true&stream=false" 200 42 response_headers=$(cat "$WORKDIR/curl.headers.out") 43 like "$response_headers" ".*Content-Type: application/vnd\.docker\.raw-stream.*" "vnd.docker.raw-stream libpod v4.6.0" 44 t POST "/v4.7.0/libpod/containers/foo/attach?logs=true&stream=false" 200 45 response_headers=$(cat "$WORKDIR/curl.headers.out") 46 like "$response_headers" ".*Content-Type: application/vnd\.docker\.multiplexed-stream.*" "vnd.docker.multiplexed-stream libpod v4.7.0" 47 48 t POST "containers/foo/attach?logs=true&stream=false" 101 49 response_headers=$(cat "$WORKDIR/curl.headers.out") 50 like "$response_headers" ".*Content-Type: application/vnd\.docker\.raw-stream.*" "hijacked connection header: Content-type: application/vnd.docker.raw-stream" 51 like "$response_headers" ".*Upgrade: tcp.*" "hijacked connection header: Upgrade: tcp" 52 53 t POST "containers/foo/kill" 204 54 55 podman run --replace --name=foo -v /tmp:/tmp $IMAGE true 56 # cannot kill non-running container 57 t POST "containers/foo/kill" 409 58 t POST "libpod/containers/foo/kill" 409 59 60 t GET libpod/containers/json 200 length=0 61 62 # bad all input 63 t GET libpod/containers/json?all='garb1age' 500 \ 64 .cause="schema: error converting value for \"all\"" 65 66 t GET libpod/containers/json?all=true 200 \ 67 length=1 \ 68 .[0].Id~[0-9a-f]\\{64\\} \ 69 .[0].Image=$IMAGE \ 70 .[0].Command[0]="true" \ 71 .[0].State~\\\(exited\\\|stopped\\\) \ 72 .[0].ExitCode=0 \ 73 .[0].Mounts~.*/tmp \ 74 .[0].IsInfra=false 75 76 # Test compat API for Network Settings (.Network is N/A when rootless) 77 network_expect="Networks.pasta.NetworkID=pasta" 78 if root; then 79 network_expect="Networks.podman.NetworkID=podman" 80 fi 81 t GET /containers/json?all=true 200 \ 82 length=1 \ 83 .[0].Id~[0-9a-f]\\{64\\} \ 84 .[0].Image=$IMAGE \ 85 .[0].Mounts~.*/tmp \ 86 .[0].NetworkSettings.$network_expect 87 88 # compat API imageid with sha256: prefix 89 t GET containers/json?limit=1 200 \ 90 .[0].ImageID~sha256:[0-9a-f]\\{64\\} 91 92 # Make sure `limit` works. 93 t GET libpod/containers/json?limit=1 200 \ 94 length=1 \ 95 .[0].Id~[0-9a-f]\\{64\\} \ 96 .[0].Image=$IMAGE \ 97 .[0].Command[0]="true" \ 98 .[0].State~\\\(exited\\\|stopped\\\) \ 99 .[0].ExitCode=0 \ 100 .[0].IsInfra=false 101 102 # Make sure `last` works, which is an alias for `limit`. 103 # See https://github.com/containers/podman/issues/6413. 104 t GET libpod/containers/json?last=1 200 \ 105 length=1 \ 106 .[0].Id~[0-9a-f]\\{64\\} \ 107 .[0].Image=$IMAGE \ 108 .[0].Command[0]="true" \ 109 .[0].State~\\\(exited\\\|stopped\\\) \ 110 .[0].ExitCode=0 \ 111 .[0].IsInfra=false 112 113 cid=$(jq -r '.[0].Id' <<<"$output") 114 115 if root; then 116 t GET libpod/containers/stats?containers='[$cid]' 200 117 else 118 if have_cgroupsv2; then 119 t GET libpod/containers/stats?containers='[$cid]' 200 120 else 121 t GET libpod/containers/stats?containers='[$cid]' 409 122 fi 123 fi 124 125 # max_usage is not set for cgroupv2 126 if have_cgroupsv2; then 127 t GET libpod/containers/stats?containers='[$cid]' 200 \ 128 .memory_stats.max_usage=null 129 fi 130 131 t DELETE libpod/containers/$cid 200 .[0].Id=$cid 132 133 # Issue #14676: make sure the stats show the memory limit specified for the container 134 if root; then 135 CTRNAME=ctr-with-limit 136 podman run --name $CTRNAME -d -m 512m -v /tmp:/tmp $IMAGE top 137 138 t GET libpod/containers/$CTRNAME/stats?stream=false 200 \ 139 .memory_stats.limit=536870912 \ 140 .Id~[0-9a-f]\\{64\\} 141 142 # Make sure docker compat endpoint shows "id" lowercase 143 t GET containers/$CTRNAME/stats?stream=false 200 \ 144 .memory_stats.limit=536870912 \ 145 .id~[0-9a-f]\\{64\\} 146 147 t GET containers/$CTRNAME/top?stream=false 200 \ 148 .Titles='[ 149 "UID", 150 "PID", 151 "PPID", 152 "C", 153 "STIME", 154 "TTY", 155 "TIME", 156 "CMD" 157 ]' 158 159 podman rm -f $CTRNAME 160 fi 161 162 CTRNAME=test123 163 podman run --name $CTRNAME -d $IMAGE top 164 t GET libpod/containers/$CTRNAME/top?ps_args=--invalid 500 \ 165 .cause~".*unknown gnu long option.*" 166 t GET containers/$CTRNAME/top?ps_args=--invalid 500 \ 167 .cause~".*unknown gnu long option.*" 168 169 podman rm -f $CTRNAME 170 171 # Issue #15765: make sure the memory limit is capped 172 if root; then 173 CTRNAME=ctr-with-limit 174 podman run --name $CTRNAME -d -m 512m -v /tmp:/tmp $IMAGE top 175 176 t GET libpod/containers/$CTRNAME/stats?stream=false 200 \ 177 .memory_stats.limit!=18446744073709552000 178 179 podman rm -f $CTRNAME 180 fi 181 182 # Container create without existing image should return 404 183 t POST libpod/containers/create Image="foo" 404 \ 184 .cause="image not known" 185 186 # Issue #6799: it should be possible to start a container, even w/o args. 187 t POST libpod/containers/create?name=test_noargs Image=${IMAGE} 201 \ 188 .Id~[0-9a-f]\\{64\\} 189 cid=$(jq -r '.Id' <<<"$output") 190 # Prior to the fix in #6835, this would fail 500 "args must not be empty" 191 t POST libpod/containers/${cid}/start 204 192 # Container should exit almost immediately. Wait for it, confirm successful run 193 t POST "libpod/containers/${cid}/wait?condition=stopped&condition=exited" 200 '0' 194 t GET libpod/containers/${cid}/json 200 \ 195 .Id=$cid \ 196 .State.Status~\\\(exited\\\|stopped\\\) \ 197 .State.Running=false \ 198 .State.ExitCode=0 \ 199 .Config.Umask=0022 # regression check for #15036 200 t DELETE libpod/containers/$cid 200 .[0].Id=$cid 201 202 CNAME=myfoo 203 podman run -d --name $CNAME $IMAGE top 204 t GET libpod/containers/json?all=true 200 \ 205 .[0].Id~[0-9a-f]\\{64\\} 206 cid=$(jq -r '.[0].Id' <<<"$output") 207 208 # No such container 209 t POST "libpod/commit?container=nonesuch" 404 210 211 # Comment can only be used with docker format, not OCI 212 cparam="repo=newrepo&comment=foo&author=bob" 213 t POST "libpod/commit?container=$CNAME&$cparam" 500 \ 214 .cause="messages are only compatible with the docker image format (-f docker)" 215 216 # Commit a new image from the container 217 t POST "libpod/commit?container=$CNAME" 200 \ 218 .Id~[0-9a-f]\\{64\\} 219 iid=$(jq -r '.Id' <<<"$output") 220 t GET libpod/images/$iid/json 200 \ 221 .RepoTags[0]=null \ 222 .Author="" \ 223 .Comment="" 224 225 # Commit a new image w/o tag 226 cparam="repo=newrepo&comment=foo&author=bob&format=docker" 227 t POST "libpod/commit?container=$CNAME&$cparam" 200 228 t GET libpod/images/newrepo:latest/json 200 \ 229 .RepoTags[0]=localhost/newrepo:latest \ 230 .Author=bob \ 231 .Comment=foo 232 233 # Commit a new image w/ specified tag and author 234 cparam="repo=newrepo&tag=v1&author=alice" 235 t POST "libpod/commit?container=$cid&$cparam&pause=false" 200 236 t GET libpod/images/newrepo:v1/json 200 \ 237 .RepoTags[0]=localhost/newrepo:v1 \ 238 .Author=alice 239 240 # Commit a new image w/ full parameters 241 cparam="repo=newrepo&tag=v2&comment=bar&author=eric" 242 cparam="$cparam&format=docker&changes=CMD=/bin/foo" 243 244 if root || have_cgroupsv2; then 245 t POST "libpod/commit?container=${cid:0:12}&$cparam&pause=true" 200 246 t GET libpod/images/newrepo:v2/json 200 \ 247 .RepoTags[0]=localhost/newrepo:v2 \ 248 .Author=eric \ 249 .Comment=bar \ 250 .Config.Cmd[-1]="/bin/foo" 251 t DELETE images/localhost/newrepo:v2?force=true 200 252 else 253 # cgroupsv1 rootless : pause is not supported in cgroups v1 rootless 254 t POST "libpod/commit?container=${cid:0:12}&$cparam&pause=true" 500 \ 255 .cause="this container does not have a cgroup" \ 256 .message~".*pause containers on rootless containers with cgroup V1" 257 fi 258 259 # Create a container for testing the container initializing later 260 podman create -t -i --name myctr $IMAGE ls 261 262 # Check configuration before initializing 263 t GET libpod/containers/myctr/json 200 \ 264 .Id~[0-9a-f]\\{64\\} \ 265 .State.Status="created" \ 266 .State.Pid=0 \ 267 .ResolvConfPath="" \ 268 .HostnamePath="" \ 269 .HostsPath="" \ 270 .NetworkSettings.SandboxKey="" 271 272 cpid_file=$(jq -r '.ConmonPidFile' <<<"$output") 273 userdata_path=$(dirname $cpid_file) 274 275 # Initializing the container 276 t POST libpod/containers/myctr/init 204 277 278 # Check configuration after initializing 279 t GET libpod/containers/myctr/json 200 \ 280 .Id~[0-9a-f]\\{64\\} \ 281 .State.Status="initialized" \ 282 .State.Pid~[0-9]\\{1\,8\\} \ 283 .ResolvConfPath=$userdata_path/resolv.conf \ 284 .HostnamePath=$userdata_path/hostname \ 285 .HostsPath=$userdata_path/hosts \ 286 .NetworkSettings.SandboxKey~.*/netns/netns- \ 287 .OCIConfigPath~.*config\.json \ 288 .GraphDriver.Data.MergedDir~.*merged 289 290 # Test TS are in UTC 291 t GET containers/myctr/json 200 \ 292 .Created~.*Z \ 293 .State.StartedAt~.*Z \ 294 .State.FinishedAt~.*Z 295 296 t DELETE images/localhost/newrepo:latest?force=true 200 297 t DELETE images/localhost/newrepo:v1?force=true 200 298 t DELETE libpod/containers/$cid?force=true 200 .[0].Id=$cid 299 t DELETE libpod/containers/myctr 200 300 t DELETE libpod/containers/bogus 404 301 302 303 # test apiv2 create container with correct entrypoint and cmd 304 # --data '{"Image":"quay.io/libpod/alpine_labels:latest","Entrypoint":["echo"],"Cmd":["param1","param2"]}' 305 t POST containers/create \ 306 Image=$IMAGE \ 307 Entrypoint='["echo"]' \ 308 Cmd='["param1","param2"]' \ 309 201 \ 310 .Id~[0-9a-f]\\{64\\} 311 cid=$(jq -r '.Id' <<<"$output") 312 t GET containers/$cid/json 200 \ 313 .Config.Entrypoint[0]="echo" \ 314 .Config.Cmd[0]="param1" \ 315 .Config.Cmd[1]="param2" \ 316 .Path="echo" \ 317 .Args[0]="param1" \ 318 .Args[1]="param2" 319 t DELETE containers/$cid 204 320 321 # test only set the entrypoint, Cmd should be [] 322 t POST containers/create \ 323 Image=$IMAGE \ 324 Entrypoint='["echo","param1"]' \ 325 201 \ 326 .Id~[0-9a-f]\\{64\\} 327 cid=$(jq -r '.Id' <<<"$output") 328 t GET containers/$cid/json 200 \ 329 .Config.Entrypoint[0]="echo" \ 330 .Config.Entrypoint[1]="param1" \ 331 .Config.Cmd='[]' \ 332 .Path="echo" \ 333 .Args[0]="param1" 334 335 # create a running container for after 336 t POST containers/create Image=$IMAGE Entrypoint='["top"]' 201 \ 337 .Id~[0-9a-f]\\{64\\} 338 cid_top=$(jq -r '.Id' <<<"$output") 339 340 t GET containers/${cid_top}/json 200 \ 341 .Config.Entrypoint[0]="top" \ 342 .Config.Cmd='[]' \ 343 .Config.StopTimeout="10" \ 344 .Path="top" \ 345 .NetworkSettings.Networks.podman.NetworkID=podman 346 t POST containers/${cid_top}/start 204 347 # make sure the container is running 348 t GET containers/${cid_top}/json 200 \ 349 .State.Status="running" 350 351 # 0 means unlimited, need same with docker 352 t GET containers/json?limit=0 200 \ 353 .[0].Id~[0-9a-f]\\{64\\} 354 355 t GET 'containers/json?limit=0&all=1' 200 \ 356 .[0].Id~[0-9a-f]\\{64\\} \ 357 .[1].Id~[0-9a-f]\\{64\\} 358 359 t GET containers/json?limit=2 200 length=2 360 361 # Filter with two ids should return both container 362 t GET containers/json?filters='{"id":["'${cid}'","'${cid_top}'"]}&all=1' 200 length=2 363 # Filter with two ids and status running should return only 1 container 364 t GET containers/json?filters='{"id":["'${cid}'","'${cid_top}'"],"status":["running"]}&all=1' 200 \ 365 length=1 \ 366 .[0].Id=${cid_top} 367 368 t POST containers/${cid_top}/stop 204 369 370 t DELETE containers/$cid 204 371 t DELETE containers/$cid_top 204 372 373 # test the WORKDIR and StopSignal 374 t POST containers/create \ 375 Image=$ENV_WORKDIR_IMG \ 376 WorkingDir=/dataDir \ 377 StopSignal=\"9\" \ 378 201 \ 379 .Id~[0-9a-f]\\{64\\} 380 cid=$(jq -r '.Id' <<<"$output") 381 t GET containers/$cid/json 200 \ 382 .Config.WorkingDir="/dataDir" \ 383 .Config.StopSignal="9" 384 385 t DELETE containers/$cid 204 386 387 # when the image had multi tags, the container's Image should be correct 388 # Fixes https://github.com/containers/podman/issues/8547 389 t POST containers/create Image=${MultiTagName} 201 \ 390 .Id~[0-9a-f]\\{64\\} 391 cid=$(jq -r '.Id' <<<"$output") 392 t GET containers/$cid/json 200 \ 393 .Config.Image=${MultiTagName} \ 394 .Image~sha256:[0-9a-f]\\{64\\} 395 396 t DELETE containers/$cid 204 397 t DELETE images/${MultiTagName} 200 398 # vim: filetype=sh 399 400 # Test Volumes field adds an anonymous volume 401 t POST containers/create Image=$IMAGE Volumes='{"/test":{}}' 201 \ 402 .Id~[0-9a-f]\\{64\\} 403 cid=$(jq -r '.Id' <<<"$output") 404 t GET containers/$cid/json 200 \ 405 .Mounts[0].Destination="/test" 406 407 t DELETE containers/$cid?v=true 204 408 409 # Test Volumes with bind mount, for some reason docker-py sets this #18454 410 t POST containers/create Image=$IMAGE Volumes='{"/test/":{}}' HostConfig='{"Binds":["/tmp:/test/:ro"]}' 201 \ 411 .Id~[0-9a-f]\\{64\\} 412 cid=$(jq -r '.Id' <<<"$output") 413 t GET containers/$cid/json 200 \ 414 .Mounts[0].Destination="/test/" 415 416 t DELETE containers/$cid?v=true 204 417 418 # test port mapping 419 podman run -d --rm --name bar -p 8080:9090 $IMAGE top 420 421 t GET containers/json 200 \ 422 .[0].Ports[0].PrivatePort=9090 \ 423 .[0].Ports[0].PublicPort=8080 \ 424 .[0].Ports[0].Type="tcp" 425 426 podman stop bar 427 428 #compat api list containers sanity checks 429 podman run -d --rm --name labelcontainer_with $ENV_WORKDIR_IMG top 430 podman run -d --rm --name labelcontainer_without $IMAGE top 431 432 t GET containers/json?filters='garb1age}' 500 \ 433 .cause="invalid character 'g' looking for beginning of value" 434 t GET containers/json?filters='{"label":["testl' 500 \ 435 .cause="unexpected end of JSON input" 436 437 438 #libpod api list containers sanity checks 439 t GET libpod/containers/json?filters='{"status":["removing"]}' 200 length=0 440 t GET libpod/containers/json?filters='{"status":["bogus"]}' 500 \ 441 .cause="invalid argument" 442 t GET libpod/containers/json?filters='garb1age}' 500 \ 443 .cause="invalid character 'g' looking for beginning of value" 444 t GET libpod/containers/json?filters='{"label":["testl' 500 \ 445 .cause="unexpected end of JSON input" 446 447 # Prune containers - bad filter input 448 t POST containers/prune?filters='garb1age}' 500 \ 449 .cause="invalid character 'g' looking for beginning of value" 450 t POST libpod/containers/prune?filters='garb1age}' 500 \ 451 .cause="invalid character 'g' looking for beginning of value" 452 453 # Prune containers with illformed label 454 t POST containers/prune?filters='{"label":["tes' 500 \ 455 .cause="unexpected end of JSON input" 456 t POST libpod/containers/prune?filters='{"label":["tes' 500 \ 457 .cause="unexpected end of JSON input" 458 459 t GET libpod/containers/json?filters='{"label":["created_by"]}' 200 \ 460 length=1 \ 461 .[0].Names[0]="labelcontainer_with" 462 t GET libpod/containers/json?filters='{"label!":["created_by"]}' 200 \ 463 length=1 \ 464 .[0].Names[0]="labelcontainer_without" 465 t GET libpod/containers/json?filters='{"label!":["testlabel"]}' 200 length=2 466 467 podman stop -t0 labelcontainer_with labelcontainer_without 468 469 # libpod api: do not use list filters for prune 470 t POST libpod/containers/prune?filters='{"name":["anyname"]}' 500 \ 471 .cause="name is an invalid filter" 472 t POST libpod/containers/prune?filters='{"id":["anyid"]}' 500 \ 473 .cause="id is an invalid filter" 474 t POST libpod/containers/prune?filters='{"network":["anynetwork"]}' 500 \ 475 .cause="network is an invalid filter" 476 477 # compat api: do not use list filters for prune 478 t POST containers/prune?filters='{"name":["anyname"]}' 500 \ 479 .cause="name is an invalid filter" 480 t POST containers/prune?filters='{"id":["anyid"]}' 500 \ 481 .cause="id is an invalid filter" 482 t POST containers/prune?filters='{"network":["anynetwork"]}' 500 \ 483 .cause="network is an invalid filter" 484 485 # Test CPU limit (NanoCPUs) 486 nanoCpu=500000 487 if have_cgroupsv2; then 488 t POST containers/create Image=$IMAGE HostConfig='{"NanoCpus":500000}' 201 \ 489 .Id~[0-9a-f]\\{64\\} 490 else 491 if root; then 492 # cgroupsv1 rootful : NanoCpus needs to set more than 10000000 493 t POST containers/create Image=$IMAGE HostConfig='{"NanoCpus":500000}' 500 \ 494 .cause="CPU cfs quota cannot be less than 1ms (i.e. 1000)" 495 t POST containers/create Image=$IMAGE HostConfig='{"NanoCpus":10000000}' 201 \ 496 .Id~[0-9a-f]\\{64\\} 497 nanoCpu=10000000 498 else 499 # cgroupsv1 rootless : Resource limits that include NanoCPUs are not supported and ignored 500 t POST containers/create Image=$IMAGE HostConfig='{"NanoCpus":500000}' 201 \ 501 .Id~[0-9a-f]\\{64\\} 502 nanoCpu=0 503 fi 504 fi 505 506 cid=$(jq -r '.Id' <<<"$output") 507 t GET containers/$cid/json 200 \ 508 .HostConfig.NanoCpus=$nanoCpu 509 510 t DELETE containers/$cid?v=true 204 511 512 # Test Compat Create with default network mode (#10569) 513 t POST containers/create Image=$IMAGE HostConfig='{"NetworkMode":"default"}' 201 \ 514 .Id~[0-9a-f]\\{64\\} 515 cid=$(jq -r '.Id' <<<"$output") 516 t GET containers/$cid/json 200 \ 517 .HostConfig.NetworkMode="bridge" 518 519 t DELETE containers/$cid?v=true 204 520 521 # test create with default netns="host" 522 stop_service 523 CONTAINERS_CONF=$TESTS_DIR/containers.host-netns.conf start_service 524 525 # check that the default docker netns "default" is rewritten to "host" 526 # when the containers.conf explicitly uses "host" 527 t POST containers/create Image=$IMAGE HostConfig='{"NetworkMode":"default"}' 201 \ 528 .Id~[0-9a-f]\\{64\\} 529 cid=$(jq -r '.Id' <<<"$output") 530 t GET containers/$cid/json 200 \ 531 .HostConfig.NetworkMode="host" 532 533 t DELETE containers/$cid?v=true 204 534 535 # test create container like Docker >= 25 cli: NetworkMode="default" but EndpointsConfig struct is explicitly set and netns="host" 536 t POST containers/create \ 537 Image=$IMAGE \ 538 HostConfig='{"NetworkMode":"default"}' \ 539 NetworkingConfig='{"EndpointsConfig":{"default":{"IPAMConfig":null,"Links":null,"Aliases":null,"MacAddress":"","NetworkID":"","EndpointID":"","Gateway":"","IPAddress":"","IPPrefixLen":0,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"DriverOpts":null,"DNSNames":null}}}' \ 540 201 \ 541 .Id~[0-9a-f]\\{64\\} 542 cid=$(jq -r '.Id' <<<"$output") 543 t GET containers/$cid/json 200 \ 544 .HostConfig.NetworkMode="host" 545 546 t DELETE containers/$cid?v=true 204 547 548 # test creating a container fails with netns="hosts" on podman side but keep using the default network mode 549 # on docker CLI side and trying to use --ip 1.2.3.4 which is only valid for the bridge network mode (docker CLI 550 # will assume the default is the bridge mode, so it's valid from docker CLI point of view). 551 t POST containers/create \ 552 Image=$IMAGE \ 553 HostConfig='{"NetworkMode":"default"}' \ 554 NetworkingConfig='{"EndpointsConfig":{"default":{"IPAMConfig":null,"Links":null,"Aliases":null,"MacAddress":"","NetworkID":"","EndpointID":"","Gateway":"","IPAddress":"1.2.3.4","IPPrefixLen":0,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"DriverOpts":null,"DNSNames":null}}}' \ 555 500 \ 556 .cause="networks and static ip/mac address can only be used with Bridge mode networking" 557 558 # Restart with the default containers.conf for next tests. 559 stop_service 560 start_service 561 562 # Test Compat Create with healthcheck, check default values 563 t POST containers/create Image=$IMAGE Cmd='["top"]' Healthcheck='{"Test":["true"]}' 201 \ 564 .Id~[0-9a-f]\\{64\\} 565 cid=$(jq -r '.Id' <<<"$output") 566 t GET containers/$cid/json 200 \ 567 .Config.Healthcheck.Interval=30000000000 \ 568 .Config.Healthcheck.Timeout=30000000000 \ 569 .Config.Healthcheck.Retries=3 570 571 # compat api: Test for mount options support 572 # Sigh, JSON can't handle octal. 0755(octal) = 493(decimal) 573 payload='{"Mounts":[{"Type":"tmpfs","Target":"/mnt/scratch","TmpfsOptions":{"SizeBytes":1024,"Mode":493}}]}' 574 t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\} 575 cid=$(jq -r '.Id' <<<"$output") 576 t GET containers/$cid/json 200 \ 577 .HostConfig.Tmpfs['"/mnt/scratch"']~.*size=1024.* \ 578 .HostConfig.Tmpfs['"/mnt/scratch"']~.*mode=755.* 579 580 t DELETE containers/$cid?v=true 204 581 582 # compat api: tmpfs without mount options 583 payload='{"Mounts":[{"Type":"tmpfs","Target":"/mnt/scratch"}]}' 584 t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\} 585 cid=$(jq -r '.Id' <<<"$output") 586 t GET containers/$cid/json 200 \ 587 .HostConfig.Tmpfs['"/mnt/scratch"']~.*tmpcopyup.* \ 588 589 t DELETE containers/$cid?v=true 204 590 591 # compat api: bind mount without mount options 592 payload='{"Mounts":[{"Type":"bind","Source":"/tmp","Target":"/mnt"}]}' 593 t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\} 594 cid=$(jq -r '.Id' <<<"$output") 595 t GET containers/$cid/json 200 \ 596 .HostConfig.Binds[0]~/tmp:/mnt:.* \ 597 598 t DELETE containers/$cid?v=true 204 599 600 # test apiv2 create/commit 601 t POST containers/create \ 602 Image=$IMAGE \ 603 Entrypoint='["echo"]' \ 604 Cmd='["param1","param2"]' \ 605 201 \ 606 .Id~[0-9a-f]\\{64\\} 607 cid=$(jq -r '.Id' <<<"$output") 608 609 # No such container 610 t POST "commit?container=nonesuch" 404 611 612 cparam="repo=newrepo&tag=v3&comment=abcd&author=eric" 613 cparam="$cparam&format=docker&changes=CMD%20/bin/bar%0aEXPOSE%209090" 614 t POST "commit?container=${cid:0:12}&$cparam" 201 \ 615 .Id~[0-9a-f]\\{64\\} 616 iid=$(jq -r '.Id' <<<"$output") 617 t GET images/$iid/json 200 \ 618 .RepoTags[0]=docker.io/library/newrepo:v3 \ 619 .Config.ExposedPorts~.*"9090/tcp" \ 620 .Config.Cmd~.*"/bin/bar" \ 621 .Comment="abcd" 622 623 t DELETE containers/$cid 204 624 t DELETE images/docker.io/library/newrepo:v3?force=false 200 625 626 # test create without default no_hosts 627 t POST containers/create \ 628 Image=$IMAGE \ 629 201 \ 630 .Id~[0-9a-f]\\{64\\} 631 cid=$(jq -r '.Id' <<<"$output") 632 633 t POST libpod/containers/$cid/init 204 634 635 t GET libpod/containers/$cid/json 200 636 637 cpid_file=$(jq -r '.ConmonPidFile' <<<"$output") 638 userdata_path=$(dirname $cpid_file) 639 640 t GET libpod/containers/$cid/json 200 \ 641 .HostsPath=$userdata_path/hosts 642 643 t DELETE containers/$cid 204 644 645 # test create with default no_hosts=true 646 stop_service 647 648 CONTAINERS_CONF=$TESTS_DIR/containers.no_hosts.conf start_service 649 650 # check docker and libpod endpoint 651 for endpoint in containers/create libpod/containers/create; do 652 t POST $endpoint \ 653 Image=$IMAGE \ 654 201 \ 655 .Id~[0-9a-f]\\{64\\} 656 cid=$(jq -r '.Id' <<<"$output") 657 658 t POST libpod/containers/$cid/init 204 659 660 t GET libpod/containers/$cid/json 200 \ 661 .HostsPath="" 662 663 t DELETE containers/$cid 204 664 done 665 666 stop_service 667 start_service 668 669 # Our states are different from Docker's. 670 # Regression test for #14700 (Docker compat returning unknown "initialized" for status.status) to ensure the stay compatible 671 podman create --name status-test $IMAGE sh -c "sleep 3" 672 t GET containers/status-test/json 200 .State.Status="created" 673 674 podman init status-test 675 t GET containers/status-test/json 200 .State.Status="created" 676 677 podman start status-test 678 t GET containers/status-test/json 200 .State.Status="running" 679 680 # cgroupsv1 rootless : pause and unpause are not supported in cgroups v1 rootless 681 if root || have_cgroupsv2; then 682 podman pause status-test 683 t GET containers/status-test/json 200 .State.Status="paused" 684 685 podman unpause status-test 686 t GET containers/status-test/json 200 .State.Status="running" 687 fi 688 689 podman stop status-test & 690 sleep 1 691 t GET containers/status-test/json 200 .State.Status="stopping" 692 693 sleep 3 694 t GET containers/status-test/json 200 .State.Status="exited" 695 696 # test podman generate spec as input for the api 697 cname=specgen$(random_string 10) 698 podman create --name=$cname $IMAGE 699 700 TMPD=$(mktemp -d podman-apiv2-test.build.XXXXXXXX) 701 702 podman generate spec -f ${TMPD}/myspec.json -c $cname 703 704 # Create a container based on that spec 705 t POST libpod/containers/create ${TMPD}/myspec.json 201 \ 706 .Id~[0-9a-f]\\{64\\} 707 708 # Verify 709 t GET libpod/containers/$cname/json 200 \ 710 .ImageName=$IMAGE \ 711 .Name=$cname 712 713 if root; then 714 podman run -dt --name=updateCtr alpine 715 echo '{"Memory":{"Limit":500000}, "CPU":{"Shares":123}}' >${TMPD}/update.json 716 t POST libpod/containers/updateCtr/update ${TMPD}/update.json 201 717 718 cgroupPath=/sys/fs/cgroup/cpu.weight 719 # 002 is the byte length 720 cpu_weight_expect=$'\001\0025' 721 if ! have_cgroupsv2; then 722 cgroupPath=/sys/fs/cgroup/cpu/cpu.shares 723 # 004 is the byte length 724 cpu_weight_expect=$'\001\004123' 725 fi 726 727 # Verify 728 echo '{ "AttachStdout":true,"Cmd":["cat", "'$cgroupPath'"]}' >${TMPD}/exec.json 729 t POST containers/updateCtr/exec ${TMPD}/exec.json 201 .Id~[0-9a-f]\\{64\\} 730 eid=$(jq -r '.Id' <<<"$output") 731 t POST exec/$eid/start 200 $cpu_weight_expect 732 733 # Now use the compat API 734 echo '{ "Memory": 536870912 }' >${TMPD}/compatupdate.json 735 t POST containers/updateCtr/update ${TMPD}/compatupdate.json 200 736 t GET libpod/containers/updateCtr/json 200 \ 737 .HostConfig.Memory=536870912 738 739 podman rm -f updateCtr 740 fi 741 742 rm -rf $TMPD 743 744 podman container rm -fa 745 746 # 18951: Make sure container create supports the platform parameter. Force an 747 # initial architecture to make sure the test runs on all platforms. 748 podman pull --platform=linux/amd64 $IMAGE 749 t POST containers/create?platform=linux/amd64 \ 750 Image=$IMAGE \ 751 201 752 t POST containers/create?platform=linux/aarch64 \ 753 Image=$IMAGE \ 754 404 755 podman rmi -f $IMAGE