github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/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, err := s.backend.SystemInfo() 48 if err != nil { 49 return err 50 } 51 if s.cluster != nil { 52 info.Swarm = s.cluster.Info() 53 info.Warnings = append(info.Warnings, info.Swarm.Warnings...) 54 } 55 56 if versions.LessThan(httputils.VersionFromContext(ctx), "1.25") { 57 // TODO: handle this conversion in engine-api 58 type oldInfo struct { 59 *types.Info 60 ExecutionDriver string 61 } 62 old := &oldInfo{ 63 Info: info, 64 ExecutionDriver: "<not supported>", 65 } 66 nameOnlySecurityOptions := []string{} 67 kvSecOpts, err := types.DecodeSecurityOptions(old.SecurityOptions) 68 if err != nil { 69 return err 70 } 71 for _, s := range kvSecOpts { 72 nameOnlySecurityOptions = append(nameOnlySecurityOptions, s.Name) 73 } 74 old.SecurityOptions = nameOnlySecurityOptions 75 return httputils.WriteJSON(w, http.StatusOK, old) 76 } 77 if versions.LessThan(httputils.VersionFromContext(ctx), "1.39") { 78 if info.KernelVersion == "" { 79 info.KernelVersion = "<unknown>" 80 } 81 if info.OperatingSystem == "" { 82 info.OperatingSystem = "<unknown>" 83 } 84 } 85 return httputils.WriteJSON(w, http.StatusOK, info) 86 } 87 88 func (s *systemRouter) getVersion(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 89 info := s.backend.SystemVersion() 90 91 return httputils.WriteJSON(w, http.StatusOK, info) 92 } 93 94 func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 95 eg, ctx := errgroup.WithContext(ctx) 96 97 var du *types.DiskUsage 98 eg.Go(func() error { 99 var err error 100 du, err = s.backend.SystemDiskUsage(ctx) 101 return err 102 }) 103 104 var builderSize int64 // legacy 105 eg.Go(func() error { 106 var err error 107 builderSize, err = s.fscache.DiskUsage(ctx) 108 if err != nil { 109 return pkgerrors.Wrap(err, "error getting fscache build cache usage") 110 } 111 return nil 112 }) 113 114 var buildCache []*types.BuildCache 115 eg.Go(func() error { 116 var err error 117 buildCache, err = s.builder.DiskUsage(ctx) 118 if err != nil { 119 return pkgerrors.Wrap(err, "error getting build cache usage") 120 } 121 return nil 122 }) 123 124 if err := eg.Wait(); err != nil { 125 return err 126 } 127 128 for _, b := range buildCache { 129 builderSize += b.Size 130 } 131 132 du.BuilderSize = builderSize 133 du.BuildCache = buildCache 134 135 return httputils.WriteJSON(w, http.StatusOK, du) 136 } 137 138 type invalidRequestError struct { 139 Err error 140 } 141 142 func (e invalidRequestError) Error() string { 143 return e.Err.Error() 144 } 145 146 func (e invalidRequestError) InvalidParameter() {} 147 148 func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 149 if err := httputils.ParseForm(r); err != nil { 150 return err 151 } 152 153 since, err := eventTime(r.Form.Get("since")) 154 if err != nil { 155 return err 156 } 157 until, err := eventTime(r.Form.Get("until")) 158 if err != nil { 159 return err 160 } 161 162 var ( 163 timeout <-chan time.Time 164 onlyPastEvents bool 165 ) 166 if !until.IsZero() { 167 if until.Before(since) { 168 return invalidRequestError{fmt.Errorf("`since` time (%s) cannot be after `until` time (%s)", r.Form.Get("since"), r.Form.Get("until"))} 169 } 170 171 now := time.Now() 172 173 onlyPastEvents = until.Before(now) 174 175 if !onlyPastEvents { 176 dur := until.Sub(now) 177 timeout = time.After(dur) 178 } 179 } 180 181 ef, err := filters.FromJSON(r.Form.Get("filters")) 182 if err != nil { 183 return err 184 } 185 186 w.Header().Set("Content-Type", "application/json") 187 output := ioutils.NewWriteFlusher(w) 188 defer output.Close() 189 output.Flush() 190 191 enc := json.NewEncoder(output) 192 193 buffered, l := s.backend.SubscribeToEvents(since, until, ef) 194 defer s.backend.UnsubscribeFromEvents(l) 195 196 for _, ev := range buffered { 197 if err := enc.Encode(ev); err != nil { 198 return err 199 } 200 } 201 202 if onlyPastEvents { 203 return nil 204 } 205 206 for { 207 select { 208 case ev := <-l: 209 jev, ok := ev.(events.Message) 210 if !ok { 211 logrus.Warnf("unexpected event message: %q", ev) 212 continue 213 } 214 if err := enc.Encode(jev); err != nil { 215 return err 216 } 217 case <-timeout: 218 return nil 219 case <-ctx.Done(): 220 logrus.Debug("Client context cancelled, stop sending events") 221 return nil 222 } 223 } 224 } 225 226 func (s *systemRouter) postAuth(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 227 var config *types.AuthConfig 228 err := json.NewDecoder(r.Body).Decode(&config) 229 r.Body.Close() 230 if err != nil { 231 return err 232 } 233 status, token, err := s.backend.AuthenticateToRegistry(ctx, config) 234 if err != nil { 235 return err 236 } 237 return httputils.WriteJSON(w, http.StatusOK, ®istry.AuthenticateOKBody{ 238 Status: status, 239 IdentityToken: token, 240 }) 241 } 242 243 func eventTime(formTime string) (time.Time, error) { 244 t, tNano, err := timetypes.ParseTimestamps(formTime, -1) 245 if err != nil { 246 return time.Time{}, err 247 } 248 if t == -1 { 249 return time.Time{}, nil 250 } 251 return time.Unix(t, tNano), nil 252 }