Files
podman/test/apiv2/20-containers.at
Matt Heon e04668c8ca Match output of Compat Top API to Docker
We were only splitting on tabs, not spaces, so we returned just a
single line most of the time, not an array of the fields in the
output of `ps`. Unfortunately, some of these fields are allowed
to contain spaces themselves, which makes things complicated, but
we got lucky in that Docker took the simplest possible solution
and just assumed that only one field would contain spaces and it
would always be the last one, which is easy enough to duplicate
on our end.

Fixes #23981

Signed-off-by: Matt Heon <mheon@redhat.com>
2024-09-17 11:34:22 -04:00

718 lines
23 KiB
Bash

# -*- sh -*-
#
# test container-related endpoints
#
# WORKDIR=/data
MultiTagName=localhost/test/testformultitag:tag
podman pull $IMAGE &>/dev/null
podman tag $IMAGE $MultiTagName
# Unimplemented
#t POST libpod/containers/create '' 201 'sdf'
# Ensure clean slate
podman rm -a -f &>/dev/null
t GET "libpod/containers/json (at start: clean slate)" 200 \
"[]" \
length=0
# check content type: https://github.com/containers/podman/issues/14647
response_headers=$(cat "$WORKDIR/curl.headers.out")
like "$response_headers" ".*Content-Type: application/json.*" "header does not contain application/json"
# Regression test for #12904 (race condition in logging code)
mytext="hi-there-$(random_string 15)"
podman run --rm -d --replace --name foo $IMAGE sh -c "echo $mytext;sleep 42"
# Logs output is prepended by ^A^Y (stdout = 1, length = 25 (with newline))
# Looks like it is missing the required 0 bytes from the message, why?
t POST "containers/foo/attach?logs=true&stream=false" 200 \
$'\001\031'$mytext
# check old docker header
response_headers=$(cat "$WORKDIR/curl.headers.out")
like "$response_headers" ".*Content-Type: application/vnd\.docker\.raw-stream.*" "vnd.docker.raw-stream docker v1.40"
# check new vnd.docker.multiplexed-stream header
t POST "/v1.42/containers/foo/attach?logs=true&stream=false" 200
response_headers=$(cat "$WORKDIR/curl.headers.out")
like "$response_headers" ".*Content-Type: application/vnd\.docker\.multiplexed-stream.*" "vnd.docker.multiplexed-stream docker v1.42"
t POST "/v4.6.0/libpod/containers/foo/attach?logs=true&stream=false" 200
response_headers=$(cat "$WORKDIR/curl.headers.out")
like "$response_headers" ".*Content-Type: application/vnd\.docker\.raw-stream.*" "vnd.docker.raw-stream libpod v4.6.0"
t POST "/v4.7.0/libpod/containers/foo/attach?logs=true&stream=false" 200
response_headers=$(cat "$WORKDIR/curl.headers.out")
like "$response_headers" ".*Content-Type: application/vnd\.docker\.multiplexed-stream.*" "vnd.docker.multiplexed-stream libpod v4.7.0"
t POST "containers/foo/attach?logs=true&stream=false" 101
response_headers=$(cat "$WORKDIR/curl.headers.out")
like "$response_headers" ".*Content-Type: application/vnd\.docker\.raw-stream.*" "hijacked connection header: Content-type: application/vnd.docker.raw-stream"
like "$response_headers" ".*Upgrade: tcp.*" "hijacked connection header: Upgrade: tcp"
t POST "containers/foo/kill" 204
podman run --replace --name=foo -v /tmp:/tmp $IMAGE true
# cannot kill non-running container
t POST "containers/foo/kill" 409
t POST "libpod/containers/foo/kill" 409
t GET libpod/containers/json 200 length=0
# bad all input
t GET libpod/containers/json?all='garb1age' 500 \
.cause="schema: error converting value for \"all\""
t GET libpod/containers/json?all=true 200 \
length=1 \
.[0].Id~[0-9a-f]\\{64\\} \
.[0].Image=$IMAGE \
.[0].Command[0]="true" \
.[0].State~\\\(exited\\\|stopped\\\) \
.[0].ExitCode=0 \
.[0].Mounts~.*/tmp \
.[0].IsInfra=false
# Test compat API for Network Settings (.Network is N/A when rootless)
network_expect="Networks.pasta.NetworkID=pasta"
if root; then
network_expect="Networks.podman.NetworkID=podman"
fi
t GET /containers/json?all=true 200 \
length=1 \
.[0].Id~[0-9a-f]\\{64\\} \
.[0].Image=$IMAGE \
.[0].Mounts~.*/tmp \
.[0].NetworkSettings.$network_expect
# compat API imageid with sha256: prefix
t GET containers/json?limit=1 200 \
.[0].ImageID~sha256:[0-9a-f]\\{64\\}
# Make sure `limit` works.
t GET libpod/containers/json?limit=1 200 \
length=1 \
.[0].Id~[0-9a-f]\\{64\\} \
.[0].Image=$IMAGE \
.[0].Command[0]="true" \
.[0].State~\\\(exited\\\|stopped\\\) \
.[0].ExitCode=0 \
.[0].IsInfra=false
# Make sure `last` works, which is an alias for `limit`.
# See https://github.com/containers/podman/issues/6413.
t GET libpod/containers/json?last=1 200 \
length=1 \
.[0].Id~[0-9a-f]\\{64\\} \
.[0].Image=$IMAGE \
.[0].Command[0]="true" \
.[0].State~\\\(exited\\\|stopped\\\) \
.[0].ExitCode=0 \
.[0].IsInfra=false
cid=$(jq -r '.[0].Id' <<<"$output")
t GET "libpod/containers/stats?containers=$cid&stream=false" 200 \
.memory_stats.max_usage=null
t DELETE libpod/containers/$cid 200 .[0].Id=$cid
# Issue #14676: make sure the stats show the memory limit specified for the container
if root; then
CTRNAME=ctr-with-limit
podman run --name $CTRNAME -d -m 512m -v /tmp:/tmp $IMAGE top
t GET libpod/containers/$CTRNAME/stats?stream=false 200 \
.memory_stats.limit=536870912 \
.Id~[0-9a-f]\\{64\\}
# Make sure docker compat endpoint shows "id" lowercase
t GET containers/$CTRNAME/stats?stream=false 200 \
.memory_stats.limit=536870912 \
.id~[0-9a-f]\\{64\\}
t GET containers/$CTRNAME/top?stream=false 200 \
.Titles='[
"UID",
"PID",
"PPID",
"C",
"STIME",
"TTY",
"TIME",
"CMD"
]'
podman rm -f $CTRNAME
fi
# Verify that compat top endpoint combines multi-entry COMMAND lines
CTRNAME=testtopproc
podman run --name $CTRNAME -d $IMAGE sleep 25
t GET containers/$CTRNAME/top?stream=false 200 \
.Processes.[0].[6]="00:00:00" \
.Processes.[0].[7]="sleep 25"
podman rm -f -t0 $CTRNAME
CTRNAME=test123
podman run --name $CTRNAME -d $IMAGE top
t GET libpod/containers/$CTRNAME/top?ps_args=--invalid 500 \
.cause~".*unknown gnu long option.*"
t GET containers/$CTRNAME/top?ps_args=--invalid 500 \
.cause~".*unknown gnu long option.*"
podman rm -f $CTRNAME
# Issue #15765: make sure the memory limit is capped
if root; then
CTRNAME=ctr-with-limit
podman run --name $CTRNAME -d -m 512m -v /tmp:/tmp $IMAGE top
t GET libpod/containers/$CTRNAME/stats?stream=false 200 \
.memory_stats.limit!=18446744073709552000
podman rm -f $CTRNAME
fi
# Container create without existing image should return 404
t POST libpod/containers/create Image="foo" 404 \
.cause="image not known"
# Issue #6799: it should be possible to start a container, even w/o args.
t POST libpod/containers/create?name=test_noargs Image=${IMAGE} 201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
# Prior to the fix in #6835, this would fail 500 "args must not be empty"
t POST libpod/containers/${cid}/start 204
# Container should exit almost immediately. Wait for it, confirm successful run
t POST "libpod/containers/${cid}/wait?condition=stopped&condition=exited" 200 '0'
t GET libpod/containers/${cid}/json 200 \
.Id=$cid \
.State.Status~\\\(exited\\\|stopped\\\) \
.State.Running=false \
.State.ExitCode=0 \
.Config.Umask=0022 # regression check for #15036
t DELETE libpod/containers/$cid 200 .[0].Id=$cid
CNAME=myfoo
podman run -d --name $CNAME $IMAGE top
t GET libpod/containers/json?all=true 200 \
.[0].Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.[0].Id' <<<"$output")
# No such container
t POST "libpod/commit?container=nonesuch" 404
# Comment can only be used with docker format, not OCI
cparam="repo=newrepo&comment=foo&author=bob"
t POST "libpod/commit?container=$CNAME&$cparam" 500 \
.cause="messages are only compatible with the docker image format (-f docker)"
# Commit a new image from the container
t POST "libpod/commit?container=$CNAME" 200 \
.Id~[0-9a-f]\\{64\\}
iid=$(jq -r '.Id' <<<"$output")
t GET libpod/images/$iid/json 200 \
.RepoTags[0]=null \
.Author="" \
.Comment=""
# Commit a new image w/o tag
cparam="repo=newrepo&comment=foo&author=bob&format=docker"
t POST "libpod/commit?container=$CNAME&$cparam" 200
t GET libpod/images/newrepo:latest/json 200 \
.RepoTags[0]=localhost/newrepo:latest \
.Author=bob \
.Comment=foo
# Commit a new image w/ specified tag and author
cparam="repo=newrepo&tag=v1&author=alice"
t POST "libpod/commit?container=$cid&$cparam&pause=false" 200
t GET libpod/images/newrepo:v1/json 200 \
.RepoTags[0]=localhost/newrepo:v1 \
.Author=alice
# Commit a new image w/ full parameters
cparam="repo=newrepo&tag=v2&comment=bar&author=eric"
cparam="$cparam&format=docker&changes=CMD=/bin/foo"
t POST "libpod/commit?container=${cid:0:12}&$cparam&pause=true" 200
t GET libpod/images/newrepo:v2/json 200 \
.RepoTags[0]=localhost/newrepo:v2 \
.Author=eric \
.Comment=bar \
.Config.Cmd[-1]="/bin/foo"
t DELETE images/localhost/newrepo:v2?force=true 200
# Create a container for testing the container initializing later
podman create -t -i --name myctr $IMAGE ls
# Check configuration before initializing
t GET libpod/containers/myctr/json 200 \
.Id~[0-9a-f]\\{64\\} \
.State.Status="created" \
.State.Pid=0 \
.ResolvConfPath="" \
.HostnamePath="" \
.HostsPath="" \
.NetworkSettings.SandboxKey=""
cpid_file=$(jq -r '.ConmonPidFile' <<<"$output")
userdata_path=$(dirname $cpid_file)
# Initializing the container
t POST libpod/containers/myctr/init 204
# Check configuration after initializing
t GET libpod/containers/myctr/json 200 \
.Id~[0-9a-f]\\{64\\} \
.State.Status="initialized" \
.State.Pid~[0-9]\\{1\,8\\} \
.ResolvConfPath=$userdata_path/resolv.conf \
.HostnamePath=$userdata_path/hostname \
.HostsPath=$userdata_path/hosts \
.NetworkSettings.SandboxKey~.*/netns/netns- \
.OCIConfigPath~.*config\.json \
.GraphDriver.Data.MergedDir~.*merged
# Test TS are in UTC
t GET containers/myctr/json 200 \
.Created~.*Z \
.State.StartedAt~.*Z \
.State.FinishedAt~.*Z
t DELETE images/localhost/newrepo:latest?force=true 200
t DELETE images/localhost/newrepo:v1?force=true 200
t DELETE libpod/containers/$cid?force=true 200 .[0].Id=$cid
t DELETE libpod/containers/myctr 200
t DELETE libpod/containers/bogus 404
# test apiv2 create container with correct entrypoint and cmd
# --data '{"Image":"quay.io/libpod/some:thing","Entrypoint":["echo"],"Cmd":["param1","param2"]}'
t POST containers/create \
Image=$IMAGE \
Entrypoint='["echo"]' \
Cmd='["param1","param2"]' \
201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.Config.Entrypoint[0]="echo" \
.Config.Cmd[0]="param1" \
.Config.Cmd[1]="param2" \
.Path="echo" \
.Args[0]="param1" \
.Args[1]="param2"
t DELETE containers/$cid 204
# test only set the entrypoint, Cmd should be []
t POST containers/create \
Image=$IMAGE \
Entrypoint='["echo","param1"]' \
201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.Config.Entrypoint[0]="echo" \
.Config.Entrypoint[1]="param1" \
.Config.Cmd='[]' \
.Path="echo" \
.Args[0]="param1"
# create a running container for after
t POST containers/create Image=$IMAGE Entrypoint='["top"]' 201 \
.Id~[0-9a-f]\\{64\\}
cid_top=$(jq -r '.Id' <<<"$output")
t GET containers/${cid_top}/json 200 \
.Config.Entrypoint[0]="top" \
.Config.Cmd='[]' \
.Config.StopTimeout="10" \
.Path="top" \
.NetworkSettings.Networks.podman.NetworkID=podman
t POST containers/${cid_top}/start 204
# make sure the container is running
t GET containers/${cid_top}/json 200 \
.State.Status="running"
# 0 means unlimited, need same with docker
t GET containers/json?limit=0 200 \
.[0].Id~[0-9a-f]\\{64\\}
t GET 'containers/json?limit=0&all=1' 200 \
.[0].Id~[0-9a-f]\\{64\\} \
.[1].Id~[0-9a-f]\\{64\\}
t GET containers/json?limit=2 200 length=2
# Filter with two ids should return both container
t GET containers/json?filters='{"id":["'${cid}'","'${cid_top}'"]}&all=1' 200 length=2
# Filter with two ids and status running should return only 1 container
t GET containers/json?filters='{"id":["'${cid}'","'${cid_top}'"],"status":["running"]}&all=1' 200 \
length=1 \
.[0].Id=${cid_top}
t POST containers/${cid_top}/stop 204
t DELETE containers/$cid 204
t DELETE containers/$cid_top 204
# test the WORKDIR and StopSignal
t POST containers/create \
Image=$IMAGE \
WorkingDir=/dataDir \
StopSignal=\"9\" \
201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.Config.WorkingDir="/dataDir" \
.Config.StopSignal="9"
t DELETE containers/$cid 204
# when the image had multi tags, the container's Image should be correct
# Fixes https://github.com/containers/podman/issues/8547
t POST containers/create Image=${MultiTagName} 201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.Config.Image=${MultiTagName} \
.Image~sha256:[0-9a-f]\\{64\\}
t DELETE containers/$cid 204
t DELETE images/${MultiTagName} 200
# vim: filetype=sh
# Test Volumes field adds an anonymous volume
t POST containers/create Image=$IMAGE Volumes='{"/test":{}}' 201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.Mounts[0].Destination="/test"
t DELETE containers/$cid?v=true 204
# Test Volumes with bind mount, for some reason docker-py sets this #18454
t POST containers/create Image=$IMAGE Volumes='{"/test/":{}}' HostConfig='{"Binds":["/tmp:/test/:ro"]}' 201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.Mounts[0].Destination="/test/"
t DELETE containers/$cid?v=true 204
# test port mapping
podman run -d --rm --name bar -p 8080:9090 $IMAGE top
t GET containers/json 200 \
.[0].Ports[0].PrivatePort=9090 \
.[0].Ports[0].PublicPort=8080 \
.[0].Ports[0].Type="tcp"
podman stop bar
#compat api list containers sanity checks
podman run -d --rm --name labelcontainer_with --label slartibart=fast $IMAGE top
podman run -d --rm --name labelcontainer_without $IMAGE top
t GET containers/json?filters='garb1age}' 500 \
.cause="invalid character 'g' looking for beginning of value"
t GET containers/json?filters='{"label":["testl' 500 \
.cause="unexpected end of JSON input"
#libpod api list containers sanity checks
t GET libpod/containers/json?filters='{"status":["removing"]}' 200 length=0
t GET libpod/containers/json?filters='{"status":["bogus"]}' 500 \
.cause="invalid argument"
t GET libpod/containers/json?filters='garb1age}' 500 \
.cause="invalid character 'g' looking for beginning of value"
t GET libpod/containers/json?filters='{"label":["testl' 500 \
.cause="unexpected end of JSON input"
# Prune containers - bad filter input
t POST containers/prune?filters='garb1age}' 500 \
.cause="invalid character 'g' looking for beginning of value"
t POST libpod/containers/prune?filters='garb1age}' 500 \
.cause="invalid character 'g' looking for beginning of value"
# Prune containers with illformed label
t POST containers/prune?filters='{"label":["tes' 500 \
.cause="unexpected end of JSON input"
t POST libpod/containers/prune?filters='{"label":["tes' 500 \
.cause="unexpected end of JSON input"
t GET libpod/containers/json?filters='{"label":["slartibart"]}' 200 \
length=1 \
.[0].Names[0]="labelcontainer_with"
t GET libpod/containers/json?filters='{"label!":["slartibart"]}' 200 \
length=1 \
.[0].Names[0]="labelcontainer_without"
t GET libpod/containers/json?filters='{"label!":["testlabel"]}' 200 length=2
podman stop -t0 labelcontainer_with labelcontainer_without
# libpod api: do not use list filters for prune
t POST libpod/containers/prune?filters='{"name":["anyname"]}' 500 \
.cause="name is an invalid filter"
t POST libpod/containers/prune?filters='{"id":["anyid"]}' 500 \
.cause="id is an invalid filter"
t POST libpod/containers/prune?filters='{"network":["anynetwork"]}' 500 \
.cause="network is an invalid filter"
# compat api: do not use list filters for prune
t POST containers/prune?filters='{"name":["anyname"]}' 500 \
.cause="name is an invalid filter"
t POST containers/prune?filters='{"id":["anyid"]}' 500 \
.cause="id is an invalid filter"
t POST containers/prune?filters='{"network":["anynetwork"]}' 500 \
.cause="network is an invalid filter"
# Test CPU limit (NanoCPUs)
nanoCpu=500000
t POST containers/create Image=$IMAGE HostConfig='{"NanoCpus":500000}' 201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.HostConfig.NanoCpus=$nanoCpu
t DELETE containers/$cid?v=true 204
# Test Compat Create with default network mode (#10569)
t POST containers/create Image=$IMAGE HostConfig='{"NetworkMode":"default"}' 201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.HostConfig.NetworkMode="bridge"
t DELETE containers/$cid?v=true 204
# test create with default netns="host"
stop_service
CONTAINERS_CONF=$TESTS_DIR/containers.host-netns.conf start_service
# check that the default docker netns "default" is rewritten to "host"
# when the containers.conf explicitly uses "host"
t POST containers/create Image=$IMAGE HostConfig='{"NetworkMode":"default"}' 201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.HostConfig.NetworkMode="host"
t DELETE containers/$cid?v=true 204
# test create container like Docker >= 25 cli: NetworkMode="default" but EndpointsConfig struct is explicitly set and netns="host"
t POST containers/create \
Image=$IMAGE \
HostConfig='{"NetworkMode":"default"}' \
NetworkingConfig='{"EndpointsConfig":{"default":{"IPAMConfig":null,"Links":null,"Aliases":null,"MacAddress":"","NetworkID":"","EndpointID":"","Gateway":"","IPAddress":"","IPPrefixLen":0,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"DriverOpts":null,"DNSNames":null}}}' \
201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.HostConfig.NetworkMode="host"
t DELETE containers/$cid?v=true 204
# test creating a container fails with netns="hosts" on podman side but keep using the default network mode
# on docker CLI side and trying to use --ip 1.2.3.4 which is only valid for the bridge network mode (docker CLI
# will assume the default is the bridge mode, so it's valid from docker CLI point of view).
t POST containers/create \
Image=$IMAGE \
HostConfig='{"NetworkMode":"default"}' \
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}}}' \
500 \
.cause="networks and static ip/mac address can only be used with Bridge mode networking"
# Restart with the default containers.conf for next tests.
stop_service
start_service
# Test Compat Create with healthcheck, check default values
t POST containers/create Image=$IMAGE Cmd='["top"]' Healthcheck='{"Test":["true"]}' 201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.Config.Healthcheck.Interval=30000000000 \
.Config.Healthcheck.Timeout=30000000000 \
.Config.Healthcheck.Retries=3
# compat api: Test for mount options support
# Sigh, JSON can't handle octal. 0755(octal) = 493(decimal)
payload='{"Mounts":[{"Type":"tmpfs","Target":"/mnt/scratch","TmpfsOptions":{"SizeBytes":1024,"Mode":493}}]}'
t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.HostConfig.Tmpfs['"/mnt/scratch"']~.*size=1024.* \
.HostConfig.Tmpfs['"/mnt/scratch"']~.*mode=755.*
t DELETE containers/$cid?v=true 204
# compat api: tmpfs without mount options
payload='{"Mounts":[{"Type":"tmpfs","Target":"/mnt/scratch"}]}'
t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.HostConfig.Tmpfs['"/mnt/scratch"']~.*tmpcopyup.* \
t DELETE containers/$cid?v=true 204
# compat api: bind mount without mount options
payload='{"Mounts":[{"Type":"bind","Source":"/tmp","Target":"/mnt"}]}'
t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
.HostConfig.Binds[0]~/tmp:/mnt:.* \
t DELETE containers/$cid?v=true 204
# test apiv2 create/commit
t POST containers/create \
Image=$IMAGE \
Entrypoint='["echo"]' \
Cmd='["param1","param2"]' \
201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
# No such container
t POST "commit?container=nonesuch" 404
cparam="repo=newrepo&tag=v3&comment=abcd&author=eric"
cparam="$cparam&format=docker&changes=CMD%20/bin/bar%0aEXPOSE%209090"
t POST "commit?container=${cid:0:12}&$cparam" 201 \
.Id~[0-9a-f]\\{64\\}
iid=$(jq -r '.Id' <<<"$output")
t GET images/$iid/json 200 \
.RepoTags[0]=docker.io/library/newrepo:v3 \
.Config.ExposedPorts~.*"9090/tcp" \
.Config.Cmd~.*"/bin/bar" \
.Comment="abcd"
t DELETE containers/$cid 204
t DELETE images/docker.io/library/newrepo:v3?force=false 200
# test create without default no_hosts
t POST containers/create \
Image=$IMAGE \
201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t POST libpod/containers/$cid/init 204
t GET libpod/containers/$cid/json 200
cpid_file=$(jq -r '.ConmonPidFile' <<<"$output")
userdata_path=$(dirname $cpid_file)
t GET libpod/containers/$cid/json 200 \
.HostsPath=$userdata_path/hosts
t DELETE containers/$cid 204
# test create with default no_hosts=true
stop_service
CONTAINERS_CONF=$TESTS_DIR/containers.no_hosts.conf start_service
# check docker and libpod endpoint
for endpoint in containers/create libpod/containers/create; do
t POST $endpoint \
Image=$IMAGE \
201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t POST libpod/containers/$cid/init 204
t GET libpod/containers/$cid/json 200 \
.HostsPath=""
t DELETE containers/$cid 204
done
stop_service
start_service
# Our states are different from Docker's.
# Regression test for #14700 (Docker compat returning unknown "initialized" for status.status) to ensure the stay compatible
podman create --name status-test $IMAGE sh -c "sleep 3"
t GET containers/status-test/json 200 .State.Status="created"
podman init status-test
t GET containers/status-test/json 200 .State.Status="created"
podman start status-test
t GET containers/status-test/json 200 .State.Status="running"
podman pause status-test
t GET containers/status-test/json 200 .State.Status="paused"
podman unpause status-test
t GET containers/status-test/json 200 .State.Status="running"
podman stop status-test &
sleep 1
t GET containers/status-test/json 200 .State.Status="stopping"
sleep 3
t GET containers/status-test/json 200 .State.Status="exited"
# test podman generate spec as input for the api
cname=specgen$(random_string 10)
podman create --name=$cname $IMAGE
TMPD=$(mktemp -d podman-apiv2-test.build.XXXXXXXX)
podman generate spec -f ${TMPD}/myspec.json -c $cname
# Create a container based on that spec
t POST libpod/containers/create ${TMPD}/myspec.json 201 \
.Id~[0-9a-f]\\{64\\}
# Verify
t GET libpod/containers/$cname/json 200 \
.ImageName=$IMAGE \
.Name=$cname
if root; then
podman run -dt --name=updateCtr alpine
echo '{"Memory":{"Limit":500000}, "CPU":{"Shares":123}}' >${TMPD}/update.json
t POST libpod/containers/updateCtr/update ${TMPD}/update.json 201
cgroupPath=/sys/fs/cgroup/cpu.weight
# 002 is the byte length
cpu_weight_expect=$'\001\0025'
# Verify
echo '{ "AttachStdout":true,"Cmd":["cat", "'$cgroupPath'"]}' >${TMPD}/exec.json
t POST containers/updateCtr/exec ${TMPD}/exec.json 201 .Id~[0-9a-f]\\{64\\}
eid=$(jq -r '.Id' <<<"$output")
t POST exec/$eid/start 200 $cpu_weight_expect
# Now use the compat API
echo '{ "Memory": 536870912 }' >${TMPD}/compatupdate.json
t POST containers/updateCtr/update ${TMPD}/compatupdate.json 200
t GET libpod/containers/updateCtr/json 200 \
.HostConfig.Memory=536870912
podman rm -f updateCtr
fi
rm -rf $TMPD
podman container rm -fa
# 18951: Make sure container create supports the platform parameter. Force an
# initial architecture to make sure the test runs on all platforms.
podman pull --platform=linux/amd64 $IMAGE
t POST containers/create?platform=linux/amd64 \
Image=$IMAGE \
201
t POST containers/create?platform=linux/aarch64 \
Image=$IMAGE \
404
podman rmi -f $IMAGE