mirror of https://github.com/portainer/portainer
93 lines
1.8 KiB
Go
93 lines
1.8 KiB
Go
package stats
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sync"
|
|
|
|
"github.com/docker/docker/api/types/container"
|
|
)
|
|
|
|
type ContainerStats struct {
|
|
Running int `json:"running"`
|
|
Stopped int `json:"stopped"`
|
|
Healthy int `json:"healthy"`
|
|
Unhealthy int `json:"unhealthy"`
|
|
Total int `json:"total"`
|
|
}
|
|
|
|
type DockerClient interface {
|
|
ContainerInspect(ctx context.Context, containerID string) (container.InspectResponse, error)
|
|
}
|
|
|
|
func CalculateContainerStats(ctx context.Context, cli DockerClient, containers []container.Summary) (ContainerStats, error) {
|
|
var running, stopped, healthy, unhealthy int
|
|
|
|
var mu sync.Mutex
|
|
var wg sync.WaitGroup
|
|
semaphore := make(chan struct{}, 5)
|
|
|
|
var aggErr error
|
|
var aggMu sync.Mutex
|
|
|
|
for i := range containers {
|
|
id := containers[i].ID
|
|
semaphore <- struct{}{}
|
|
wg.Go(func() {
|
|
defer func() { <-semaphore }()
|
|
|
|
containerInspection, err := cli.ContainerInspect(ctx, id)
|
|
stat := ContainerStats{}
|
|
if err != nil {
|
|
aggMu.Lock()
|
|
aggErr = errors.Join(aggErr, err)
|
|
aggMu.Unlock()
|
|
return
|
|
}
|
|
stat = getContainerStatus(containerInspection.State)
|
|
|
|
mu.Lock()
|
|
running += stat.Running
|
|
stopped += stat.Stopped
|
|
healthy += stat.Healthy
|
|
unhealthy += stat.Unhealthy
|
|
mu.Unlock()
|
|
})
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
return ContainerStats{
|
|
Running: running,
|
|
Stopped: stopped,
|
|
Healthy: healthy,
|
|
Unhealthy: unhealthy,
|
|
Total: len(containers),
|
|
}, aggErr
|
|
}
|
|
|
|
func getContainerStatus(state *container.State) ContainerStats {
|
|
stat := ContainerStats{}
|
|
if state == nil {
|
|
return stat
|
|
}
|
|
|
|
switch state.Status {
|
|
case container.StateRunning:
|
|
stat.Running++
|
|
case container.StateExited, container.StateDead:
|
|
stat.Stopped++
|
|
}
|
|
|
|
if state.Health != nil {
|
|
switch state.Health.Status {
|
|
case container.Healthy:
|
|
stat.Healthy++
|
|
case container.Unhealthy:
|
|
stat.Unhealthy++
|
|
}
|
|
}
|
|
|
|
return stat
|
|
}
|