package system // import "github.com/docker/docker/api/server/router/system" import ( "encoding/json" "fmt" "net/http" "time" "github.com/docker/docker/api/server/httputils" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/events" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/registry" timetypes "github.com/docker/docker/api/types/time" "github.com/docker/docker/api/types/versions" "github.com/docker/docker/pkg/ioutils" pkgerrors "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/net/context" ) func optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { w.WriteHeader(http.StatusOK) return nil } func pingHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { _, err := w.Write([]byte{'O', 'K'}) return err } func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { info, err := s.backend.SystemInfo() if err != nil { return err } if s.cluster != nil { info.Swarm = s.cluster.Info() } if versions.LessThan(httputils.VersionFromContext(ctx), "1.25") { // TODO: handle this conversion in engine-api type oldInfo struct { *types.Info ExecutionDriver string } old := &oldInfo{ Info: info, ExecutionDriver: "", } nameOnlySecurityOptions := []string{} kvSecOpts, err := types.DecodeSecurityOptions(old.SecurityOptions) if err != nil { return err } for _, s := range kvSecOpts { nameOnlySecurityOptions = append(nameOnlySecurityOptions, s.Name) } old.SecurityOptions = nameOnlySecurityOptions return httputils.WriteJSON(w, http.StatusOK, old) } return httputils.WriteJSON(w, http.StatusOK, info) } func (s *systemRouter) getVersion(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { info := s.backend.SystemVersion() return httputils.WriteJSON(w, http.StatusOK, info) } func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { du, err := s.backend.SystemDiskUsage(ctx) if err != nil { return err } builderSize, err := s.builder.DiskUsage() if err != nil { return pkgerrors.Wrap(err, "error getting build cache usage") } du.BuilderSize = builderSize return httputils.WriteJSON(w, http.StatusOK, du) } type invalidRequestError struct { Err error } func (e invalidRequestError) Error() string { return e.Err.Error() } func (e invalidRequestError) InvalidParameter() {} func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err } since, err := eventTime(r.Form.Get("since")) if err != nil { return err } until, err := eventTime(r.Form.Get("until")) if err != nil { return err } var ( timeout <-chan time.Time onlyPastEvents bool ) if !until.IsZero() { if until.Before(since) { return invalidRequestError{fmt.Errorf("`since` time (%s) cannot be after `until` time (%s)", r.Form.Get("since"), r.Form.Get("until"))} } now := time.Now() onlyPastEvents = until.Before(now) if !onlyPastEvents { dur := until.Sub(now) timeout = time.After(dur) } } ef, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { return err } w.Header().Set("Content-Type", "application/json") output := ioutils.NewWriteFlusher(w) defer output.Close() output.Flush() enc := json.NewEncoder(output) buffered, l := s.backend.SubscribeToEvents(since, until, ef) defer s.backend.UnsubscribeFromEvents(l) for _, ev := range buffered { if err := enc.Encode(ev); err != nil { return err } } if onlyPastEvents { return nil } for { select { case ev := <-l: jev, ok := ev.(events.Message) if !ok { logrus.Warnf("unexpected event message: %q", ev) continue } if err := enc.Encode(jev); err != nil { return err } case <-timeout: return nil case <-ctx.Done(): logrus.Debug("Client context cancelled, stop sending events") return nil } } } func (s *systemRouter) postAuth(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var config *types.AuthConfig err := json.NewDecoder(r.Body).Decode(&config) r.Body.Close() if err != nil { return err } status, token, err := s.backend.AuthenticateToRegistry(ctx, config) if err != nil { return err } return httputils.WriteJSON(w, http.StatusOK, ®istry.AuthenticateOKBody{ Status: status, IdentityToken: token, }) } func eventTime(formTime string) (time.Time, error) { t, tNano, err := timetypes.ParseTimestamps(formTime, -1) if err != nil { return time.Time{}, err } if t == -1 { return time.Time{}, nil } return time.Unix(t, tNano), nil }