daemon.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. package daemon // import "github.com/docker/docker/integration-cli/daemon"
  2. import (
  3. "fmt"
  4. "os/exec"
  5. "strings"
  6. "time"
  7. "github.com/docker/docker/integration-cli/checker"
  8. "github.com/docker/docker/internal/test/daemon"
  9. "github.com/go-check/check"
  10. "github.com/gotestyourself/gotestyourself/assert"
  11. "github.com/gotestyourself/gotestyourself/icmd"
  12. "github.com/pkg/errors"
  13. )
  14. type testingT interface {
  15. assert.TestingT
  16. logT
  17. Fatalf(string, ...interface{})
  18. }
  19. type logT interface {
  20. Logf(string, ...interface{})
  21. }
  22. // Daemon represents a Docker daemon for the testing framework.
  23. type Daemon struct {
  24. *daemon.Daemon
  25. dockerBinary string
  26. }
  27. // Config holds docker daemon integration configuration
  28. type Config struct {
  29. Experimental bool
  30. }
  31. // New returns a Daemon instance to be used for testing.
  32. // This will create a directory such as d123456789 in the folder specified by $DOCKER_INTEGRATION_DAEMON_DEST or $DEST.
  33. // The daemon will not automatically start.
  34. func New(t testingT, dockerBinary string, dockerdBinary string, config Config, ops ...func(*daemon.Daemon)) *Daemon {
  35. ops = append(ops, daemon.WithDockerdBinary(dockerdBinary))
  36. if config.Experimental {
  37. ops = append(ops, daemon.WithExperimental)
  38. }
  39. d := daemon.New(t, ops...)
  40. return &Daemon{
  41. Daemon: d,
  42. dockerBinary: dockerBinary,
  43. }
  44. }
  45. // Cmd executes a docker CLI command against this daemon.
  46. // Example: d.Cmd("version") will run docker -H unix://path/to/unix.sock version
  47. func (d *Daemon) Cmd(args ...string) (string, error) {
  48. result := icmd.RunCmd(d.Command(args...))
  49. return result.Combined(), result.Error
  50. }
  51. // Command creates a docker CLI command against this daemon, to be executed later.
  52. // Example: d.Command("version") creates a command to run "docker -H unix://path/to/unix.sock version"
  53. func (d *Daemon) Command(args ...string) icmd.Cmd {
  54. return icmd.Command(d.dockerBinary, d.PrependHostArg(args)...)
  55. }
  56. // PrependHostArg prepend the specified arguments by the daemon host flags
  57. func (d *Daemon) PrependHostArg(args []string) []string {
  58. for _, arg := range args {
  59. if arg == "--host" || arg == "-H" {
  60. return args
  61. }
  62. }
  63. return append([]string{"--host", d.Sock()}, args...)
  64. }
  65. // GetIDByName returns the ID of an object (container, volume, …) given its name
  66. func (d *Daemon) GetIDByName(name string) (string, error) {
  67. return d.inspectFieldWithError(name, "Id")
  68. }
  69. // ActiveContainers returns the list of ids of the currently running containers
  70. func (d *Daemon) ActiveContainers() (ids []string) {
  71. // FIXME(vdemeester) shouldn't ignore the error
  72. out, _ := d.Cmd("ps", "-q")
  73. for _, id := range strings.Split(out, "\n") {
  74. if id = strings.TrimSpace(id); id != "" {
  75. ids = append(ids, id)
  76. }
  77. }
  78. return
  79. }
  80. // InspectField returns the field filter by 'filter'
  81. func (d *Daemon) InspectField(name, filter string) (string, error) {
  82. return d.inspectFilter(name, filter)
  83. }
  84. func (d *Daemon) inspectFilter(name, filter string) (string, error) {
  85. format := fmt.Sprintf("{{%s}}", filter)
  86. out, err := d.Cmd("inspect", "-f", format, name)
  87. if err != nil {
  88. return "", errors.Errorf("failed to inspect %s: %s", name, out)
  89. }
  90. return strings.TrimSpace(out), nil
  91. }
  92. func (d *Daemon) inspectFieldWithError(name, field string) (string, error) {
  93. return d.inspectFilter(name, fmt.Sprintf(".%s", field))
  94. }
  95. // FindContainerIP returns the ip of the specified container
  96. func (d *Daemon) FindContainerIP(id string) (string, error) {
  97. out, err := d.Cmd("inspect", "--format='{{ .NetworkSettings.Networks.bridge.IPAddress }}'", id)
  98. if err != nil {
  99. return "", err
  100. }
  101. return strings.Trim(out, " \r\n'"), nil
  102. }
  103. // BuildImageWithOut builds an image with the specified dockerfile and options and returns the output
  104. func (d *Daemon) BuildImageWithOut(name, dockerfile string, useCache bool, buildFlags ...string) (string, int, error) {
  105. buildCmd := BuildImageCmdWithHost(d.dockerBinary, name, dockerfile, d.Sock(), useCache, buildFlags...)
  106. result := icmd.RunCmd(icmd.Cmd{
  107. Command: buildCmd.Args,
  108. Env: buildCmd.Env,
  109. Dir: buildCmd.Dir,
  110. Stdin: buildCmd.Stdin,
  111. Stdout: buildCmd.Stdout,
  112. })
  113. return result.Combined(), result.ExitCode, result.Error
  114. }
  115. // CheckActiveContainerCount returns the number of active containers
  116. // FIXME(vdemeester) should re-use ActivateContainers in some way
  117. func (d *Daemon) CheckActiveContainerCount(c *check.C) (interface{}, check.CommentInterface) {
  118. out, err := d.Cmd("ps", "-q")
  119. c.Assert(err, checker.IsNil)
  120. if len(strings.TrimSpace(out)) == 0 {
  121. return 0, nil
  122. }
  123. return len(strings.Split(strings.TrimSpace(out), "\n")), check.Commentf("output: %q", string(out))
  124. }
  125. // WaitRun waits for a container to be running for 10s
  126. func (d *Daemon) WaitRun(contID string) error {
  127. args := []string{"--host", d.Sock()}
  128. return WaitInspectWithArgs(d.dockerBinary, contID, "{{.State.Running}}", "true", 10*time.Second, args...)
  129. }
  130. // CmdRetryOutOfSequence tries the specified command against the current daemon for 10 times
  131. func (d *Daemon) CmdRetryOutOfSequence(args ...string) (string, error) {
  132. for i := 0; ; i++ {
  133. out, err := d.Cmd(args...)
  134. if err != nil {
  135. if strings.Contains(out, "update out of sequence") {
  136. if i < 10 {
  137. continue
  138. }
  139. }
  140. }
  141. return out, err
  142. }
  143. }
  144. // WaitInspectWithArgs waits for the specified expression to be equals to the specified expected string in the given time.
  145. // Deprecated: use cli.WaitCmd instead
  146. func WaitInspectWithArgs(dockerBinary, name, expr, expected string, timeout time.Duration, arg ...string) error {
  147. after := time.After(timeout)
  148. args := append(arg, "inspect", "-f", expr, name)
  149. for {
  150. result := icmd.RunCommand(dockerBinary, args...)
  151. if result.Error != nil {
  152. if !strings.Contains(strings.ToLower(result.Stderr()), "no such") {
  153. return errors.Errorf("error executing docker inspect: %v\n%s",
  154. result.Stderr(), result.Stdout())
  155. }
  156. select {
  157. case <-after:
  158. return result.Error
  159. default:
  160. time.Sleep(10 * time.Millisecond)
  161. continue
  162. }
  163. }
  164. out := strings.TrimSpace(result.Stdout())
  165. if out == expected {
  166. break
  167. }
  168. select {
  169. case <-after:
  170. return errors.Errorf("condition \"%q == %q\" not true in time (%v)", out, expected, timeout)
  171. default:
  172. }
  173. time.Sleep(100 * time.Millisecond)
  174. }
  175. return nil
  176. }
  177. // BuildImageCmdWithHost create a build command with the specified arguments.
  178. // Deprecated
  179. // FIXME(vdemeester) move this away
  180. func BuildImageCmdWithHost(dockerBinary, name, dockerfile, host string, useCache bool, buildFlags ...string) *exec.Cmd {
  181. args := []string{}
  182. if host != "" {
  183. args = append(args, "--host", host)
  184. }
  185. args = append(args, "build", "-t", name)
  186. if !useCache {
  187. args = append(args, "--no-cache")
  188. }
  189. args = append(args, buildFlags...)
  190. args = append(args, "-")
  191. buildCmd := exec.Command(dockerBinary, args...)
  192. buildCmd.Stdin = strings.NewReader(dockerfile)
  193. return buildCmd
  194. }