github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/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 if versions.LessThan(httputils.VersionFromContext(ctx), "1.42") { 117 var builderSize int64 118 for _, b := range buildCache { 119 builderSize += b.Size 120 } 121 du.BuilderSize = builderSize 122 } 123 124 du.BuildCache = buildCache 125 if buildCache == nil { 126 // Ensure empty `BuildCache` field is represented as empty JSON array(`[]`) 127 // instead of `null` to be consistent with `Images`, `Containers` etc. 128 du.BuildCache = []*types.BuildCache{} 129 } 130 131 return httputils.WriteJSON(w, http.StatusOK, du) 132 } 133 134 type invalidRequestError struct { 135 Err error 136 } 137 138 func (e invalidRequestError) Error() string { 139 return e.Err.Error() 140 } 141 142 func (e invalidRequestError) InvalidParameter() {} 143 144 func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 145 if err := httputils.ParseForm(r); err != nil { 146 return err 147 } 148 149 since, err := eventTime(r.Form.Get("since")) 150 if err != nil { 151 return err 152 } 153 until, err := eventTime(r.Form.Get("until")) 154 if err != nil { 155 return err 156 } 157 158 var ( 159 timeout <-chan time.Time 160 onlyPastEvents bool 161 ) 162 if !until.IsZero() { 163 if until.Before(since) { 164 return invalidRequestError{fmt.Errorf("`since` time (%s) cannot be after `until` time (%s)", r.Form.Get("since"), r.Form.Get("until"))} 165 } 166 167 now := time.Now() 168 169 onlyPastEvents = until.Before(now) 170 171 if !onlyPastEvents { 172 dur := until.Sub(now) 173 timer := time.NewTimer(dur) 174 defer timer.Stop() 175 timeout = timer.C 176 } 177 } 178 179 ef, err := filters.FromJSON(r.Form.Get("filters")) 180 if err != nil { 181 return err 182 } 183 184 w.Header().Set("Content-Type", "application/json") 185 output := ioutils.NewWriteFlusher(w) 186 defer output.Close() 187 output.Flush() 188 189 enc := json.NewEncoder(output) 190 191 buffered, l := s.backend.SubscribeToEvents(since, until, ef) 192 defer s.backend.UnsubscribeFromEvents(l) 193 194 for _, ev := range buffered { 195 if err := enc.Encode(ev); err != nil { 196 return err 197 } 198 } 199 200 if onlyPastEvents { 201 return nil 202 } 203 204 for { 205 select { 206 case ev := <-l: 207 jev, ok := ev.(events.Message) 208 if !ok { 209 logrus.Warnf("unexpected event message: %q", ev) 210 continue 211 } 212 if err := enc.Encode(jev); err != nil { 213 return err 214 } 215 case <-timeout: 216 return nil 217 case <-ctx.Done(): 218 logrus.Debug("Client context cancelled, stop sending events") 219 return nil 220 } 221 } 222 } 223 224 func (s *systemRouter) postAuth(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 225 var config *types.AuthConfig 226 err := json.NewDecoder(r.Body).Decode(&config) 227 r.Body.Close() 228 if err != nil { 229 return err 230 } 231 status, token, err := s.backend.AuthenticateToRegistry(ctx, config) 232 if err != nil { 233 return err 234 } 235 return httputils.WriteJSON(w, http.StatusOK, ®istry.AuthenticateOKBody{ 236 Status: status, 237 IdentityToken: token, 238 }) 239 } 240 241 func eventTime(formTime string) (time.Time, error) { 242 t, tNano, err := timetypes.ParseTimestamps(formTime, -1) 243 if err != nil { 244 return time.Time{}, err 245 } 246 if t == -1 { 247 return time.Time{}, nil 248 } 249 return time.Unix(t, tNano), nil 250 }