mirror of
https://github.com/containers/podman.git
synced 2025-06-29 23:22:40 +08:00
Fail earlier when no containers exist in stats
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
@ -62,18 +62,23 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write header and content type.
|
wroteContent := false
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
if flusher, ok := w.(http.Flusher); ok {
|
|
||||||
flusher.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up JSON encoder for streaming.
|
// Set up JSON encoder for streaming.
|
||||||
coder := json.NewEncoder(w)
|
coder := json.NewEncoder(w)
|
||||||
coder.SetEscapeHTML(true)
|
coder.SetEscapeHTML(true)
|
||||||
|
|
||||||
for stats := range statsChan {
|
for stats := range statsChan {
|
||||||
|
if !wroteContent {
|
||||||
|
if stats.Error != nil {
|
||||||
|
utils.ContainerNotFound(w, "", stats.Error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Write header and content type.
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
wroteContent = true
|
||||||
|
}
|
||||||
|
|
||||||
if err := coder.Encode(stats); err != nil {
|
if err := coder.Encode(stats); err != nil {
|
||||||
// Note: even when streaming, the stats goroutine will
|
// Note: even when streaming, the stats goroutine will
|
||||||
// be notified (and stop) as the connection will be
|
// be notified (and stop) as the connection will be
|
||||||
|
@ -1571,12 +1571,7 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(statsChan)
|
defer close(statsChan)
|
||||||
var (
|
containerStats := make(map[string]*define.ContainerStats)
|
||||||
err error
|
|
||||||
containers []*libpod.Container
|
|
||||||
containerStats map[string]*define.ContainerStats
|
|
||||||
)
|
|
||||||
containerStats = make(map[string]*define.ContainerStats)
|
|
||||||
|
|
||||||
stream: // label to flatten the scope
|
stream: // label to flatten the scope
|
||||||
select {
|
select {
|
||||||
@ -1590,7 +1585,7 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
|
|||||||
|
|
||||||
// Anonymous func to easily use the return values for streaming.
|
// Anonymous func to easily use the return values for streaming.
|
||||||
computeStats := func() ([]define.ContainerStats, error) {
|
computeStats := func() ([]define.ContainerStats, error) {
|
||||||
containers, err = containerFunc()
|
containers, err := containerFunc()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to get list of containers: %w", err)
|
return nil, fmt.Errorf("unable to get list of containers: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -112,21 +112,8 @@ t GET libpod/containers/json?last=1 200 \
|
|||||||
|
|
||||||
cid=$(jq -r '.[0].Id' <<<"$output")
|
cid=$(jq -r '.[0].Id' <<<"$output")
|
||||||
|
|
||||||
if root; then
|
t GET "libpod/containers/stats?containers=$cid&stream=false" 200 \
|
||||||
t GET libpod/containers/stats?containers='[$cid]' 200
|
.memory_stats.max_usage=null
|
||||||
else
|
|
||||||
if have_cgroupsv2; then
|
|
||||||
t GET libpod/containers/stats?containers='[$cid]' 200
|
|
||||||
else
|
|
||||||
t GET libpod/containers/stats?containers='[$cid]' 409
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# max_usage is not set for cgroupv2
|
|
||||||
if have_cgroupsv2; then
|
|
||||||
t GET libpod/containers/stats?containers='[$cid]' 200 \
|
|
||||||
.memory_stats.max_usage=null
|
|
||||||
fi
|
|
||||||
|
|
||||||
t DELETE libpod/containers/$cid 200 .[0].Id=$cid
|
t DELETE libpod/containers/$cid 200 .[0].Id=$cid
|
||||||
|
|
||||||
@ -241,20 +228,13 @@ t GET libpod/images/newrepo:v1/json 200 \
|
|||||||
cparam="repo=newrepo&tag=v2&comment=bar&author=eric"
|
cparam="repo=newrepo&tag=v2&comment=bar&author=eric"
|
||||||
cparam="$cparam&format=docker&changes=CMD=/bin/foo"
|
cparam="$cparam&format=docker&changes=CMD=/bin/foo"
|
||||||
|
|
||||||
if root || have_cgroupsv2; then
|
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 \
|
||||||
t GET libpod/images/newrepo:v2/json 200 \
|
.RepoTags[0]=localhost/newrepo:v2 \
|
||||||
.RepoTags[0]=localhost/newrepo:v2 \
|
.Author=eric \
|
||||||
.Author=eric \
|
.Comment=bar \
|
||||||
.Comment=bar \
|
.Config.Cmd[-1]="/bin/foo"
|
||||||
.Config.Cmd[-1]="/bin/foo"
|
t DELETE images/localhost/newrepo:v2?force=true 200
|
||||||
t DELETE images/localhost/newrepo:v2?force=true 200
|
|
||||||
else
|
|
||||||
# cgroupsv1 rootless : pause is not supported in cgroups v1 rootless
|
|
||||||
t POST "libpod/commit?container=${cid:0:12}&$cparam&pause=true" 500 \
|
|
||||||
.cause="this container does not have a cgroup" \
|
|
||||||
.message~".*pause containers on rootless containers with cgroup V1"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create a container for testing the container initializing later
|
# Create a container for testing the container initializing later
|
||||||
podman create -t -i --name myctr $IMAGE ls
|
podman create -t -i --name myctr $IMAGE ls
|
||||||
@ -484,24 +464,8 @@ t POST containers/prune?filters='{"network":["anynetwork"]}' 500 \
|
|||||||
|
|
||||||
# Test CPU limit (NanoCPUs)
|
# Test CPU limit (NanoCPUs)
|
||||||
nanoCpu=500000
|
nanoCpu=500000
|
||||||
if have_cgroupsv2; then
|
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\\}
|
||||||
.Id~[0-9a-f]\\{64\\}
|
|
||||||
else
|
|
||||||
if root; then
|
|
||||||
# cgroupsv1 rootful : NanoCpus needs to set more than 10000000
|
|
||||||
t POST containers/create Image=$IMAGE HostConfig='{"NanoCpus":500000}' 500 \
|
|
||||||
.cause="CPU cfs quota cannot be less than 1ms (i.e. 1000)"
|
|
||||||
t POST containers/create Image=$IMAGE HostConfig='{"NanoCpus":10000000}' 201 \
|
|
||||||
.Id~[0-9a-f]\\{64\\}
|
|
||||||
nanoCpu=10000000
|
|
||||||
else
|
|
||||||
# cgroupsv1 rootless : Resource limits that include NanoCPUs are not supported and ignored
|
|
||||||
t POST containers/create Image=$IMAGE HostConfig='{"NanoCpus":500000}' 201 \
|
|
||||||
.Id~[0-9a-f]\\{64\\}
|
|
||||||
nanoCpu=0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
cid=$(jq -r '.Id' <<<"$output")
|
cid=$(jq -r '.Id' <<<"$output")
|
||||||
t GET containers/$cid/json 200 \
|
t GET containers/$cid/json 200 \
|
||||||
@ -677,14 +641,11 @@ t GET containers/status-test/json 200 .State.Status="created"
|
|||||||
podman start status-test
|
podman start status-test
|
||||||
t GET containers/status-test/json 200 .State.Status="running"
|
t GET containers/status-test/json 200 .State.Status="running"
|
||||||
|
|
||||||
# cgroupsv1 rootless : pause and unpause are not supported in cgroups v1 rootless
|
podman pause status-test
|
||||||
if root || have_cgroupsv2; then
|
t GET containers/status-test/json 200 .State.Status="paused"
|
||||||
podman pause status-test
|
|
||||||
t GET containers/status-test/json 200 .State.Status="paused"
|
|
||||||
|
|
||||||
podman unpause status-test
|
podman unpause status-test
|
||||||
t GET containers/status-test/json 200 .State.Status="running"
|
t GET containers/status-test/json 200 .State.Status="running"
|
||||||
fi
|
|
||||||
|
|
||||||
podman stop status-test &
|
podman stop status-test &
|
||||||
sleep 1
|
sleep 1
|
||||||
@ -718,11 +679,6 @@ if root; then
|
|||||||
cgroupPath=/sys/fs/cgroup/cpu.weight
|
cgroupPath=/sys/fs/cgroup/cpu.weight
|
||||||
# 002 is the byte length
|
# 002 is the byte length
|
||||||
cpu_weight_expect=$'\001\0025'
|
cpu_weight_expect=$'\001\0025'
|
||||||
if ! have_cgroupsv2; then
|
|
||||||
cgroupPath=/sys/fs/cgroup/cpu/cpu.shares
|
|
||||||
# 004 is the byte length
|
|
||||||
cpu_weight_expect=$'\001\004123'
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verify
|
# Verify
|
||||||
echo '{ "AttachStdout":true,"Cmd":["cat", "'$cgroupPath'"]}' >${TMPD}/exec.json
|
echo '{ "AttachStdout":true,"Cmd":["cat", "'$cgroupPath'"]}' >${TMPD}/exec.json
|
||||||
|
@ -24,12 +24,7 @@ var _ = Describe("Podman stats", func() {
|
|||||||
It("podman stats with bogus container", func() {
|
It("podman stats with bogus container", func() {
|
||||||
session := podmanTest.Podman([]string{"stats", "--no-stream", "123"})
|
session := podmanTest.Podman([]string{"stats", "--no-stream", "123"})
|
||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
expect := `unable to get list of containers: unable to look up container 123: no container with name or ID "123" found: no such container`
|
Expect(session).Should(ExitWithError(125, `unable to get list of containers: unable to look up container 123: no container with name or ID "123" found: no such container`))
|
||||||
// FIXME: #22612
|
|
||||||
if IsRemote() {
|
|
||||||
expect = "types.ContainerStatsReport.Error: decode non empty interface: can not unmarshal into nil, error found in #9 byte"
|
|
||||||
}
|
|
||||||
Expect(session).Should(ExitWithError(125, expect))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman stats on a running container", func() {
|
It("podman stats on a running container", func() {
|
||||||
|
Reference in New Issue
Block a user