github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/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 "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 if err := httputils.ParseForm(r); err != nil { 94 return err 95 } 96 97 version := httputils.VersionFromContext(ctx) 98 99 var getContainers, getImages, getVolumes, getBuildCache bool 100 typeStrs, ok := r.Form["type"] 101 if versions.LessThan(version, "1.42") || !ok { 102 getContainers, getImages, getVolumes, getBuildCache = true, true, true, true 103 } else { 104 for _, typ := range typeStrs { 105 switch types.DiskUsageObject(typ) { 106 case types.ContainerObject: 107 getContainers = true 108 case types.ImageObject: 109 getImages = true 110 case types.VolumeObject: 111 getVolumes = true 112 case types.BuildCacheObject: 113 getBuildCache = true 114 default: 115 return invalidRequestError{Err: fmt.Errorf("unknown object type: %s", typ)} 116 } 117 } 118 } 119 120 eg, ctx := errgroup.WithContext(ctx) 121 122 var systemDiskUsage *types.DiskUsage 123 if getContainers || getImages || getVolumes { 124 eg.Go(func() error { 125 var err error 126 systemDiskUsage, err = s.backend.SystemDiskUsage(ctx, DiskUsageOptions{ 127 Containers: getContainers, 128 Images: getImages, 129 Volumes: getVolumes, 130 }) 131 return err 132 }) 133 } 134 135 var buildCache []*types.BuildCache 136 if getBuildCache { 137 eg.Go(func() error { 138 var err error 139 buildCache, err = s.builder.DiskUsage(ctx) 140 if err != nil { 141 return errors.Wrap(err, "error getting build cache usage") 142 } 143 if buildCache == nil { 144 // Ensure empty `BuildCache` field is represented as empty JSON array(`[]`) 145 // instead of `null` to be consistent with `Images`, `Containers` etc. 146 buildCache = []*types.BuildCache{} 147 } 148 return nil 149 }) 150 } 151 152 if err := eg.Wait(); err != nil { 153 return err 154 } 155 156 var builderSize int64 157 if versions.LessThan(version, "1.42") { 158 for _, b := range buildCache { 159 builderSize += b.Size 160 } 161 } 162 163 du := types.DiskUsage{ 164 BuildCache: buildCache, 165 BuilderSize: builderSize, 166 } 167 if systemDiskUsage != nil { 168 du.LayersSize = systemDiskUsage.LayersSize 169 du.Images = systemDiskUsage.Images 170 du.Containers = systemDiskUsage.Containers 171 du.Volumes = systemDiskUsage.Volumes 172 } 173 return httputils.WriteJSON(w, http.StatusOK, du) 174 } 175 176 type invalidRequestError struct { 177 Err error 178 } 179 180 func (e invalidRequestError) Error() string { 181 return e.Err.Error() 182 } 183 184 func (e invalidRequestError) InvalidParameter() {} 185 186 func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 187 if err := httputils.ParseForm(r); err != nil { 188 return err 189 } 190 191 since, err := eventTime(r.Form.Get("since")) 192 if err != nil { 193 return err 194 } 195 until, err := eventTime(r.Form.Get("until")) 196 if err != nil { 197 return err 198 } 199 200 var ( 201 timeout <-chan time.Time 202 onlyPastEvents bool 203 ) 204 if !until.IsZero() { 205 if until.Before(since) { 206 return invalidRequestError{fmt.Errorf("`since` time (%s) cannot be after `until` time (%s)", r.Form.Get("since"), r.Form.Get("until"))} 207 } 208 209 now := time.Now() 210 211 onlyPastEvents = until.Before(now) 212 213 if !onlyPastEvents { 214 dur := until.Sub(now) 215 timer := time.NewTimer(dur) 216 defer timer.Stop() 217 timeout = timer.C 218 } 219 } 220 221 ef, err := filters.FromJSON(r.Form.Get("filters")) 222 if err != nil { 223 return err 224 } 225 226 w.Header().Set("Content-Type", "application/json") 227 output := ioutils.NewWriteFlusher(w) 228 defer output.Close() 229 output.Flush() 230 231 enc := json.NewEncoder(output) 232 233 buffered, l := s.backend.SubscribeToEvents(since, until, ef) 234 defer s.backend.UnsubscribeFromEvents(l) 235 236 for _, ev := range buffered { 237 if err := enc.Encode(ev); err != nil { 238 return err 239 } 240 } 241 242 if onlyPastEvents { 243 return nil 244 } 245 246 for { 247 select { 248 case ev := <-l: 249 jev, ok := ev.(events.Message) 250 if !ok { 251 logrus.Warnf("unexpected event message: %q", ev) 252 continue 253 } 254 if err := enc.Encode(jev); err != nil { 255 return err 256 } 257 case <-timeout: 258 return nil 259 case <-ctx.Done(): 260 logrus.Debug("Client context cancelled, stop sending events") 261 return nil 262 } 263 } 264 } 265 266 func (s *systemRouter) postAuth(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 267 var config *types.AuthConfig 268 err := json.NewDecoder(r.Body).Decode(&config) 269 r.Body.Close() 270 if err != nil { 271 return err 272 } 273 status, token, err := s.backend.AuthenticateToRegistry(ctx, config) 274 if err != nil { 275 return err 276 } 277 return httputils.WriteJSON(w, http.StatusOK, ®istry.AuthenticateOKBody{ 278 Status: status, 279 IdentityToken: token, 280 }) 281 } 282 283 func eventTime(formTime string) (time.Time, error) { 284 t, tNano, err := timetypes.ParseTimestamps(formTime, -1) 285 if err != nil { 286 return time.Time{}, err 287 } 288 if t == -1 { 289 return time.Time{}, nil 290 } 291 return time.Unix(t, tNano), nil 292 }