service.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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 = 1 * time.Minute
  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. // 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. t.Helper()
  122. client := d.NewClientT(t)
  123. defer client.Close()
  124. filterArgs := filters.NewArgs()
  125. filterArgs.Add("desired-state", "running")
  126. filterArgs.Add("service", serviceID)
  127. options := types.TaskListOptions{
  128. Filters: filterArgs,
  129. }
  130. tasks, err := client.TaskList(context.Background(), options)
  131. assert.NilError(t, err)
  132. return tasks
  133. }
  134. // ExecTask runs the passed in exec config on the given task
  135. func ExecTask(t *testing.T, d *daemon.Daemon, task swarmtypes.Task, config types.ExecConfig) types.HijackedResponse {
  136. t.Helper()
  137. client := d.NewClientT(t)
  138. defer client.Close()
  139. ctx := context.Background()
  140. resp, err := client.ContainerExecCreate(ctx, task.Status.ContainerStatus.ContainerID, config)
  141. assert.NilError(t, err, "error creating exec")
  142. startCheck := types.ExecStartCheck{}
  143. attach, err := client.ContainerExecAttach(ctx, resp.ID, startCheck)
  144. assert.NilError(t, err, "error attaching to exec")
  145. return attach
  146. }
  147. func ensureContainerSpec(spec *swarmtypes.ServiceSpec) {
  148. if spec.TaskTemplate.ContainerSpec == nil {
  149. spec.TaskTemplate.ContainerSpec = &swarmtypes.ContainerSpec{}
  150. }
  151. }