api: use singleflight for /info endpoint
Prevent potential suggestion when many concurrent requests happen on the /info endpoint. It's worth noting that with this change, requests to the endpoint while another request is still in flight will share the results, hence might be slightly incorrect (for example, the output includes SystemTime, which may now be incorrect). Assuming that under normal circumstances, requests will still happen fast enough to not be shared, this may not be a problem, but we could decide to update specific fields to not be shared. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
20364bd658
commit
a1c9a686b0
2 changed files with 37 additions and 27 deletions
|
@ -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
|
||||
|
|
|
@ -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 = "<not supported>" //nolint:staticcheck // ignore SA1019 (ExecutionDriver is deprecated)
|
||||
}
|
||||
info.SecurityOptions = nameOnly
|
||||
info.ExecutionDriver = "<not supported>" //nolint:staticcheck // ignore SA1019 (ExecutionDriver is deprecated)
|
||||
}
|
||||
if versions.LessThan(version, "1.39") {
|
||||
if info.KernelVersion == "" {
|
||||
info.KernelVersion = "<unknown>"
|
||||
if versions.LessThan(version, "1.39") {
|
||||
if info.KernelVersion == "" {
|
||||
info.KernelVersion = "<unknown>"
|
||||
}
|
||||
if info.OperatingSystem == "" {
|
||||
info.OperatingSystem = "<unknown>"
|
||||
}
|
||||
}
|
||||
if info.OperatingSystem == "" {
|
||||
info.OperatingSystem = "<unknown>"
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue