helpers.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. package swarm // import "github.com/docker/docker/api/server/router/swarm"
  2. import (
  3. "fmt"
  4. "io"
  5. "net/http"
  6. "github.com/docker/docker/api/server/httputils"
  7. basictypes "github.com/docker/docker/api/types"
  8. "github.com/docker/docker/api/types/backend"
  9. "golang.org/x/net/context"
  10. )
  11. // swarmLogs takes an http response, request, and selector, and writes the logs
  12. // specified by the selector to the response
  13. func (sr *swarmRouter) swarmLogs(ctx context.Context, w io.Writer, r *http.Request, selector *backend.LogSelector) error {
  14. // Args are validated before the stream starts because when it starts we're
  15. // sending HTTP 200 by writing an empty chunk of data to tell the client that
  16. // daemon is going to stream. By sending this initial HTTP 200 we can't report
  17. // any error after the stream starts (i.e. container not found, wrong parameters)
  18. // with the appropriate status code.
  19. stdout, stderr := httputils.BoolValue(r, "stdout"), httputils.BoolValue(r, "stderr")
  20. if !(stdout || stderr) {
  21. return fmt.Errorf("Bad parameters: you must choose at least one stream")
  22. }
  23. // there is probably a neater way to manufacture the ContainerLogsOptions
  24. // struct, probably in the caller, to eliminate the dependency on net/http
  25. logsConfig := &basictypes.ContainerLogsOptions{
  26. Follow: httputils.BoolValue(r, "follow"),
  27. Timestamps: httputils.BoolValue(r, "timestamps"),
  28. Since: r.Form.Get("since"),
  29. Tail: r.Form.Get("tail"),
  30. ShowStdout: stdout,
  31. ShowStderr: stderr,
  32. Details: httputils.BoolValue(r, "details"),
  33. }
  34. tty := false
  35. // checking for whether logs are TTY involves iterating over every service
  36. // and task. idk if there is a better way
  37. for _, service := range selector.Services {
  38. s, err := sr.backend.GetService(service, false)
  39. if err != nil {
  40. // maybe should return some context with this error?
  41. return err
  42. }
  43. tty = (s.Spec.TaskTemplate.ContainerSpec != nil && s.Spec.TaskTemplate.ContainerSpec.TTY) || tty
  44. }
  45. for _, task := range selector.Tasks {
  46. t, err := sr.backend.GetTask(task)
  47. if err != nil {
  48. // as above
  49. return err
  50. }
  51. tty = t.Spec.ContainerSpec.TTY || tty
  52. }
  53. msgs, err := sr.backend.ServiceLogs(ctx, selector, logsConfig)
  54. if err != nil {
  55. return err
  56. }
  57. httputils.WriteLogStream(ctx, w, msgs, logsConfig, !tty)
  58. return nil
  59. }