docker_cli_service_logs_experimental_test.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // +build !windows
  2. package main
  3. import (
  4. "bufio"
  5. "fmt"
  6. "io"
  7. "os/exec"
  8. "strings"
  9. "time"
  10. "github.com/docker/docker/integration-cli/checker"
  11. "github.com/docker/docker/integration-cli/daemon"
  12. "github.com/go-check/check"
  13. )
  14. type logMessage struct {
  15. err error
  16. data []byte
  17. }
  18. func (s *DockerSwarmSuite) TestServiceLogs(c *check.C) {
  19. testRequires(c, ExperimentalDaemon)
  20. d := s.AddDaemon(c, true, true)
  21. // we have multiple services here for detecting the goroutine issue #28915
  22. services := map[string]string{
  23. "TestServiceLogs1": "hello1",
  24. "TestServiceLogs2": "hello2",
  25. }
  26. for name, message := range services {
  27. out, err := d.Cmd("service", "create", "--name", name, "busybox",
  28. "sh", "-c", fmt.Sprintf("echo %s; tail -f /dev/null", message))
  29. c.Assert(err, checker.IsNil)
  30. c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
  31. }
  32. // make sure task has been deployed.
  33. waitAndAssert(c, defaultReconciliationTimeout,
  34. d.CheckRunningTaskImages, checker.DeepEquals,
  35. map[string]int{"busybox": len(services)})
  36. for name, message := range services {
  37. out, err := d.Cmd("service", "logs", name)
  38. c.Assert(err, checker.IsNil)
  39. c.Logf("log for %q: %q", name, out)
  40. c.Assert(out, checker.Contains, message)
  41. }
  42. }
  43. // countLogLines returns a closure that can be used with waitAndAssert to
  44. // verify that a minimum number of expected container log messages have been
  45. // output.
  46. func countLogLines(d *daemon.Swarm, name string) func(*check.C) (interface{}, check.CommentInterface) {
  47. return func(c *check.C) (interface{}, check.CommentInterface) {
  48. out, err := d.Cmd("service", "logs", "-t", name)
  49. c.Assert(err, checker.IsNil)
  50. lines := strings.Split(strings.TrimSpace(out), "\n")
  51. return len(lines), check.Commentf("output, %q", string(out))
  52. }
  53. }
  54. func (s *DockerSwarmSuite) TestServiceLogsCompleteness(c *check.C) {
  55. testRequires(c, ExperimentalDaemon)
  56. d := s.AddDaemon(c, true, true)
  57. name := "TestServiceLogsCompleteness"
  58. // make a service that prints 6 lines
  59. out, err := d.Cmd("service", "create", "--name", name, "busybox", "sh", "-c", "for line in $(seq 1 6); do echo log test $line; done; sleep 100000")
  60. c.Assert(err, checker.IsNil)
  61. c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
  62. // make sure task has been deployed.
  63. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
  64. // and make sure we have all the log lines
  65. waitAndAssert(c, defaultReconciliationTimeout, countLogLines(d, name), checker.Equals, 6)
  66. args := []string{"service", "logs", name}
  67. cmd := exec.Command(dockerBinary, d.PrependHostArg(args)...)
  68. r, w := io.Pipe()
  69. cmd.Stdout = w
  70. cmd.Stderr = w
  71. c.Assert(cmd.Start(), checker.IsNil)
  72. reader := bufio.NewReader(r)
  73. // i have heard anecdotal reports that logs may come back from the engine
  74. // mis-ordered. if this tests fails, consider the possibility that that
  75. // might be occurring
  76. for i := 1; i <= 6; i++ {
  77. msg := &logMessage{}
  78. msg.data, _, msg.err = reader.ReadLine()
  79. c.Assert(msg.err, checker.IsNil)
  80. c.Assert(string(msg.data), checker.Contains, fmt.Sprintf("log test %v", i))
  81. }
  82. }
  83. func (s *DockerSwarmSuite) TestServiceLogsTail(c *check.C) {
  84. testRequires(c, ExperimentalDaemon)
  85. d := s.AddDaemon(c, true, true)
  86. name := "TestServiceLogsTail"
  87. // make a service that prints 6 lines
  88. out, err := d.Cmd("service", "create", "--name", name, "busybox", "sh", "-c", "for line in $(seq 1 6); do echo log test $line; done; sleep 100000")
  89. c.Assert(err, checker.IsNil)
  90. c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
  91. // make sure task has been deployed.
  92. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
  93. waitAndAssert(c, defaultReconciliationTimeout, countLogLines(d, name), checker.Equals, 6)
  94. args := []string{"service", "logs", "--tail=2", name}
  95. cmd := exec.Command(dockerBinary, d.PrependHostArg(args)...)
  96. r, w := io.Pipe()
  97. cmd.Stdout = w
  98. cmd.Stderr = w
  99. c.Assert(cmd.Start(), checker.IsNil)
  100. reader := bufio.NewReader(r)
  101. // see TestServiceLogsCompleteness for comments about logs being well-
  102. // ordered, if this flakes
  103. for i := 5; i <= 6; i++ {
  104. msg := &logMessage{}
  105. msg.data, _, msg.err = reader.ReadLine()
  106. c.Assert(msg.err, checker.IsNil)
  107. c.Assert(string(msg.data), checker.Contains, fmt.Sprintf("log test %v", i))
  108. }
  109. }
  110. func (s *DockerSwarmSuite) TestServiceLogsSince(c *check.C) {
  111. // See DockerSuite.TestLogsSince, which is where this comes from
  112. testRequires(c, ExperimentalDaemon)
  113. d := s.AddDaemon(c, true, true)
  114. name := "TestServiceLogsSince"
  115. out, err := d.Cmd("service", "create", "--name", name, "busybox", "sh", "-c", "for i in $(seq 1 3); do sleep .1; echo log$i; done; sleep 10000000")
  116. c.Assert(err, checker.IsNil)
  117. c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
  118. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
  119. // wait a sec for the logs to come in
  120. waitAndAssert(c, defaultReconciliationTimeout, countLogLines(d, name), checker.Equals, 3)
  121. out, err = d.Cmd("service", "logs", "-t", name)
  122. c.Assert(err, checker.IsNil)
  123. log2Line := strings.Split(strings.Split(out, "\n")[1], " ")
  124. t, err := time.Parse(time.RFC3339Nano, log2Line[0]) // timestamp log2 is written
  125. c.Assert(err, checker.IsNil)
  126. u := t.Add(50 * time.Millisecond) // add .05s so log1 & log2 don't show up
  127. since := u.Format(time.RFC3339Nano)
  128. out, err = d.Cmd("service", "logs", "-t", fmt.Sprintf("--since=%v", since), name)
  129. c.Assert(err, checker.IsNil)
  130. unexpected := []string{"log1", "log2"}
  131. expected := []string{"log3"}
  132. for _, v := range unexpected {
  133. c.Assert(out, checker.Not(checker.Contains), v, check.Commentf("unexpected log message returned, since=%v", u))
  134. }
  135. for _, v := range expected {
  136. c.Assert(out, checker.Contains, v, check.Commentf("expected log message %v, was not present, since=%v", u))
  137. }
  138. }
  139. func (s *DockerSwarmSuite) TestServiceLogsFollow(c *check.C) {
  140. testRequires(c, ExperimentalDaemon)
  141. d := s.AddDaemon(c, true, true)
  142. name := "TestServiceLogsFollow"
  143. out, err := d.Cmd("service", "create", "--name", name, "busybox", "sh", "-c", "while true; do echo log test; sleep 0.1; done")
  144. c.Assert(err, checker.IsNil)
  145. c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "")
  146. // make sure task has been deployed.
  147. waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
  148. args := []string{"service", "logs", "-f", name}
  149. cmd := exec.Command(dockerBinary, d.PrependHostArg(args)...)
  150. r, w := io.Pipe()
  151. cmd.Stdout = w
  152. cmd.Stderr = w
  153. c.Assert(cmd.Start(), checker.IsNil)
  154. // Make sure pipe is written to
  155. ch := make(chan *logMessage)
  156. done := make(chan struct{})
  157. go func() {
  158. reader := bufio.NewReader(r)
  159. for {
  160. msg := &logMessage{}
  161. msg.data, _, msg.err = reader.ReadLine()
  162. select {
  163. case ch <- msg:
  164. case <-done:
  165. return
  166. }
  167. }
  168. }()
  169. for i := 0; i < 3; i++ {
  170. msg := <-ch
  171. c.Assert(msg.err, checker.IsNil)
  172. c.Assert(string(msg.data), checker.Contains, "log test")
  173. }
  174. close(done)
  175. c.Assert(cmd.Process.Kill(), checker.IsNil)
  176. }