service.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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/internal/test/daemon"
  11. "github.com/docker/docker/internal/test/environment"
  12. "github.com/gotestyourself/gotestyourself/assert"
  13. "github.com/gotestyourself/gotestyourself/poll"
  14. "github.com/gotestyourself/gotestyourself/skip"
  15. )
  16. // ServicePoll tweaks the pollSettings for `service`
  17. func ServicePoll(config *poll.Settings) {
  18. // Override the default pollSettings for `service` resource here ...
  19. config.Timeout = 30 * time.Second
  20. config.Delay = 100 * time.Millisecond
  21. if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" {
  22. config.Timeout = 90 * time.Second
  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. t.Helper()
  45. skip.If(t, testEnv.IsRemoteDaemon)
  46. if testEnv.DaemonInfo.ExperimentalBuild {
  47. ops = append(ops, daemon.WithExperimental)
  48. }
  49. d := daemon.New(t, ops...)
  50. d.StartAndSwarmInit(t)
  51. return d
  52. }
  53. // ServiceSpecOpt is used with `CreateService` to pass in service spec modifiers
  54. type ServiceSpecOpt func(*swarmtypes.ServiceSpec)
  55. // CreateService creates a service on the passed in swarm daemon.
  56. func CreateService(t *testing.T, d *daemon.Daemon, opts ...ServiceSpecOpt) string {
  57. t.Helper()
  58. spec := defaultServiceSpec()
  59. for _, o := range opts {
  60. o(&spec)
  61. }
  62. client := d.NewClientT(t)
  63. defer client.Close()
  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. // ServiceWithInit sets whether the service should use init or not
  76. func ServiceWithInit(b *bool) func(*swarmtypes.ServiceSpec) {
  77. return func(spec *swarmtypes.ServiceSpec) {
  78. ensureContainerSpec(spec)
  79. spec.TaskTemplate.ContainerSpec.Init = b
  80. }
  81. }
  82. // ServiceWithImage sets the image to use for the service
  83. func ServiceWithImage(image string) func(*swarmtypes.ServiceSpec) {
  84. return func(spec *swarmtypes.ServiceSpec) {
  85. ensureContainerSpec(spec)
  86. spec.TaskTemplate.ContainerSpec.Image = image
  87. }
  88. }
  89. // ServiceWithCommand sets the command to use for the service
  90. func ServiceWithCommand(cmd []string) ServiceSpecOpt {
  91. return func(spec *swarmtypes.ServiceSpec) {
  92. ensureContainerSpec(spec)
  93. spec.TaskTemplate.ContainerSpec.Command = cmd
  94. }
  95. }
  96. // ServiceWithConfig adds the config reference to the service
  97. func ServiceWithConfig(configRef *swarmtypes.ConfigReference) ServiceSpecOpt {
  98. return func(spec *swarmtypes.ServiceSpec) {
  99. ensureContainerSpec(spec)
  100. spec.TaskTemplate.ContainerSpec.Configs = append(spec.TaskTemplate.ContainerSpec.Configs, configRef)
  101. }
  102. }
  103. // ServiceWithSecret adds the secret reference to the service
  104. func ServiceWithSecret(secretRef *swarmtypes.SecretReference) ServiceSpecOpt {
  105. return func(spec *swarmtypes.ServiceSpec) {
  106. ensureContainerSpec(spec)
  107. spec.TaskTemplate.ContainerSpec.Secrets = append(spec.TaskTemplate.ContainerSpec.Secrets, secretRef)
  108. }
  109. }
  110. // ServiceWithReplicas sets the replicas for the service
  111. func ServiceWithReplicas(n uint64) ServiceSpecOpt {
  112. return func(spec *swarmtypes.ServiceSpec) {
  113. spec.Mode = swarmtypes.ServiceMode{
  114. Replicated: &swarmtypes.ReplicatedService{
  115. Replicas: &n,
  116. },
  117. }
  118. }
  119. }
  120. // ServiceWithName sets the name of the service
  121. func ServiceWithName(name string) ServiceSpecOpt {
  122. return func(spec *swarmtypes.ServiceSpec) {
  123. spec.Annotations.Name = name
  124. }
  125. }
  126. // ServiceWithNetwork sets the network of the service
  127. func ServiceWithNetwork(network string) ServiceSpecOpt {
  128. return func(spec *swarmtypes.ServiceSpec) {
  129. spec.TaskTemplate.Networks = append(spec.TaskTemplate.Networks,
  130. swarmtypes.NetworkAttachmentConfig{Target: network})
  131. }
  132. }
  133. // ServiceWithEndpoint sets the Endpoint of the service
  134. func ServiceWithEndpoint(endpoint *swarmtypes.EndpointSpec) ServiceSpecOpt {
  135. return func(spec *swarmtypes.ServiceSpec) {
  136. spec.EndpointSpec = endpoint
  137. }
  138. }
  139. // GetRunningTasks gets the list of running tasks for a service
  140. func GetRunningTasks(t *testing.T, d *daemon.Daemon, serviceID string) []swarmtypes.Task {
  141. t.Helper()
  142. client := d.NewClientT(t)
  143. defer client.Close()
  144. filterArgs := filters.NewArgs()
  145. filterArgs.Add("desired-state", "running")
  146. filterArgs.Add("service", serviceID)
  147. options := types.TaskListOptions{
  148. Filters: filterArgs,
  149. }
  150. tasks, err := client.TaskList(context.Background(), options)
  151. assert.NilError(t, err)
  152. return tasks
  153. }
  154. // ExecTask runs the passed in exec config on the given task
  155. func ExecTask(t *testing.T, d *daemon.Daemon, task swarmtypes.Task, config types.ExecConfig) types.HijackedResponse {
  156. t.Helper()
  157. client := d.NewClientT(t)
  158. defer client.Close()
  159. ctx := context.Background()
  160. resp, err := client.ContainerExecCreate(ctx, task.Status.ContainerStatus.ContainerID, config)
  161. assert.NilError(t, err, "error creating exec")
  162. startCheck := types.ExecStartCheck{}
  163. attach, err := client.ContainerExecAttach(ctx, resp.ID, startCheck)
  164. assert.NilError(t, err, "error attaching to exec")
  165. return attach
  166. }
  167. func ensureContainerSpec(spec *swarmtypes.ServiceSpec) {
  168. if spec.TaskTemplate.ContainerSpec == nil {
  169. spec.TaskTemplate.ContainerSpec = &swarmtypes.ContainerSpec{}
  170. }
  171. }