Fix: use --all in podman stats to get all containers stats

* Set query all when options.All is true
* Update API to support the "all" option in stats

Signed-off-by: Boaz Shuster <boaz.shuster.github@gmail.com>
This commit is contained in:
Boaz Shuster 2023-07-16 22:43:26 +03:00
parent 1f455cf619
commit de122bb44e
8 changed files with 64 additions and 4 deletions

View File

@ -120,6 +120,7 @@ func stats(cmd *cobra.Command, args []string) error {
Latest: statsOptions.Latest, Latest: statsOptions.Latest,
Stream: !statsOptions.NoStream, Stream: !statsOptions.NoStream,
Interval: statsOptions.Interval, Interval: statsOptions.Interval,
All: statsOptions.All,
} }
args = putils.RemoveSlash(args) args = putils.RemoveSlash(args)
statsChan, err := registry.ContainerEngine().ContainerStats(registry.Context(), args, opts) statsChan, err := registry.ContainerEngine().ContainerStats(registry.Context(), args, opts)

View File

@ -34,9 +34,11 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
Containers []string `schema:"containers"` Containers []string `schema:"containers"`
Stream bool `schema:"stream"` Stream bool `schema:"stream"`
Interval int `schema:"interval"` Interval int `schema:"interval"`
All bool `schema:"all"`
}{ }{
Stream: true, Stream: true,
Interval: 5, Interval: 5,
All: false,
} }
if err := decoder.Decode(&query, r.URL.Query()); err != nil { 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)) utils.Error(w, http.StatusBadRequest, fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err))
@ -50,6 +52,7 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
statsOptions := entities.ContainerStatsOptions{ statsOptions := entities.ContainerStatsOptions{
Stream: query.Stream, Stream: query.Stream,
Interval: query.Interval, Interval: query.Interval,
All: query.All,
} }
// Stats will stop if the connection is closed. // Stats will stop if the connection is closed.

View File

@ -208,6 +208,7 @@ type StartOptions struct {
// //
//go:generate go run ../generator/generator.go StatsOptions //go:generate go run ../generator/generator.go StatsOptions
type StatsOptions struct { type StatsOptions struct {
All *bool
Stream *bool Stream *bool
Interval *int Interval *int
} }

View File

@ -17,6 +17,21 @@ func (o *StatsOptions) ToParams() (url.Values, error) {
return util.ToParams(o) return util.ToParams(o)
} }
// WithAll set field All to given value
func (o *StatsOptions) WithAll(value bool) *StatsOptions {
o.All = &value
return o
}
// GetAll returns value of field All
func (o *StatsOptions) GetAll() bool {
if o.All == nil {
var z bool
return z
}
return *o.All
}
// WithStream set field Stream to given value // WithStream set field Stream to given value
func (o *StatsOptions) WithStream(value bool) *StatsOptions { func (o *StatsOptions) WithStream(value bool) *StatsOptions {
o.Stream = &value o.Stream = &value

View File

@ -472,6 +472,8 @@ type ContainerCpOptions struct {
// ContainerStatsOptions describes input options for getting // ContainerStatsOptions describes input options for getting
// stats on containers // stats on containers
type ContainerStatsOptions struct { type ContainerStatsOptions struct {
// Get all containers stats
All bool
// Operate on the latest known container. Only supported for local // Operate on the latest known container. Only supported for local
// clients. // clients.
Latest bool Latest bool

View File

@ -1526,7 +1526,7 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
} }
statsChan = make(chan entities.ContainerStatsReport, 1) statsChan = make(chan entities.ContainerStatsReport, 1)
containerFunc := ic.Libpod.GetRunningContainers var containerFunc func() ([]*libpod.Container, error)
queryAll := false queryAll := false
switch { switch {
case options.Latest: case options.Latest:
@ -1539,10 +1539,14 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
} }
case len(namesOrIds) > 0: case len(namesOrIds) > 0:
containerFunc = func() ([]*libpod.Container, error) { return ic.Libpod.GetContainersByList(namesOrIds) } containerFunc = func() ([]*libpod.Container, error) { return ic.Libpod.GetContainersByList(namesOrIds) }
default: case options.All:
// No containers, no latest -> query all!
queryAll = true queryAll = true
containerFunc = ic.Libpod.GetAllContainers containerFunc = ic.Libpod.GetAllContainers
default:
// queryAll is used to ignore errors when the container was removed between listing and
// checking stats which we should do for running containers as well
queryAll = true
containerFunc = ic.Libpod.GetRunningContainers
} }
go func() { go func() {

View File

@ -1049,7 +1049,7 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
if options.Latest { if options.Latest {
return nil, errors.New("latest is not supported for the remote client") return nil, errors.New("latest is not supported for the remote client")
} }
return containers.Stats(ic.ClientCtx, namesOrIds, new(containers.StatsOptions).WithStream(options.Stream).WithInterval(options.Interval)) return containers.Stats(ic.ClientCtx, namesOrIds, new(containers.StatsOptions).WithStream(options.Stream).WithInterval(options.Interval).WithAll(options.All))
} }
// ShouldRestart reports back whether the container will restart. // ShouldRestart reports back whether the container will restart.

View File

@ -264,4 +264,38 @@ var _ = Describe("Podman stats", func() {
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(limit).To(BeNumerically("==", 100*1024*1024)) Expect(limit).To(BeNumerically("==", 100*1024*1024))
}) })
It("podman stats --all", func() {
runningContainersession := podmanTest.RunTopContainer("")
runningContainersession.WaitWithDefaultTimeout()
Expect(runningContainersession).Should(Exit(0))
runningCtrID := runningContainersession.OutputToString()[0:12]
createdContainerSession, _, _ := podmanTest.CreatePod(map[string][]string{
"--infra": {"true"},
})
createdContainerSession.WaitWithDefaultTimeout()
Expect(createdContainerSession).Should(Exit(0))
sessionAll := podmanTest.Podman([]string{"stats", "--no-stream", "--format", "{{.ID}}"})
sessionAll.WaitWithDefaultTimeout()
Expect(sessionAll).Should(Exit(0))
Expect(sessionAll.OutputToString()).Should(Equal(runningCtrID))
sessionAll = podmanTest.Podman([]string{"stats", "--no-stream", "--all=false", "--format", "{{.ID}}"})
sessionAll.WaitWithDefaultTimeout()
Expect(sessionAll).Should(Exit(0))
Expect(sessionAll.OutputToString()).Should(Equal(runningCtrID))
sessionAll = podmanTest.Podman([]string{"stats", "--all=true", "--no-stream", "--format", "{{.ID}}"})
sessionAll.WaitWithDefaultTimeout()
Expect(sessionAll).Should(Exit(0))
Expect(sessionAll.OutputToStringArray()).Should(HaveLen(2))
sessionAll = podmanTest.Podman([]string{"stats", "--all", "--no-stream", "--format", "{{.ID}}"})
sessionAll.WaitWithDefaultTimeout()
Expect(sessionAll).Should(Exit(0))
Expect(sessionAll.OutputToStringArray()).Should(HaveLen(2))
})
}) })