mirror of https://github.com/portainer/portainer
fix(container): apply less accurate solution to calculate container status for swarm environment [BE-12256] (#1225)
parent
eedf37d18a
commit
666d51482e
|
@ -3,6 +3,7 @@ package stats
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
|
@ -20,7 +21,11 @@ type DockerClient interface {
|
|||
ContainerInspect(ctx context.Context, containerID string) (container.InspectResponse, error)
|
||||
}
|
||||
|
||||
func CalculateContainerStats(ctx context.Context, cli DockerClient, containers []container.Summary) (ContainerStats, error) {
|
||||
func CalculateContainerStats(ctx context.Context, cli DockerClient, isSwarm bool, containers []container.Summary) (ContainerStats, error) {
|
||||
if isSwarm {
|
||||
return CalculateContainerStatsForSwarm(containers), nil
|
||||
}
|
||||
|
||||
var running, stopped, healthy, unhealthy int
|
||||
|
||||
var mu sync.Mutex
|
||||
|
@ -90,3 +95,31 @@ func getContainerStatus(state *container.State) ContainerStats {
|
|||
|
||||
return stat
|
||||
}
|
||||
|
||||
// This is a temporary workaround to calculate container stats for Swarm
|
||||
// TODO: Remove this once we have a proper way to calculate container stats for Swarm
|
||||
func CalculateContainerStatsForSwarm(containers []container.Summary) ContainerStats {
|
||||
var running, stopped, healthy, unhealthy int
|
||||
for _, container := range containers {
|
||||
switch container.State {
|
||||
case "running":
|
||||
running++
|
||||
case "exited", "stopped":
|
||||
stopped++
|
||||
}
|
||||
|
||||
if strings.Contains(container.Status, "(healthy)") {
|
||||
healthy++
|
||||
} else if strings.Contains(container.Status, "(unhealthy)") {
|
||||
unhealthy++
|
||||
}
|
||||
}
|
||||
|
||||
return ContainerStats{
|
||||
Running: running,
|
||||
Stopped: stopped,
|
||||
Healthy: healthy,
|
||||
Unhealthy: unhealthy,
|
||||
Total: len(containers),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ func TestCalculateContainerStats(t *testing.T) {
|
|||
|
||||
// Call the function and measure time
|
||||
startTime := time.Now()
|
||||
stats, err := CalculateContainerStats(context.Background(), mockClient, containers)
|
||||
stats, err := CalculateContainerStats(context.Background(), mockClient, false, containers)
|
||||
require.NoError(t, err, "failed to calculate container stats")
|
||||
duration := time.Since(startTime)
|
||||
|
||||
|
@ -120,7 +120,7 @@ func TestCalculateContainerStatsAllErrors(t *testing.T) {
|
|||
mockClient.On("ContainerInspect", mock.Anything, "container2").Return(container.InspectResponse{}, errors.New("permission denied"))
|
||||
|
||||
// Call the function
|
||||
stats, err := CalculateContainerStats(context.Background(), mockClient, containers)
|
||||
stats, err := CalculateContainerStats(context.Background(), mockClient, false, containers)
|
||||
|
||||
// Assert that an error was returned
|
||||
require.Error(t, err, "should return error when all containers fail to inspect")
|
||||
|
@ -232,3 +232,22 @@ func TestGetContainerStatus(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateContainerStatsForSwarm(t *testing.T) {
|
||||
containers := []container.Summary{
|
||||
{State: "running"},
|
||||
{State: "running", Status: "Up 5 minutes (healthy)"},
|
||||
{State: "exited"},
|
||||
{State: "stopped"},
|
||||
{State: "running", Status: "Up 10 minutes"},
|
||||
{State: "running", Status: "Up about an hour (unhealthy)"},
|
||||
}
|
||||
|
||||
stats := CalculateContainerStatsForSwarm(containers)
|
||||
|
||||
assert.Equal(t, 4, stats.Running)
|
||||
assert.Equal(t, 2, stats.Stopped)
|
||||
assert.Equal(t, 1, stats.Healthy)
|
||||
assert.Equal(t, 1, stats.Unhealthy)
|
||||
assert.Equal(t, 6, stats.Total)
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ func (h *Handler) dashboard(w http.ResponseWriter, r *http.Request) *httperror.H
|
|||
stackCount = len(stacks)
|
||||
}
|
||||
|
||||
containersStats, err := stats.CalculateContainerStats(r.Context(), cli, containers)
|
||||
containersStats, err := stats.CalculateContainerStats(r.Context(), cli, info.Swarm.ControlAvailable, containers)
|
||||
if err != nil {
|
||||
return httperror.InternalServerError("Unable to retrieve Docker containers stats", err)
|
||||
}
|
||||
|
|
|
@ -209,16 +209,16 @@ func dockerSnapshotContainers(snapshot *portainer.DockerSnapshot, cli *client.Cl
|
|||
snapshot.GpuUseAll = gpuUseAll
|
||||
snapshot.GpuUseList = gpuUseList
|
||||
|
||||
stats, err := stats.CalculateContainerStats(ctx, cli, containers)
|
||||
result, err := stats.CalculateContainerStats(ctx, cli, snapshot.Swarm, containers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to calculate container stats: %w", err)
|
||||
}
|
||||
|
||||
snapshot.ContainerCount = stats.Total
|
||||
snapshot.RunningContainerCount = stats.Running
|
||||
snapshot.StoppedContainerCount = stats.Stopped
|
||||
snapshot.HealthyContainerCount = stats.Healthy
|
||||
snapshot.UnhealthyContainerCount = stats.Unhealthy
|
||||
snapshot.ContainerCount = result.Total
|
||||
snapshot.RunningContainerCount = result.Running
|
||||
snapshot.StoppedContainerCount = result.Stopped
|
||||
snapshot.HealthyContainerCount = result.Healthy
|
||||
snapshot.UnhealthyContainerCount = result.Unhealthy
|
||||
snapshot.StackCount += len(stacks)
|
||||
|
||||
for _, container := range containers {
|
||||
|
|
Loading…
Reference in New Issue