github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/api/server/router/system/system_routes.go (about) 1 package system // import "github.com/docker/docker/api/server/router/system" 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "time" 9 10 "github.com/docker/docker/api/server/httputils" 11 "github.com/docker/docker/api/server/router/build" 12 "github.com/docker/docker/api/types" 13 "github.com/docker/docker/api/types/events" 14 "github.com/docker/docker/api/types/filters" 15 "github.com/docker/docker/api/types/registry" 16 timetypes "github.com/docker/docker/api/types/time" 17 "github.com/docker/docker/api/types/versions" 18 "github.com/docker/docker/pkg/ioutils" 19 pkgerrors "github.com/pkg/errors" 20 "github.com/sirupsen/logrus" 21 "golang.org/x/sync/errgroup" 22 ) 23 24 func optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 25 w.WriteHeader(http.StatusOK) 26 return nil 27 } 28 29 func (s *systemRouter) pingHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 30 w.Header().Add("Cache-Control", "no-cache, no-store, must-revalidate") 31 w.Header().Add("Pragma", "no-cache") 32 33 builderVersion := build.BuilderVersion(*s.features) 34 if bv := builderVersion; bv != "" { 35 w.Header().Set("Builder-Version", string(bv)) 36 } 37 if r.Method == http.MethodHead { 38 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 39 w.Header().Set("Content-Length", "0") 40 return nil 41 } 42 _, err := w.Write([]byte{'O', 'K'}) 43 return err 44 } 45 46 func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 47 info := s.backend.SystemInfo() 48 49 if s.cluster != nil { 50 info.Swarm = s.cluster.Info() 51 info.Warnings = append(info.Warnings, info.Swarm.Warnings...) 52 } 53 54 if versions.LessThan(httputils.VersionFromContext(ctx), "1.25") { 55 // TODO: handle this conversion in engine-api 56 type oldInfo struct { 57 *types.Info 58 ExecutionDriver string 59 } 60 old := &oldInfo{ 61 Info: info, 62 ExecutionDriver: "<not supported>", 63 } 64 nameOnlySecurityOptions := []string{} 65 kvSecOpts, err := types.DecodeSecurityOptions(old.SecurityOptions) 66 if err != nil { 67 return err 68 } 69 for _, s := range kvSecOpts { 70 nameOnlySecurityOptions = append(nameOnlySecurityOptions, s.Name) 71 } 72 old.SecurityOptions = nameOnlySecurityOptions 73 return httputils.WriteJSON(w, http.StatusOK, old) 74 } 75 if versions.LessThan(httputils.VersionFromContext(ctx), "1.39") { 76 if info.KernelVersion == "" { 77 info.KernelVersion = "<unknown>" 78 } 79 if info.OperatingSystem == "" { 80 info.OperatingSystem = "<unknown>" 81 } 82 } 83 return httputils.WriteJSON(w, http.StatusOK, info) 84 } 85 86 func (s *systemRouter) getVersion(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 87 info := s.backend.SystemVersion() 88 89 return httputils.WriteJSON(w, http.StatusOK, info) 90 } 91 92 func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 93 eg, ctx := errgroup.WithContext(ctx) 94 95 var du *types.DiskUsage 96 eg.Go(func() error { 97 var err error 98 du, err = s.backend.SystemDiskUsage(ctx) 99 return err 100 }) 101 102 var buildCache []*types.BuildCache 103 eg.Go(func() error { 104 var err error 105 buildCache, err = s.builder.DiskUsage(ctx) 106 if err != nil { 107 return pkgerrors.Wrap(err, "error getting build cache usage") 108 } 109 return nil 110 }) 111 112 if err := eg.Wait(); err != nil { 113 return err 114 } 115 116 var builderSize int64 117 for _, b := range buildCache { 118 builderSize += b.Size 119 } 120 121 du.BuilderSize = builderSize 122 du.BuildCache = buildCache 123 124 return httputils.WriteJSON(w, http.StatusOK, du) 125 } 126 127 type invalidRequestError struct { 128 Err error 129 } 130 131 func (e invalidRequestError) Error() string { 132 return e.Err.Error() 133 } 134 135 func (e invalidRequestError) InvalidParameter() {} 136 137 func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 138 if err := httputils.ParseForm(r); err != nil { 139 return err 140 } 141 142 since, err := eventTime(r.Form.Get("since")) 143 if err != nil { 144 return err 145 } 146 until, err := eventTime(r.Form.Get("until")) 147 if err != nil { 148 return err 149 } 150 151 var ( 152 timeout <-chan time.Time 153 onlyPastEvents bool 154 ) 155 if !until.IsZero() { 156 if until.Before(since) { 157 return invalidRequestError{fmt.Errorf("`since` time (%s) cannot be after `until` time (%s)", r.Form.Get("since"), r.Form.Get("until"))} 158 } 159 160 now := time.Now() 161 162 onlyPastEvents = until.Before(now) 163 164 if !onlyPastEvents { 165 dur := until.Sub(now) 166 timer := time.NewTimer(dur) 167 defer timer.Stop() 168 timeout = timer.C 169 } 170 } 171 172 ef, err := filters.FromJSON(r.Form.Get("filters")) 173 if err != nil { 174 return err 175 } 176 177 w.Header().Set("Content-Type", "application/json") 178 output := ioutils.NewWriteFlusher(w) 179 defer output.Close() 180 output.Flush() 181 182 enc := json.NewEncoder(output) 183 184 buffered, l := s.backend.SubscribeToEvents(since, until, ef) 185 defer s.backend.UnsubscribeFromEvents(l) 186 187 for _, ev := range buffered { 188 if err := enc.Encode(ev); err != nil { 189 return err 190 } 191 } 192 193 if onlyPastEvents { 194 return nil 195 } 196 197 for { 198 select { 199 case ev := <-l: 200 jev, ok := ev.(events.Message) 201 if !ok { 202 logrus.Warnf("unexpected event message: %q", ev) 203 continue 204 } 205 if err := enc.Encode(jev); err != nil { 206 return err 207 } 208 case <-timeout: 209 return nil 210 case <-ctx.Done(): 211 logrus.Debug("Client context cancelled, stop sending events") 212 return nil 213 } 214 } 215 } 216 217 func (s *systemRouter) postAuth(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 218 var config *types.AuthConfig 219 err := json.NewDecoder(r.Body).Decode(&config) 220 r.Body.Close() 221 if err != nil { 222 return err 223 } 224 status, token, err := s.backend.AuthenticateToRegistry(ctx, config) 225 if err != nil { 226 return err 227 } 228 return httputils.WriteJSON(w, http.StatusOK, ®istry.AuthenticateOKBody{ 229 Status: status, 230 IdentityToken: token, 231 }) 232 } 233 234 func eventTime(formTime string) (time.Time, error) { 235 t, tNano, err := timetypes.ParseTimestamps(formTime, -1) 236 if err != nil { 237 return time.Time{}, err 238 } 239 if t == -1 { 240 return time.Time{}, nil 241 } 242 return time.Unix(t, tNano), nil 243 }