mirror of
https://github.com/containers/podman.git
synced 2026-10-23 10:19:13 -04:00
compat: Add a stub container/stats handler for FreeBSD
The container/stats endpoint was unimplemented. Copy over the structure from the Linux endpoint handler, albeit with most of the stats unpopulated. This is similar to how "podman stats" returns very little info on FreeBSD. On the other hand, some orchestration tools will query the stats endpoint to check liveness of a container, so it's useful to implement it even though some fields are unimplemented for now. Signed-off-by: Mark Johnston <mark.johnston@klarasystems.com>
This commit is contained in:
1 parent
6d0b28a5c4
commit
a341a4ee24
1 file changed
+122
-1
@@ -3,15 +3,136 @@
|
||||
package compat
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/containers/podman/v5/libpod"
|
||||
"github.com/containers/podman/v5/libpod/define"
|
||||
"github.com/containers/podman/v5/pkg/api/handlers/utils"
|
||||
api "github.com/containers/podman/v5/pkg/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const DefaultStatsPeriod = 5 * time.Second
|
||||
|
||||
func StatsContainer(w http.ResponseWriter, r *http.Request) {
|
||||
utils.Error(w, http.StatusBadRequest, fmt.Errorf("compat.StatsContainer not supported on FreeBSD"))
|
||||
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
|
||||
decoder := utils.GetDecoder(r)
|
||||
|
||||
query := struct {
|
||||
Stream bool `schema:"stream"`
|
||||
OneShot bool `schema:"one-shot"` // added schema for one shot
|
||||
}{
|
||||
Stream: true,
|
||||
}
|
||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
||||
utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err))
|
||||
return
|
||||
}
|
||||
if query.Stream && query.OneShot { // mismatch. one-shot can only be passed with stream=false
|
||||
utils.Error(w, http.StatusBadRequest, define.ErrInvalidArg)
|
||||
return
|
||||
}
|
||||
|
||||
name := utils.GetName(r)
|
||||
ctnr, err := runtime.LookupContainer(name)
|
||||
if err != nil {
|
||||
utils.ContainerNotFound(w, name, err)
|
||||
return
|
||||
}
|
||||
|
||||
stats, err := ctnr.GetContainerStats(nil)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, fmt.Errorf("failed to obtain Container %s stats: %w", name, err))
|
||||
return
|
||||
}
|
||||
|
||||
coder := json.NewEncoder(w)
|
||||
// Write header and content type.
|
||||
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.
|
||||
coder.SetEscapeHTML(true)
|
||||
var preRead time.Time
|
||||
var preCPUStats CPUStats
|
||||
if query.Stream {
|
||||
preRead = time.Now()
|
||||
preCPUStats = CPUStats{
|
||||
CPUUsage: container.CPUUsage{
|
||||
TotalUsage: stats.CPUNano,
|
||||
},
|
||||
CPU: stats.CPU,
|
||||
OnlineCPUs: 0,
|
||||
ThrottlingData: container.ThrottlingData{},
|
||||
}
|
||||
}
|
||||
|
||||
streamLabel: // A label to flatten the scope
|
||||
select {
|
||||
case <-r.Context().Done():
|
||||
logrus.Debugf("Client connection (container stats) cancelled")
|
||||
|
||||
default:
|
||||
stats, err = ctnr.GetContainerStats(stats)
|
||||
if err != nil {
|
||||
logrus.Errorf("Unable to get container stats: %v", err)
|
||||
return
|
||||
}
|
||||
s := StatsJSON{
|
||||
Stats: Stats{
|
||||
Read: time.Now(),
|
||||
PreRead: preRead,
|
||||
CPUStats: CPUStats{
|
||||
CPUUsage: container.CPUUsage{
|
||||
TotalUsage: stats.CPUNano,
|
||||
},
|
||||
CPU: stats.CPU,
|
||||
OnlineCPUs: 0,
|
||||
ThrottlingData: container.ThrottlingData{},
|
||||
},
|
||||
PreCPUStats: preCPUStats,
|
||||
MemoryStats: container.MemoryStats{},
|
||||
},
|
||||
Name: stats.Name,
|
||||
ID: stats.ContainerID,
|
||||
}
|
||||
|
||||
var jsonOut interface{}
|
||||
if utils.IsLibpodRequest(r) {
|
||||
jsonOut = s
|
||||
} else {
|
||||
jsonOut = DockerStatsJSON(s)
|
||||
}
|
||||
|
||||
if err := coder.Encode(jsonOut); err != nil {
|
||||
logrus.Errorf("Unable to encode stats: %v", err)
|
||||
return
|
||||
}
|
||||
if flusher, ok := w.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
|
||||
if !query.Stream || query.OneShot {
|
||||
return
|
||||
}
|
||||
|
||||
preRead = s.Read
|
||||
bits, err := json.Marshal(s.CPUStats)
|
||||
if err != nil {
|
||||
logrus.Errorf("Unable to marshal cpu stats: %q", err)
|
||||
}
|
||||
if err := json.Unmarshal(bits, &preCPUStats); err != nil {
|
||||
logrus.Errorf("Unable to unmarshal previous stats: %q", err)
|
||||
}
|
||||
|
||||
time.Sleep(DefaultStatsPeriod)
|
||||
goto streamLabel
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user