helpers.go 2.2 KB

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