system_routes.go 5.9 KB

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