service.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. package swarm
  2. import (
  3. "context"
  4. "runtime"
  5. "testing"
  6. "time"
  7. "github.com/docker/docker/api/types"
  8. "github.com/docker/docker/api/types/filters"
  9. swarmtypes "github.com/docker/docker/api/types/swarm"
  10. "github.com/docker/docker/client"
  11. "github.com/docker/docker/internal/test/daemon"
  12. "github.com/docker/docker/internal/test/environment"
  13. "github.com/gotestyourself/gotestyourself/assert"
  14. "github.com/gotestyourself/gotestyourself/poll"
  15. "github.com/gotestyourself/gotestyourself/skip"
  16. )
  17. // ServicePoll tweaks the pollSettings for `service`
  18. func ServicePoll(config *poll.Settings) {
  19. // Override the default pollSettings for `service` resource here ...
  20. if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" {
  21. config.Timeout = 1 * time.Minute
  22. config.Delay = 100 * time.Millisecond
  23. }
  24. }
  25. // NetworkPoll tweaks the pollSettings for `network`
  26. func NetworkPoll(config *poll.Settings) {
  27. // Override the default pollSettings for `network` resource here ...
  28. config.Timeout = 30 * time.Second
  29. config.Delay = 100 * time.Millisecond
  30. if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" {
  31. config.Timeout = 50 * time.Second
  32. }
  33. }
  34. // ContainerPoll tweaks the pollSettings for `container`
  35. func ContainerPoll(config *poll.Settings) {
  36. // Override the default pollSettings for `container` resource here ...
  37. if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" {
  38. config.Timeout = 30 * time.Second
  39. config.Delay = 100 * time.Millisecond
  40. }
  41. }
  42. // NewSwarm creates a swarm daemon for testing
  43. func NewSwarm(t *testing.T, testEnv *environment.Execution, ops ...func(*daemon.Daemon)) *daemon.Daemon {
  44. skip.IfCondition(t, testEnv.IsRemoteDaemon())
  45. if testEnv.DaemonInfo.ExperimentalBuild {
  46. ops = append(ops, daemon.WithExperimental)
  47. }
  48. d := daemon.New(t, ops...)
  49. // avoid networking conflicts
  50. args := []string{"--iptables=false", "--swarm-default-advertise-addr=lo"}
  51. d.StartWithBusybox(t, args...)
  52. d.SwarmInit(t, swarmtypes.InitRequest{})
  53. return d
  54. }
  55. // ServiceSpecOpt is used with `CreateService` to pass in service spec modifiers
  56. type ServiceSpecOpt func(*swarmtypes.ServiceSpec)
  57. // CreateService creates a service on the passed in swarm daemon.
  58. func CreateService(t *testing.T, d *daemon.Daemon, opts ...ServiceSpecOpt) string {
  59. spec := defaultServiceSpec()
  60. for _, o := range opts {
  61. o(&spec)
  62. }
  63. client := GetClient(t, d)
  64. resp, err := client.ServiceCreate(context.Background(), spec, types.ServiceCreateOptions{})
  65. assert.NilError(t, err, "error creating service")
  66. return resp.ID
  67. }
  68. func defaultServiceSpec() swarmtypes.ServiceSpec {
  69. var spec swarmtypes.ServiceSpec
  70. ServiceWithImage("busybox:latest")(&spec)
  71. ServiceWithCommand([]string{"/bin/top"})(&spec)
  72. ServiceWithReplicas(1)(&spec)
  73. return spec
  74. }
  75. // ServiceWithImage sets the image to use for the service
  76. func ServiceWithImage(image string) func(*swarmtypes.ServiceSpec) {
  77. return func(spec *swarmtypes.ServiceSpec) {
  78. ensureContainerSpec(spec)
  79. spec.TaskTemplate.ContainerSpec.Image = image
  80. }
  81. }
  82. // ServiceWithCommand sets the command to use for the service
  83. func ServiceWithCommand(cmd []string) ServiceSpecOpt {
  84. return func(spec *swarmtypes.ServiceSpec) {
  85. ensureContainerSpec(spec)
  86. spec.TaskTemplate.ContainerSpec.Command = cmd
  87. }
  88. }
  89. // ServiceWithConfig adds the config reference to the service
  90. func ServiceWithConfig(configRef *swarmtypes.ConfigReference) ServiceSpecOpt {
  91. return func(spec *swarmtypes.ServiceSpec) {
  92. ensureContainerSpec(spec)
  93. spec.TaskTemplate.ContainerSpec.Configs = append(spec.TaskTemplate.ContainerSpec.Configs, configRef)
  94. }
  95. }
  96. // ServiceWithSecret adds the secret reference to the service
  97. func ServiceWithSecret(secretRef *swarmtypes.SecretReference) ServiceSpecOpt {
  98. return func(spec *swarmtypes.ServiceSpec) {
  99. ensureContainerSpec(spec)
  100. spec.TaskTemplate.ContainerSpec.Secrets = append(spec.TaskTemplate.ContainerSpec.Secrets, secretRef)
  101. }
  102. }
  103. // ServiceWithReplicas sets the replicas for the service
  104. func ServiceWithReplicas(n uint64) ServiceSpecOpt {
  105. return func(spec *swarmtypes.ServiceSpec) {
  106. spec.Mode = swarmtypes.ServiceMode{
  107. Replicated: &swarmtypes.ReplicatedService{
  108. Replicas: &n,
  109. },
  110. }
  111. }
  112. }
  113. // ServiceWithName sets the name of the service
  114. func ServiceWithName(name string) ServiceSpecOpt {
  115. return func(spec *swarmtypes.ServiceSpec) {
  116. spec.Annotations.Name = name
  117. }
  118. }
  119. // GetRunningTasks gets the list of running tasks for a service
  120. func GetRunningTasks(t *testing.T, d *daemon.Daemon, serviceID string) []swarmtypes.Task {
  121. client := GetClient(t, d)
  122. filterArgs := filters.NewArgs()
  123. filterArgs.Add("desired-state", "running")
  124. filterArgs.Add("service", serviceID)
  125. options := types.TaskListOptions{
  126. Filters: filterArgs,
  127. }
  128. tasks, err := client.TaskList(context.Background(), options)
  129. assert.NilError(t, err)
  130. return tasks
  131. }
  132. // ExecTask runs the passed in exec config on the given task
  133. func ExecTask(t *testing.T, d *daemon.Daemon, task swarmtypes.Task, config types.ExecConfig) types.HijackedResponse {
  134. client := GetClient(t, d)
  135. ctx := context.Background()
  136. resp, err := client.ContainerExecCreate(ctx, task.Status.ContainerStatus.ContainerID, config)
  137. assert.NilError(t, err, "error creating exec")
  138. startCheck := types.ExecStartCheck{}
  139. attach, err := client.ContainerExecAttach(ctx, resp.ID, startCheck)
  140. assert.NilError(t, err, "error attaching to exec")
  141. return attach
  142. }
  143. func ensureContainerSpec(spec *swarmtypes.ServiceSpec) {
  144. if spec.TaskTemplate.ContainerSpec == nil {
  145. spec.TaskTemplate.ContainerSpec = &swarmtypes.ContainerSpec{}
  146. }
  147. }
  148. // GetClient creates a new client for the passed in swarm daemon.
  149. func GetClient(t *testing.T, d *daemon.Daemon) client.APIClient {
  150. client, err := client.NewClientWithOpts(client.WithHost((d.Sock())))
  151. assert.NilError(t, err)
  152. return client
  153. }