mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-04-26 10:31:17 +00:00
Use node-local counts for node-scoped swarm services
This commit is contained in:
parent
aa69bd2d8e
commit
48bdfdc30b
2 changed files with 133 additions and 6 deletions
|
|
@ -195,19 +195,38 @@ func (a *Agent) collectSwarmDataFromManager(ctx context.Context, info systemtype
|
|||
}
|
||||
|
||||
if scope == swarmScopeNode && includeServices && len(services) > 0 {
|
||||
used := make(map[string]struct{}, len(tasks))
|
||||
countsByService := make(map[string]agentsdocker.Service, len(services))
|
||||
for _, task := range tasks {
|
||||
// Only count running tasks - ignore shutdown/historical tasks
|
||||
if task.ServiceID != "" && strings.ToLower(task.DesiredState) == "running" {
|
||||
used[task.ServiceID] = struct{}{}
|
||||
if task.ServiceID == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
counts := countsByService[task.ServiceID]
|
||||
counts.ID = task.ServiceID
|
||||
if task.ServiceName != "" {
|
||||
counts.Name = task.ServiceName
|
||||
}
|
||||
counts.DesiredTasks++
|
||||
if strings.EqualFold(task.CurrentState, "running") {
|
||||
counts.RunningTasks++
|
||||
}
|
||||
if isTaskCompletedState(task.CurrentState) {
|
||||
counts.CompletedTasks++
|
||||
}
|
||||
countsByService[task.ServiceID] = counts
|
||||
}
|
||||
|
||||
filtered := services[:0]
|
||||
for _, svc := range services {
|
||||
if _, ok := used[svc.ID]; ok || len(used) == 0 {
|
||||
filtered = append(filtered, svc)
|
||||
counts, ok := countsByService[svc.ID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
svc.DesiredTasks = counts.DesiredTasks
|
||||
svc.RunningTasks = counts.RunningTasks
|
||||
svc.CompletedTasks = counts.CompletedTasks
|
||||
filtered = append(filtered, svc)
|
||||
}
|
||||
services = filtered
|
||||
}
|
||||
|
|
|
|||
|
|
@ -276,6 +276,114 @@ func TestCollectSwarmDataFromManager(t *testing.T) {
|
|||
t.Fatalf("expected services only on task error")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("node scope uses local task counts for services", func(t *testing.T) {
|
||||
agent := &Agent{
|
||||
docker: &fakeDockerClient{
|
||||
serviceListFn: func(_ context.Context, _ serviceListOptions) ([]swarmtypes.Service, error) {
|
||||
return []swarmtypes.Service{
|
||||
{
|
||||
ID: "svc1",
|
||||
Spec: swarmtypes.ServiceSpec{
|
||||
Annotations: swarmtypes.Annotations{Name: "alpha"},
|
||||
},
|
||||
ServiceStatus: &swarmtypes.ServiceStatus{
|
||||
DesiredTasks: 4,
|
||||
RunningTasks: 3,
|
||||
CompletedTasks: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "svc2",
|
||||
Spec: swarmtypes.ServiceSpec{
|
||||
Annotations: swarmtypes.Annotations{Name: "beta"},
|
||||
},
|
||||
ServiceStatus: &swarmtypes.ServiceStatus{
|
||||
DesiredTasks: 2,
|
||||
RunningTasks: 2,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
taskListFn: func(_ context.Context, _ taskListOptions) ([]swarmtypes.Task, error) {
|
||||
return []swarmtypes.Task{
|
||||
{
|
||||
ID: "task1",
|
||||
ServiceID: "svc1",
|
||||
DesiredState: swarmtypes.TaskStateRunning,
|
||||
Status: swarmtypes.TaskStatus{
|
||||
State: swarmtypes.TaskStateRunning,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "task2",
|
||||
ServiceID: "svc1",
|
||||
DesiredState: swarmtypes.TaskStateRunning,
|
||||
Status: swarmtypes.TaskStatus{
|
||||
State: swarmtypes.TaskStatePreparing,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
info := systemtypes.Info{
|
||||
Swarm: swarmtypes.Info{
|
||||
NodeID: "node1",
|
||||
},
|
||||
}
|
||||
|
||||
services, tasks, err := agent.collectSwarmDataFromManager(context.Background(), info, swarmScopeNode, nil, true, true)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if len(tasks) != 2 {
|
||||
t.Fatalf("expected 2 local tasks, got %d", len(tasks))
|
||||
}
|
||||
if len(services) != 1 {
|
||||
t.Fatalf("expected only local services, got %d", len(services))
|
||||
}
|
||||
if services[0].ID != "svc1" {
|
||||
t.Fatalf("expected local service svc1, got %+v", services[0])
|
||||
}
|
||||
if services[0].DesiredTasks != 2 || services[0].RunningTasks != 1 || services[0].CompletedTasks != 0 {
|
||||
t.Fatalf("expected node-local task counts, got %+v", services[0])
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("node scope drops services when no local runtime tasks remain", func(t *testing.T) {
|
||||
agent := &Agent{
|
||||
docker: &fakeDockerClient{
|
||||
serviceListFn: func(_ context.Context, _ serviceListOptions) ([]swarmtypes.Service, error) {
|
||||
return []swarmtypes.Service{
|
||||
{ID: "svc1", Spec: swarmtypes.ServiceSpec{Annotations: swarmtypes.Annotations{Name: "alpha"}}},
|
||||
{ID: "svc2", Spec: swarmtypes.ServiceSpec{Annotations: swarmtypes.Annotations{Name: "beta"}}},
|
||||
}, nil
|
||||
},
|
||||
taskListFn: func(_ context.Context, _ taskListOptions) ([]swarmtypes.Task, error) {
|
||||
return []swarmtypes.Task{}, nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
info := systemtypes.Info{
|
||||
Swarm: swarmtypes.Info{
|
||||
NodeID: "node1",
|
||||
},
|
||||
}
|
||||
|
||||
services, tasks, err := agent.collectSwarmDataFromManager(context.Background(), info, swarmScopeNode, nil, true, true)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if len(tasks) != 0 {
|
||||
t.Fatalf("expected no local tasks, got %d", len(tasks))
|
||||
}
|
||||
if len(services) != 0 {
|
||||
t.Fatalf("expected no node-scoped services without local tasks, got %d", len(services))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestIsRuntimeSwarmTask(t *testing.T) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue