Clear available_* only when the deployed ref equals it, drop the unused poll source, stop leaking internal errors to CI, use the request-scoped logger, validate X-Request-ID, re-read jobs once after the timeout, report refused when no target ref exists, and tidy UI, deploy and docs.
73 lines
1.9 KiB
Go
73 lines
1.9 KiB
Go
package web
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/shcizo/package-updater/internal/imageref"
|
|
"github.com/shcizo/package-updater/internal/master/model"
|
|
"github.com/shcizo/package-updater/internal/protocol"
|
|
)
|
|
|
|
type serviceGroup struct {
|
|
Title string
|
|
Services []serviceRow
|
|
}
|
|
|
|
// serviceRow is a service as shown in the overview table.
|
|
type serviceRow struct {
|
|
model.Service
|
|
AutoBlocked string // why the service cannot be set to auto; "" when it can
|
|
}
|
|
|
|
// groupServices groups machine-bound services per agent and Swarm services
|
|
// in one group, keeping the store's order (machines first, Swarm last).
|
|
// autoBlocked is called for every service and returns the reason it cannot be
|
|
// set to auto, or "" when it can.
|
|
func groupServices(services []model.Service, autoBlocked func(model.Service) string) []serviceGroup {
|
|
var groups []serviceGroup
|
|
index := map[string]int{}
|
|
for _, s := range services {
|
|
title := s.AgentName
|
|
if s.Kind == protocol.KindSwarm {
|
|
title = "Swarm"
|
|
} else if title == "" {
|
|
title = "Unknown agent"
|
|
}
|
|
i, ok := index[title]
|
|
if !ok {
|
|
i = len(groups)
|
|
index[title] = i
|
|
groups = append(groups, serviceGroup{Title: title})
|
|
}
|
|
groups[i].Services = append(groups[i].Services, serviceRow{Service: s, AutoBlocked: autoBlocked(s)})
|
|
}
|
|
return groups
|
|
}
|
|
|
|
// shortRef shortens a digest in an image reference to 12 hex characters.
|
|
func shortRef(ref string) string {
|
|
r := imageref.Parse(ref)
|
|
if hex, ok := strings.CutPrefix(r.Digest, "sha256:"); ok && len(hex) > 12 {
|
|
r.Digest = "sha256:" + hex[:12] + "…"
|
|
}
|
|
return r.String()
|
|
}
|
|
|
|
type agentRow struct {
|
|
model.Agent
|
|
Online bool
|
|
}
|
|
|
|
// jobDuration is how long a job ran, or has been running; "" before it starts.
|
|
func jobDuration(j model.Job) string {
|
|
if j.StartedAt == nil {
|
|
return ""
|
|
}
|
|
end := time.Now()
|
|
if j.FinishedAt != nil {
|
|
end = *j.FinishedAt
|
|
}
|
|
return end.Sub(*j.StartedAt).Round(time.Second).String()
|
|
}
|