summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pkg/api/handlers/compat/images_build.go7
-rw-r--r--pkg/api/server/register_images.go2
-rw-r--r--test/apiv2/01-basic.at10
-rw-r--r--test/apiv2/10-images.at8
-rw-r--r--test/apiv2/12-imagesMore.at10
-rw-r--r--test/apiv2/20-containers.at53
-rw-r--r--test/apiv2/22-stop.at16
-rw-r--r--test/apiv2/25-containersMore.at10
-rw-r--r--test/apiv2/26-containersWait.at10
-rw-r--r--test/apiv2/30-volumes.at47
-rw-r--r--test/apiv2/35-networks.at13
-rw-r--r--test/apiv2/40-pods.at40
-rw-r--r--test/apiv2/44-mounts.at11
-rw-r--r--test/apiv2/45-system.at34
-rw-r--r--test/apiv2/50-secrets.at8
-rw-r--r--test/apiv2/README.md11
-rw-r--r--test/apiv2/rest_api/__init__.py26
-rw-r--r--test/apiv2/rest_api/test_rest_v2_0_0.py59
-rwxr-xr-xtest/apiv2/test-apiv236
-rw-r--r--test/system/260-sdnotify.bats13
20 files changed, 241 insertions, 183 deletions
diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go
index 392f688dd..7751b91a7 100644
--- a/pkg/api/handlers/compat/images_build.go
+++ b/pkg/api/handlers/compat/images_build.go
@@ -445,6 +445,13 @@ loop:
logrus.Warnf("Failed to json encode error %v", err)
}
flush()
+ for _, tag := range query.Tag {
+ m.Stream = fmt.Sprintf("Successfully tagged %s\n", tag)
+ if err := enc.Encode(m); err != nil {
+ logrus.Warnf("Failed to json encode error %v", err)
+ }
+ flush()
+ }
}
}
break loop
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index f6a8a37ca..3d86e5d38 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -652,6 +652,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// example: |
// (build details...)
// Successfully built 8ba084515c724cbf90d447a63600c0a6
+ // Successfully tagged your_image:latest
// 400:
// $ref: "#/responses/BadParamError"
// 500:
@@ -1485,7 +1486,6 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: output from build process
// example: |
// (build details...)
- // Successfully built 8ba084515c724cbf90d447a63600c0a6
// 400:
// $ref: "#/responses/BadParamError"
// 500:
diff --git a/test/apiv2/01-basic.at b/test/apiv2/01-basic.at
index 1357e0ca6..788007069 100644
--- a/test/apiv2/01-basic.at
+++ b/test/apiv2/01-basic.at
@@ -30,18 +30,18 @@ done
# Garbage tests - requests that should yield errors
#
t GET /nonesuch 404
-t POST /nonesuch '' 404
+t POST /nonesuch 404
t GET container/nonesuch/json 404
t GET libpod/containers/nonesuch/json 404
#### FIXME: maybe someday: t GET 'libpod/containers/json?a=b' 400
# Method not allowed
-t POST /_ping '' 405
+t POST /_ping 405
t DELETE /_ping 405
-t POST libpod/containers/json '' 405
-t POST libpod/pods/abc '' 405
-t POST info '' 405
+t POST libpod/containers/json 405
+t POST libpod/pods/abc 405
+t POST info 405
t GET libpod/containers/create 405
#
diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at
index f866422e2..4ebaeff45 100644
--- a/test/apiv2/10-images.at
+++ b/test/apiv2/10-images.at
@@ -41,18 +41,18 @@ t GET images/$iid/json 200 \
.Id=sha256:$iid \
.RepoTags[0]=$IMAGE
-t POST "images/create?fromImage=alpine" '' 200 .error~null .status~".*Download complete.*"
+t POST "images/create?fromImage=alpine" 200 .error~null .status~".*Download complete.*"
-t POST "images/create?fromImage=alpine&tag=latest" '' 200
+t POST "images/create?fromImage=alpine&tag=latest" 200
# Make sure that new images are pulled
old_iid=$(podman image inspect --format "{{.ID}}" docker.io/library/alpine:latest)
podman rmi -f docker.io/library/alpine:latest
podman tag $IMAGE docker.io/library/alpine:latest
-t POST "images/create?fromImage=alpine" '' 200 .error~null .status~".*$old_iid.*"
+t POST "images/create?fromImage=alpine" 200 .error~null .status~".*$old_iid.*"
podman untag $IMAGE docker.io/library/alpine:latest
-t POST "images/create?fromImage=quay.io/libpod/alpine&tag=sha256:fa93b01658e3a5a1686dc3ae55f170d8de487006fb53a28efcd12ab0710a2e5f" '' 200
+t POST "images/create?fromImage=quay.io/libpod/alpine&tag=sha256:fa93b01658e3a5a1686dc3ae55f170d8de487006fb53a28efcd12ab0710a2e5f" 200
# Display the image history
t GET libpod/images/nonesuch/history 404
diff --git a/test/apiv2/12-imagesMore.at b/test/apiv2/12-imagesMore.at
index ce3049106..144b83194 100644
--- a/test/apiv2/12-imagesMore.at
+++ b/test/apiv2/12-imagesMore.at
@@ -17,10 +17,10 @@ t GET libpod/images/$IMAGE/tree 200 \
.Tree~^Image
# Tag nonesuch image
-t POST "libpod/images/nonesuch/tag?repo=myrepo&tag=mytag" '' 404
+t POST "libpod/images/nonesuch/tag?repo=myrepo&tag=mytag" 404
# Tag the image
-t POST "libpod/images/$IMAGE/tag?repo=localhost:5000/myrepo&tag=mytag" '' 201
+t POST "libpod/images/$IMAGE/tag?repo=localhost:5000/myrepo&tag=mytag" 201
t GET libpod/images/$IMAGE/json 200 \
.RepoTags[1]=localhost:5000/myrepo:mytag
@@ -41,13 +41,13 @@ if [ -z "${GOT_DIGEST}" ] ; then
fi
# Push to local registry
-t POST "images/localhost:5000/myrepo/push?tlsVerify=false&tag=mytag" '' 200
+t POST "images/localhost:5000/myrepo/push?tlsVerify=false&tag=mytag" 200
# Untag the image
-t POST "libpod/images/$iid/untag?repo=localhost:5000/myrepo&tag=mytag" '' 201
+t POST "libpod/images/$iid/untag?repo=localhost:5000/myrepo&tag=mytag" 201
# Try to push non-existing image
-t POST "images/localhost:5000/idonotexist/push?tlsVerify=false" '' 200
+t POST "images/localhost:5000/idonotexist/push?tlsVerify=false" 200
jq -re 'select(.errorDetail)' <<<"$output" &>/dev/null || echo -e "${red}not ok: error message not found in output${nc}" 1>&2
t GET libpod/images/$IMAGE/json 200 \
diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at
index 383d92ef3..478717700 100644
--- a/test/apiv2/20-containers.at
+++ b/test/apiv2/20-containers.at
@@ -31,12 +31,16 @@ t GET libpod/containers/json?all=true 200 \
.[0].ExitCode=0 \
.[0].IsInfra=false
-# Test compat API for Network Settings
+# Test compat API for Network Settings (.Network is N/A when rootless)
+network_expect=
+if root; then
+ network_expect='.[0].NetworkSettings.Networks.podman.NetworkID=podman'
+fi
t GET /containers/json?all=true 200 \
length=1 \
.[0].Id~[0-9a-f]\\{64\\} \
.[0].Image=$IMAGE \
- .[0].NetworkSettings.Networks.podman.NetworkID=podman
+ $network_expect
# Make sure `limit` works.
t GET libpod/containers/json?limit=1 200 \
@@ -68,9 +72,9 @@ 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
+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 POST "libpod/containers/${cid}/wait?condition=stopped&condition=exited" 200 '0'
t GET libpod/containers/${cid}/json 200 \
.Id=$cid \
.State.Status~\\\(exited\\\|stopped\\\) \
@@ -85,15 +89,15 @@ t GET libpod/containers/json?all=true 200 \
cid=$(jq -r '.[0].Id' <<<"$output")
# No such container
-t POST "libpod/commit?container=nonesuch" '' 404
+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 \
+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 \
+t POST "libpod/commit?container=$CNAME" 200 \
.Id~[0-9a-f]\\{64\\}
iid=$(jq -r '.Id' <<<"$output")
t GET libpod/images/$iid/json 200 \
@@ -103,7 +107,7 @@ t GET libpod/images/$iid/json 200 \
# 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 POST "libpod/commit?container=$CNAME&$cparam" 200
t GET libpod/images/newrepo:latest/json 200 \
.RepoTags[0]=localhost/newrepo:latest \
.Author=bob \
@@ -111,7 +115,7 @@ t GET libpod/images/newrepo:latest/json 200 \
# 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 POST "libpod/commit?container=$cid&$cparam&pause=false" 200
t GET libpod/images/newrepo:v1/json 200 \
.RepoTags[0]=localhost/newrepo:v1 \
.Author=alice
@@ -119,7 +123,7 @@ t GET libpod/images/newrepo:v1/json 200 \
# 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 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 \
@@ -143,7 +147,7 @@ cpid_file=$(jq -r '.ConmonPidFile' <<<"$output")
userdata_path=$(dirname $cpid_file)
# Initializing the container
-t POST libpod/containers/myctr/init '' 204
+t POST libpod/containers/myctr/init 204
# Check configuration after initializing
t GET libpod/containers/myctr/json 200 \
@@ -167,7 +171,11 @@ t DELETE libpod/containers/bogus 404
# test apiv2 create container with correct entrypoint and cmd
# --data '{"Image":"quay.io/libpod/alpine_labels:latest","Entrypoint":["echo"],"Cmd":["param1","param2"]}'
-t POST containers/create '"Image":"'$IMAGE'","Entrypoint":["echo"],"Cmd":["param1","param2"]' 201 \
+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 \
@@ -180,7 +188,10 @@ t GET containers/$cid/json 200 \
t DELETE containers/$cid 204
# test only set the entrypoint, Cmd should be []
-t POST containers/create '"Image":"'$IMAGE'","Entrypoint":["echo","param1"]' 201 \
+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 \
@@ -191,14 +202,14 @@ t GET containers/$cid/json 200 \
.Args[0]="param1"
# create a running container for after
-t POST containers/create '"Image":"'$IMAGE'","Entrypoint":["top"]' 201 \
+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='[]' \
.Path="top"
-t POST containers/${cid_top}/start '' 204
+t POST containers/${cid_top}/start 204
# make sure the container is running
t GET containers/${cid_top}/json 200 \
.State.Status="running"
@@ -220,13 +231,17 @@ t GET containers/json?filters='{"id":["'${cid}'","'${cid_top}'"],"status":["runn
length=1 \
.[0].Id=${cid_top}
-t POST containers/${cid_top}/stop "" 204
+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":"'$ENV_WORKDIR_IMG'","WorkingDir":"/dataDir","StopSignal":"9"' 201 \
+t POST containers/create \
+ Image=$ENV_WORKDIR_IMG \
+ WorkingDir=/dataDir \
+ StopSignal=9 \
+ 201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
@@ -247,7 +262,7 @@ t DELETE images/${MultiTagName}?force=true 200
# vim: filetype=sh
# Test Volumes field adds an anonymous volume
-t POST containers/create '"Image":"'$IMAGE'","Volumes":{"/test":{}}' 201 \
+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 \
@@ -266,7 +281,7 @@ t GET containers/json 200 \
podman stop bar
# Test CPU limit (NanoCPUs)
-t POST containers/create '"Image":"'$IMAGE'","HostConfig":{"NanoCpus":500000}' 201 \
+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 \
diff --git a/test/apiv2/22-stop.at b/test/apiv2/22-stop.at
index 11318ca81..91bc9937d 100644
--- a/test/apiv2/22-stop.at
+++ b/test/apiv2/22-stop.at
@@ -8,17 +8,17 @@ podman pull $IMAGE &>/dev/null
# stop, by name
podman run -dt --name mytop $IMAGE top &>/dev/null
-t GET libpod/containers/mytop/json 200 .State.Status=running
-t POST libpod/containers/mytop/stop "" 204
-t GET libpod/containers/mytop/json 200 .State.Status~\\\(exited\\\|stopped\\\)
-t DELETE libpod/containers/mytop 204
+t GET libpod/containers/mytop/json 200 .State.Status=running
+t POST libpod/containers/mytop/stop 204
+t GET libpod/containers/mytop/json 200 .State.Status~\\\(exited\\\|stopped\\\)
+t DELETE libpod/containers/mytop 204
# stop, by ID
# Remember that podman() hides all output; we need to get our CID via inspect
podman run -dt --name mytop $IMAGE top
-t GET libpod/containers/mytop/json 200 .State.Status=running
+t GET libpod/containers/mytop/json 200 .State.Status=running
cid=$(jq -r .Id <<<"$output")
-t POST libpod/containers/$cid/stop "" 204
-t GET libpod/containers/mytop/json 200 .State.Status~\\\(exited\\\|stopped\\\)
-t DELETE libpod/containers/mytop 204
+t POST libpod/containers/$cid/stop 204
+t GET libpod/containers/mytop/json 200 .State.Status~\\\(exited\\\|stopped\\\)
+t DELETE libpod/containers/mytop 204
diff --git a/test/apiv2/25-containersMore.at b/test/apiv2/25-containersMore.at
index b88c798eb..39bfa2e32 100644
--- a/test/apiv2/25-containersMore.at
+++ b/test/apiv2/25-containersMore.at
@@ -17,7 +17,7 @@ t GET libpod/containers/nonesuch/exists 404
t GET libpod/containers/foo/exists 204
# Pause the container
-t POST libpod/containers/foo/pause '' 204
+t POST libpod/containers/foo/pause 204
t GET libpod/containers/foo/json 200 \
.Id~[0-9a-f]\\{64\\} \
@@ -27,7 +27,7 @@ t GET libpod/containers/foo/json 200 \
.Name=foo
# Unpause the container
-t POST libpod/containers/foo/unpause '' 204
+t POST libpod/containers/foo/unpause 204
t GET libpod/containers/foo/json 200 \
.Id~[0-9a-f]\\{64\\} \
@@ -44,11 +44,11 @@ t GET libpod/containers/foo/top 200 \
t GET libpod/containers/nonesuch/top 404
# Mount the container to host filesystem
-t POST libpod/containers/foo/mount '' 200
+t POST libpod/containers/foo/mount 200
like "$output" ".*merged" "Check container mount"
# Unmount the container
-t POST libpod/containers/foo/unmount '' 204
+t POST libpod/containers/foo/unmount 204
t DELETE libpod/containers/foo?force=true 204
@@ -85,7 +85,7 @@ podman run $IMAGE true
podman run $IMAGE true
podman run $IMAGE true
-t POST libpod/containers/prune '' 200
+t POST libpod/containers/prune 200
t GET libpod/containers/json 200 \
length=0
# vim: filetype=sh
diff --git a/test/apiv2/26-containersWait.at b/test/apiv2/26-containersWait.at
index 3f530c3f0..6a628e55a 100644
--- a/test/apiv2/26-containersWait.at
+++ b/test/apiv2/26-containersWait.at
@@ -13,15 +13,15 @@ podman rm -a -f &>/dev/null
CTR="WaitTestingCtr"
-t POST "containers/nonExistent/wait?condition=next-exit" '' 404
+t POST "containers/nonExistent/wait?condition=next-exit" 404
podman create --name "${CTR}" --entrypoint '["sleep", "0.5"]' "${IMAGE}"
-t POST "containers/${CTR}/wait?condition=non-existent-cond" '' 400
+t POST "containers/${CTR}/wait?condition=non-existent-cond" 400
-t POST "containers/${CTR}/wait?condition=not-running" '' 200
+t POST "containers/${CTR}/wait?condition=not-running" 200
-t POST "containers/${CTR}/wait?condition=next-exit" '' 200 &
+t POST "containers/${CTR}/wait?condition=next-exit" 200 &
child_pid=$!
podman start "${CTR}"
wait "${child_pid}"
@@ -37,7 +37,7 @@ if kill -2 "${child_pid}" 2> "/dev/null"; then
WAIT_TEST_ERROR="1"
fi
-t POST "containers/${CTR}/wait?condition=removed" '' 200 &
+t POST "containers/${CTR}/wait?condition=removed" 200 &
child_pid=$!
podman container rm "${CTR}"
wait "${child_pid}"
diff --git a/test/apiv2/30-volumes.at b/test/apiv2/30-volumes.at
index cf4b3d3ea..c27c638bb 100644
--- a/test/apiv2/30-volumes.at
+++ b/test/apiv2/30-volumes.at
@@ -13,25 +13,34 @@ t POST libpod/volumes/create name=foo1 201 \
.CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
.Labels={} \
.Options={}
-t POST libpod/volumes/create '' 201
+t POST libpod/volumes/create 201
t POST libpod/volumes/create \
- '"Name":"foo2","Label":{"testlabel":"testonly"},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \
- .Name=foo2 \
- .Labels.testlabel=testonly \
- .Options.type=tmpfs \
- .Options.o=nodev,noexec
+ Name=foo2 \
+ Label='{"testlabel":"testonly"}' \
+ Options='{"type":"tmpfs","o":"nodev,noexec"}}' \
+ 201 \
+ .Name=foo2 \
+ .Labels.testlabel=testonly \
+ .Options.type=tmpfs \
+ .Options.o=nodev,noexec
t POST libpod/volumes/create \
- '"Name":"foo3","Label":{"testlabel":""},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \
- .Name=foo3 \
- .Labels.testlabel="" \
- .Options.type=tmpfs \
- .Options.o=nodev,noexec
+ Name=foo3 \
+ Label='{"testlabel":""}' \
+ Options='{"type":"tmpfs","o":"nodev,noexec"}}' \
+ 201 \
+ .Name=foo3 \
+ .Labels.testlabel="" \
+ .Options.type=tmpfs \
+ .Options.o=nodev,noexec
t POST libpod/volumes/create \
- '"Name":"foo4","Label":{"testlabel1":"testonly"},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \
- .Name=foo4 \
- .Labels.testlabel1=testonly \
- .Options.type=tmpfs \
- .Options.o=nodev,noexec
+ Name=foo4 \
+ Label='{"testlabel1":"testonly"}' \
+ Options='{"type":"tmpfs","o":"nodev,noexec"}}' \
+ 201 \
+ .Name=foo4 \
+ .Labels.testlabel1=testonly \
+ .Options.type=tmpfs \
+ .Options.o=nodev,noexec
# Negative test
# We have created a volume named "foo1"
@@ -78,15 +87,15 @@ t DELETE libpod/volumes/foo1 404 \
.response=404
## Prune volumes with label matching 'testlabel1=testonly'
-t POST libpod/volumes/prune?filters='{"label":["testlabel1=testonly"]}' "" 200
+t POST libpod/volumes/prune?filters='{"label":["testlabel1=testonly"]}' 200
t GET libpod/volumes/json?filters='{"label":["testlabel1=testonly"]}' 200 length=0
## Prune volumes with label matching 'testlabel'
-t POST libpod/volumes/prune?filters='{"label":["testlabel"]}' "" 200
+t POST libpod/volumes/prune?filters='{"label":["testlabel"]}' 200
t GET libpod/volumes/json?filters='{"label":["testlabel"]}' 200 length=0
## Prune volumes
-t POST libpod/volumes/prune "" 200
+t POST libpod/volumes/prune 200
#After prune volumes, there should be no volume existing
t GET libpod/volumes/json 200 length=0
diff --git a/test/apiv2/35-networks.at b/test/apiv2/35-networks.at
index d3bbaf32b..98786e914 100644
--- a/test/apiv2/35-networks.at
+++ b/test/apiv2/35-networks.at
@@ -6,18 +6,21 @@
t GET networks/non-existing-network 404 \
.cause='network not found'
-t POST libpod/networks/create?name=network1 '' 200 \
+t POST libpod/networks/create?name=network1 200 \
.Filename~.*/network1\\.conflist
# --data '{"Subnet":{"IP":"10.10.254.0","Mask":[255,255,255,0]},"Labels":{"abc":"val"}}'
-t POST libpod/networks/create?name=network2 '"Subnet":{"IP":"10.10.254.0","Mask":[255,255,255,0]},"Labels":{"abc":"val"}' 200 \
+t POST libpod/networks/create?name=network2 \
+ Subnet='{"IP":"10.10.254.0","Mask":[255,255,255,0]}' \
+ Labels='{"abc":"val"}' \
+ 200 \
.Filename~.*/network2\\.conflist
# test for empty mask
-t POST libpod/networks/create '"Subnet":{"IP":"10.10.1.0","Mask":[]}' 500 \
+t POST libpod/networks/create Subnet='{"IP":"10.10.1.0","Mask":[]}' 500 \
.cause~'.*cannot be empty'
# test for invalid mask
-t POST libpod/networks/create '"Subnet":{"IP":"10.10.1.0","Mask":[0,255,255,0]}' 500 \
+t POST libpod/networks/create Subnet='{"IP":"10.10.1.0","Mask":[0,255,255,0]}' 500 \
.cause~'.*mask is invalid'
# network list
@@ -55,7 +58,7 @@ t GET networks/a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1
.Scope=local
# network create docker
-t POST networks/create '"Name":"net3","IPAM":{"Config":[]}' 201
+t POST networks/create Name=net3\ IPAM='{"Config":[]}' 201
# network delete docker
t DELETE networks/net3 204
diff --git a/test/apiv2/40-pods.at b/test/apiv2/40-pods.at
index ce65105d2..f3272c41e 100644
--- a/test/apiv2/40-pods.at
+++ b/test/apiv2/40-pods.at
@@ -25,70 +25,70 @@ t POST "libpod/pods/create (dup pod)" name=foo 409 \
#t POST libpod/pods/create a=b 400 .cause='bad parameter' # FIXME: unimplemented
-t POST libpod/pods/foo/start '' 200 \
+t POST libpod/pods/foo/start 200 \
.Errs=null \
.Id=$pod_id
-t POST libpod/pods/foo/start '' 304 \
+t POST libpod/pods/foo/start 304 \
-t POST libpod/pods/fakename/start '' 404 \
+t POST libpod/pods/fakename/start 404 \
.cause="no such pod" \
.message="no pod with name or ID fakename found: no such pod"
if root || have_cgroupsv2; then
- t POST libpod/pods/foo/pause '' 200
+ t POST libpod/pods/foo/pause 200
else
# Rootless cgroupsv1 : unsupported
- t POST "libpod/pods/foo/pause (rootless cgroups v1)" '' 500 \
+ t POST "libpod/pods/foo/pause (rootless cgroups v1)" 500 \
.cause="this container does not have a cgroup" \
.message~".*pause pods containing rootless containers with cgroup V1"
fi
-t POST libpod/pods/foo/unpause '' 200
-t POST "libpod/pods/foo/unpause (2nd unpause in a row)" '' 200
-t POST "libpod/pods/fakename/unpause" '' 404\
+t POST libpod/pods/foo/unpause 200
+t POST "libpod/pods/foo/unpause (2nd unpause in a row)" 200
+t POST "libpod/pods/fakename/unpause" 404\
.cause="no such pod" \
.message="no pod with name or ID fakename found: no such pod"
-t POST libpod/pods/foo/stop '' 200 \
+t POST libpod/pods/foo/stop 200 \
.Errs=null \
.Id=$pod_id
-t POST "libpod/pods/foo/stop (pod is already stopped)" '' 304
-t POST "libpod/pods/fakename/stop" '' 404\
+t POST "libpod/pods/foo/stop (pod is already stopped)" 304
+t POST "libpod/pods/fakename/stop" 404\
.cause="no such pod" \
.message="no pod with name or ID fakename found: no such pod"
-t POST libpod/pods/foo/restart '' 200 \
+t POST libpod/pods/foo/restart 200 \
.Errs=null \
.Id=$pod_id
-t POST "libpod/pods/bar/restart (restart on nonexistent pod)" '' 404
+t POST "libpod/pods/bar/restart (restart on nonexistent pod)" 404
t POST libpod/pods/create name=bar 201 .Id~[0-9a-f]\\{64\\}
pod_bar_id=$(jq -r .Id <<<"$output")
-t POST libpod/pods/bar/restart '' 200 \
+t POST libpod/pods/bar/restart 200 \
.Errs=null \
.Id=$pod_bar_id
-t GET libpod/pods/bar/json 200 \
+t GET libpod/pods/bar/json 200 \
.State=Running
-t POST libpod/pods/bar/restart '' 200 \
+t POST libpod/pods/bar/restart 200 \
.Errs=null \
.Id=$pod_bar_id
-t POST "libpod/pods/bar/stop?t=invalid" '' 400 \
+t POST "libpod/pods/bar/stop?t=invalid" 400 \
.cause="schema: error converting value for \"t\"" \
.message~"failed to parse parameters for"
podman run -d --pod bar busybox sleep 999
-t POST libpod/pods/bar/stop?t=1 '' 200 \
+t POST libpod/pods/bar/stop?t=1 200 \
.Errs=null \
.Id=$pod_bar_id
-t POST libpod/pods/bar/start '' 200
+t POST libpod/pods/bar/start 200
t GET libpod/pods/stats?all=true 200
is $(jq '. | length' <<<"$output") 3 "stats?all=true: number of records found"
@@ -118,7 +118,7 @@ t GET libpod/pods/foo/top?ps_args=args,pid 200 \
# FIXME: I'm not sure what 'prune' is supposed to do; as of 20200224 it
# just returns 200 (ok) with empty result list.
-#t POST libpod/pods/prune '' 200 # FIXME: 2020-02-24 returns 200 {}
+#t POST libpod/pods/prune 200 # FIXME: 2020-02-24 returns 200 {}
#t POST libpod/pods/prune 'a=b' 400 # FIXME: 2020-02-24 returns 200
# Clean up; and try twice, making sure that the second time fails
diff --git a/test/apiv2/44-mounts.at b/test/apiv2/44-mounts.at
index 5dc560852..901245da6 100644
--- a/test/apiv2/44-mounts.at
+++ b/test/apiv2/44-mounts.at
@@ -4,7 +4,12 @@ podman pull $IMAGE &>/dev/null
# Test various HostConfig options
tmpfs_name="/mytmpfs"
-t POST containers/create?name=hostconfig_test '"Image":"'$IMAGE'","Cmd":["df"],"HostConfig":{"Binds":["/tmp/doesnotexist:/test1"],"TmpFs":{"'$tmpfs_name'":"rw"}}' 201 \
+t POST containers/create?name=hostconfig_test \
+ Image=$IMAGE \
+ Cmd='["df"]' \
+ HostConfig='{"Binds":["/tmp/doesnotexist:/test1"]' \
+ TmpFs="{\"$tmpfs_name\":\"rw\"}}" \
+ 201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
@@ -13,8 +18,8 @@ t GET containers/${cid}/json 200 \
.HostConfig.Tmpfs[\"${tmpfs_name}\"]~rw,
# Run the container, verify output
-t POST containers/${cid}/start '' 204
-t POST containers/${cid}/wait '' 200
+t POST containers/${cid}/start 204
+t POST containers/${cid}/wait 200
t GET containers/${cid}/logs?stdout=true 200
like "$(<$WORKDIR/curl.result.out)" ".* ${tmpfs_name}" \
diff --git a/test/apiv2/45-system.at b/test/apiv2/45-system.at
index ad4bdf4f7..364b87c56 100644
--- a/test/apiv2/45-system.at
+++ b/test/apiv2/45-system.at
@@ -27,22 +27,28 @@ t GET libpod/system/df 200 '.Volumes[0].VolumeName=foo1'
# Create two more volumes to test pruneing
t POST libpod/volumes/create \
- '"Name":"foo2","Label":{"testlabel1":""},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \
- .Name=foo2 \
- .Driver=local \
- .Mountpoint=$volumepath/foo2/_data \
- .CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
- .Labels.testlabel1="" \
- .Options.o=nodev,noexec
+ Name=foo2 \
+ Label='{"testlabel1":""}' \
+ Options='{"type":"tmpfs","o":"nodev,noexec"}}' \
+ 201 \
+ .Name=foo2 \
+ .Driver=local \
+ .Mountpoint=$volumepath/foo2/_data \
+ .CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
+ .Labels.testlabel1="" \
+ .Options.o=nodev,noexec
t POST libpod/volumes/create \
- '"Name":"foo3","Label":{"testlabel1":"testonly"},"Options":{"type":"tmpfs","o":"nodev,noexec"}}' 201 \
- .Name=foo3 \
- .Driver=local \
- .Mountpoint=$volumepath/foo3/_data \
- .CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
- .Labels.testlabel1=testonly \
- .Options.o=nodev,noexec
+ Name=foo3 \
+ Label='{"testlabel1":"testonly"}' \
+ Options='{"type":"tmpfs","o":"nodev,noexec"}}' \
+ 201 \
+ .Name=foo3 \
+ .Driver=local \
+ .Mountpoint=$volumepath/foo3/_data \
+ .CreatedAt~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
+ .Labels.testlabel1=testonly \
+ .Options.o=nodev,noexec
t GET system/df 200 '.Volumes | length=3'
t GET libpod/system/df 200 '.Volumes | length=3'
diff --git a/test/apiv2/50-secrets.at b/test/apiv2/50-secrets.at
index c4ffb5883..034ec080a 100644
--- a/test/apiv2/50-secrets.at
+++ b/test/apiv2/50-secrets.at
@@ -4,14 +4,14 @@
#
# secret create
-t POST secrets/create '"Name":"mysecret","Data":"c2VjcmV0"' 200\
+t POST secrets/create Name=mysecret Data=c2VjcmV0 200\
.ID~.* \
# secret create unsupported labels
-t POST secrets/create '"Name":"mysecret","Data":"c2VjcmV0","Labels":{"fail":"fail"}' 400
+t POST secrets/create Name=mysecret Data=c2VjcmV0 Labels='{"fail":"fail"}' 400
# secret create name already in use
-t POST secrets/create '"Name":"mysecret","Data":"c2VjcmV0"' 409
+t POST secrets/create Name=mysecret Data=c2VjcmV0 409
# secret inspect
t GET secrets/mysecret 200 \
@@ -36,4 +36,4 @@ t DELETE secrets/mysecret 204
t DELETE secrets/bogus 404
# secret update not implemented
-t POST secrets/mysecret/update "" 501
+t POST secrets/mysecret/update 501
diff --git a/test/apiv2/README.md b/test/apiv2/README.md
index 252d6454e..19727cec7 100644
--- a/test/apiv2/README.md
+++ b/test/apiv2/README.md
@@ -52,9 +52,14 @@ Notes:
If there's no leading slash, `t` prepends `/v1.40`. This is a simple
convenience for simplicity of writing tests.
-* When method is POST, the argument after the endpoint must be a series
-of POST arguments in the form 'key=value', separated by commas. `t` will
-convert those to JSON form for passing to the server.
+* When method is POST, the argument(s) after the endpoint may be a series
+of POST parameters in the form 'key=value', separated by spaces:
+ t POST myentrypoint 200 ! no params
+ t POST myentrypoint id=$id 200 ! just one
+ t POST myentrypoint id=$id filter='{"foo":"bar"}' 200 ! two, with json
+ t POST myentrypoint name=$name badparam='["foo","bar"]' 500 ! etc...
+`t` will convert the param list to JSON form for passing to the server.
+A numeric status code terminates processing of POST parameters.
* The final arguments are one or more expected string results. If an
argument starts with a dot, `t` will invoke `jq` on the output to
diff --git a/test/apiv2/rest_api/__init__.py b/test/apiv2/rest_api/__init__.py
index b7b8a7649..0ad6b51b3 100644
--- a/test/apiv2/rest_api/__init__.py
+++ b/test/apiv2/rest_api/__init__.py
@@ -3,6 +3,7 @@ import json
import os
import shutil
import subprocess
+import sys
import tempfile
@@ -27,7 +28,9 @@ class Podman(object):
self.cmd.append("--root=" + os.path.join(self.anchor_directory, "crio"))
self.cmd.append("--runroot=" + os.path.join(self.anchor_directory, "crio-run"))
- os.environ["CONTAINERS_REGISTRIES_CONF"] = os.path.join(self.anchor_directory, "registry.conf")
+ os.environ["CONTAINERS_REGISTRIES_CONF"] = os.path.join(
+ self.anchor_directory, "registry.conf"
+ )
p = configparser.ConfigParser()
p.read_dict(
{
@@ -114,13 +117,20 @@ class Podman(object):
check = kwargs.get("check", False)
shell = kwargs.get("shell", False)
- return subprocess.run(
- cmd,
- shell=shell,
- check=check,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- )
+ try:
+ return subprocess.run(
+ cmd,
+ shell=shell,
+ check=check,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+ except subprocess.CalledProcessError as e:
+ if e.stdout:
+ sys.stdout.write("\nRun Stdout:\n" + e.stdout.decode("utf-8"))
+ if e.stderr:
+ sys.stderr.write("\nRun Stderr:\n" + e.stderr.decode("utf-8"))
+ raise
def tear_down(self):
shutil.rmtree(self.anchor_directory, ignore_errors=True)
diff --git a/test/apiv2/rest_api/test_rest_v2_0_0.py b/test/apiv2/rest_api/test_rest_v2_0_0.py
index 8a78f5185..c0b61ea85 100644
--- a/test/apiv2/rest_api/test_rest_v2_0_0.py
+++ b/test/apiv2/rest_api/test_rest_v2_0_0.py
@@ -50,23 +50,20 @@ class TestApi(unittest.TestCase):
def setUp(self):
super().setUp()
- try:
- TestApi.podman.run("run", "alpine", "/bin/ls", check=True)
- except subprocess.CalledProcessError as e:
- if e.stdout:
- sys.stdout.write("\nRun Stdout:\n" + e.stdout.decode("utf-8"))
- if e.stderr:
- sys.stderr.write("\nRun Stderr:\n" + e.stderr.decode("utf-8"))
- raise
+ TestApi.podman.run("run", "alpine", "/bin/ls", check=True)
+
+ def tearDown(self) -> None:
+ super().tearDown()
+
+ TestApi.podman.run("pod", "rm", "--all", "--force", check=True)
+ TestApi.podman.run("rm", "--all", "--force", check=True)
@classmethod
def setUpClass(cls):
super().setUpClass()
TestApi.podman = Podman()
- TestApi.service = TestApi.podman.open(
- "system", "service", "tcp:localhost:8080", "--time=0"
- )
+ TestApi.service = TestApi.podman.open("system", "service", "tcp:localhost:8080", "--time=0")
# give the service some time to be ready...
time.sleep(2)
@@ -243,9 +240,7 @@ class TestApi(unittest.TestCase):
def test_post_create_compat(self):
"""Create network and connect container during create"""
- net = requests.post(
- PODMAN_URL + "/v1.40/networks/create", json={"Name": "TestNetwork"}
- )
+ net = requests.post(PODMAN_URL + "/v1.40/networks/create", json={"Name": "TestNetwork"})
self.assertEqual(net.status_code, 201, net.text)
create = requests.post(
@@ -454,15 +449,11 @@ class TestApi(unittest.TestCase):
self.assertIn(k, o)
def test_network_compat(self):
- name = "Network_" + "".join(
- random.choice(string.ascii_letters) for i in range(10)
- )
+ name = "Network_" + "".join(random.choice(string.ascii_letters) for i in range(10))
# Cannot test for 0 existing networks because default "podman" network always exists
- create = requests.post(
- PODMAN_URL + "/v1.40/networks/create", json={"Name": name}
- )
+ create = requests.post(PODMAN_URL + "/v1.40/networks/create", json={"Name": name})
self.assertEqual(create.status_code, 201, create.content)
obj = json.loads(create.content)
self.assertIn(type(obj), (dict,))
@@ -492,9 +483,7 @@ class TestApi(unittest.TestCase):
self.assertEqual(inspect.status_code, 404, inspect.content)
# network prune
- prune_name = "Network_" + "".join(
- random.choice(string.ascii_letters) for i in range(10)
- )
+ prune_name = "Network_" + "".join(random.choice(string.ascii_letters) for i in range(10))
prune_create = requests.post(
PODMAN_URL + "/v1.40/networks/create", json={"Name": prune_name}
)
@@ -506,9 +495,7 @@ class TestApi(unittest.TestCase):
self.assertTrue(prune_name in obj["NetworksDeleted"])
def test_volumes_compat(self):
- name = "Volume_" + "".join(
- random.choice(string.ascii_letters) for i in range(10)
- )
+ name = "Volume_" + "".join(random.choice(string.ascii_letters) for i in range(10))
ls = requests.get(PODMAN_URL + "/v1.40/volumes")
self.assertEqual(ls.status_code, 200, ls.content)
@@ -524,9 +511,7 @@ class TestApi(unittest.TestCase):
for k in required_keys:
self.assertIn(k, obj)
- create = requests.post(
- PODMAN_URL + "/v1.40/volumes/create", json={"Name": name}
- )
+ create = requests.post(PODMAN_URL + "/v1.40/volumes/create", json={"Name": name})
self.assertEqual(create.status_code, 201, create.content)
# See https://docs.docker.com/engine/api/v1.40/#operation/VolumeCreate
@@ -703,21 +688,15 @@ class TestApi(unittest.TestCase):
"""Verify issue #8865"""
pod_name = list()
- pod_name.append(
- "Pod_" + "".join(random.choice(string.ascii_letters) for i in range(10))
- )
- pod_name.append(
- "Pod_" + "".join(random.choice(string.ascii_letters) for i in range(10))
- )
+ pod_name.append("Pod_" + "".join(random.choice(string.ascii_letters) for i in range(10)))
+ pod_name.append("Pod_" + "".join(random.choice(string.ascii_letters) for i in range(10)))
r = requests.post(
_url("/pods/create"),
json={
"name": pod_name[0],
"no_infra": False,
- "portmappings": [
- {"host_ip": "127.0.0.1", "host_port": 8889, "container_port": 89}
- ],
+ "portmappings": [{"host_ip": "127.0.0.1", "host_port": 8889, "container_port": 89}],
},
)
self.assertEqual(r.status_code, 201, r.text)
@@ -736,9 +715,7 @@ class TestApi(unittest.TestCase):
json={
"name": pod_name[1],
"no_infra": False,
- "portmappings": [
- {"host_ip": "127.0.0.1", "host_port": 8889, "container_port": 89}
- ],
+ "portmappings": [{"host_ip": "127.0.0.1", "host_port": 8889, "container_port": 89}],
},
)
self.assertEqual(r.status_code, 201, r.text)
diff --git a/test/apiv2/test-apiv2 b/test/apiv2/test-apiv2
index e32d6bc62..9f6bf257f 100755
--- a/test/apiv2/test-apiv2
+++ b/test/apiv2/test-apiv2
@@ -156,19 +156,23 @@ function _bump() {
# jsonify # convert 'foo=bar,x=y' to json {"foo":"bar","x":"y"}
#############
function jsonify() {
- # split by comma
- local -a settings_in
- read -ra settings_in <<<"$1"
-
# convert each to double-quoted form
local -a settings_out
- for i in ${settings_in[*]}; do
- settings_out+=$(sed -e 's/\(.*\)=\(.*\)/"\1":"\2"/' <<<$i)
+ for i in "$@"; do
+ # Each argument is of the form foo=bar. Separate into left and right.
+ local lhs
+ local rhs
+ IFS='=' read lhs rhs <<<"$i"
+
+ # If right-hand side already includes double quotes, do nothing
+ if [[ ! $rhs =~ \" ]]; then
+ rhs="\"${rhs}\""
+ fi
+ settings_out+=("\"${lhs}\":${rhs}")
done
- # ...and wrap inside braces.
- # FIXME: handle commas
- echo "{${settings_out[*]}}"
+ # ...and wrap inside braces, with comma separator if multiple fields
+ (IFS=','; echo "{${settings_out[*]}}")
}
#######
@@ -180,11 +184,19 @@ function t() {
local curl_args
local testname="$method $path"
- # POST requests require an extra params arg
+ # POST requests may be followed by one or more key=value pairs.
+ # Slurp the command line until we see a 3-digit status code.
if [[ $method = "POST" ]]; then
- curl_args="-d $(jsonify $1)"
+ local -a post_args
+ for arg; do
+ case "$arg" in
+ *=*) post_args+=("$arg"); shift ;;
+ [1-9][0-9][0-9]) break;;
+ *) die "Internal error: invalid POST arg '$arg'" ;;
+ esac
+ done
+ curl_args="-d $(jsonify ${post_args[@]})"
testname="$testname [$curl_args]"
- shift
fi
# entrypoint path can include a descriptive comment; strip it off
diff --git a/test/system/260-sdnotify.bats b/test/system/260-sdnotify.bats
index a5fa0f4e6..8bf49eb1d 100644
--- a/test/system/260-sdnotify.bats
+++ b/test/system/260-sdnotify.bats
@@ -42,14 +42,22 @@ function _start_socat() {
_SOCAT_LOG="$PODMAN_TMPDIR/socat.log"
rm -f $_SOCAT_LOG
- socat unix-recvfrom:"$NOTIFY_SOCKET",fork \
- system:"(cat;echo) >> $_SOCAT_LOG" &
+ # Execute in subshell so we can close fd3 (which BATS uses).
+ # This is a superstitious ritual to try to avoid leaving processes behind,
+ # and thus prevent CI hangs.
+ (exec socat unix-recvfrom:"$NOTIFY_SOCKET",fork \
+ system:"(cat;echo) >> $_SOCAT_LOG" 3>&-) &
_SOCAT_PID=$!
}
# Stop the socat background process and clean up logs
function _stop_socat() {
if [[ -n "$_SOCAT_PID" ]]; then
+ # Kill all child processes, then the process itself.
+ # This is a superstitious incantation to avoid leaving processes behind.
+ # The '|| true' is because only f35 leaves behind socat processes;
+ # f33 (and perhaps others?) behave nicely. ARGH!
+ pkill -P $_SOCAT_PID || true
kill $_SOCAT_PID
fi
_SOCAT_PID=
@@ -57,6 +65,7 @@ function _stop_socat() {
if [[ -n "$_SOCAT_LOG" ]]; then
rm -f $_SOCAT_LOG
fi
+ _SOCAT_LOG=
}
# Check that MAINPID=xxxxx points to a running conmon process