diff --git a/api/server/router/system/system.go b/api/server/router/system/system.go index 8235abf686..0bc85c602b 100644 --- a/api/server/router/system/system.go +++ b/api/server/router/system/system.go @@ -2,7 +2,9 @@ package system // import "github.com/docker/docker/api/server/router/system" import ( "github.com/docker/docker/api/server/router" + "github.com/docker/docker/api/types" buildkit "github.com/docker/docker/builder/builder-next" + "resenje.org/singleflight" ) // systemRouter provides information about the Docker system overall. @@ -13,6 +15,11 @@ type systemRouter struct { routes []router.Route builder *buildkit.Builder features func() map[string]bool + + // collectSystemInfo is a single-flight for the /info endpoint, + // unique per API version (as different API versions may return + // a different API response). + collectSystemInfo singleflight.Group[string, *types.Info] } // NewRouter initializes a new system router diff --git a/api/server/router/system/system_routes.go b/api/server/router/system/system_routes.go index c7902e1f9a..560b972bf9 100644 --- a/api/server/router/system/system_routes.go +++ b/api/server/router/system/system_routes.go @@ -57,38 +57,41 @@ func (s *systemRouter) swarmStatus() string { } func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { - info := s.backend.SystemInfo() - - if s.cluster != nil { - info.Swarm = s.cluster.Info() - info.Warnings = append(info.Warnings, info.Swarm.Warnings...) - } - version := httputils.VersionFromContext(ctx) - if versions.LessThan(version, "1.25") { - // TODO: handle this conversion in engine-api - kvSecOpts, err := types.DecodeSecurityOptions(info.SecurityOptions) - if err != nil { - info.Warnings = append(info.Warnings, err.Error()) + info, _, _ := s.collectSystemInfo.Do(ctx, version, func(ctx context.Context) (*types.Info, error) { + info := s.backend.SystemInfo() + + if s.cluster != nil { + info.Swarm = s.cluster.Info() + info.Warnings = append(info.Warnings, info.Swarm.Warnings...) } - var nameOnly []string - for _, so := range kvSecOpts { - nameOnly = append(nameOnly, so.Name) + + if versions.LessThan(version, "1.25") { + // TODO: handle this conversion in engine-api + kvSecOpts, err := types.DecodeSecurityOptions(info.SecurityOptions) + if err != nil { + info.Warnings = append(info.Warnings, err.Error()) + } + var nameOnly []string + for _, so := range kvSecOpts { + nameOnly = append(nameOnly, so.Name) + } + info.SecurityOptions = nameOnly + info.ExecutionDriver = "" //nolint:staticcheck // ignore SA1019 (ExecutionDriver is deprecated) } - info.SecurityOptions = nameOnly - info.ExecutionDriver = "" //nolint:staticcheck // ignore SA1019 (ExecutionDriver is deprecated) - } - if versions.LessThan(version, "1.39") { - if info.KernelVersion == "" { - info.KernelVersion = "" + if versions.LessThan(version, "1.39") { + if info.KernelVersion == "" { + info.KernelVersion = "" + } + if info.OperatingSystem == "" { + info.OperatingSystem = "" + } } - if info.OperatingSystem == "" { - info.OperatingSystem = "" + if versions.GreaterThanOrEqualTo(version, "1.42") { + info.KernelMemory = false } - } - if versions.GreaterThanOrEqualTo(version, "1.42") { - info.KernelMemory = false - } + return info, nil + }) return httputils.WriteJSON(w, http.StatusOK, info) }