github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/integration/internal/swarm/service.go (about)

     1  package swarm
     2  
     3  import (
     4  	"context"
     5  	"runtime"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/docker/docker/api/types"
    10  	"github.com/docker/docker/api/types/filters"
    11  	swarmtypes "github.com/docker/docker/api/types/swarm"
    12  	"github.com/docker/docker/client"
    13  	"github.com/docker/docker/internal/test/daemon"
    14  	"github.com/docker/docker/internal/test/environment"
    15  	"gotest.tools/assert"
    16  	"gotest.tools/poll"
    17  	"gotest.tools/skip"
    18  )
    19  
    20  // ServicePoll tweaks the pollSettings for `service`
    21  func ServicePoll(config *poll.Settings) {
    22  	// Override the default pollSettings for `service` resource here ...
    23  	config.Timeout = 30 * time.Second
    24  	config.Delay = 100 * time.Millisecond
    25  	if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" {
    26  		config.Timeout = 90 * time.Second
    27  	}
    28  }
    29  
    30  // NetworkPoll tweaks the pollSettings for `network`
    31  func NetworkPoll(config *poll.Settings) {
    32  	// Override the default pollSettings for `network` resource here ...
    33  	config.Timeout = 30 * time.Second
    34  	config.Delay = 100 * time.Millisecond
    35  
    36  	if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" {
    37  		config.Timeout = 50 * time.Second
    38  	}
    39  }
    40  
    41  // ContainerPoll tweaks the pollSettings for `container`
    42  func ContainerPoll(config *poll.Settings) {
    43  	// Override the default pollSettings for `container` resource here ...
    44  
    45  	if runtime.GOARCH == "arm64" || runtime.GOARCH == "arm" {
    46  		config.Timeout = 30 * time.Second
    47  		config.Delay = 100 * time.Millisecond
    48  	}
    49  }
    50  
    51  // NewSwarm creates a swarm daemon for testing
    52  func NewSwarm(t *testing.T, testEnv *environment.Execution, ops ...func(*daemon.Daemon)) *daemon.Daemon {
    53  	t.Helper()
    54  	skip.If(t, testEnv.IsRemoteDaemon)
    55  	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
    56  	if testEnv.DaemonInfo.ExperimentalBuild {
    57  		ops = append(ops, daemon.WithExperimental)
    58  	}
    59  	d := daemon.New(t, ops...)
    60  	d.StartAndSwarmInit(t)
    61  	return d
    62  }
    63  
    64  // ServiceSpecOpt is used with `CreateService` to pass in service spec modifiers
    65  type ServiceSpecOpt func(*swarmtypes.ServiceSpec)
    66  
    67  // CreateService creates a service on the passed in swarm daemon.
    68  func CreateService(t *testing.T, d *daemon.Daemon, opts ...ServiceSpecOpt) string {
    69  	t.Helper()
    70  
    71  	client := d.NewClientT(t)
    72  	defer client.Close()
    73  
    74  	spec := CreateServiceSpec(t, opts...)
    75  	resp, err := client.ServiceCreate(context.Background(), spec, types.ServiceCreateOptions{})
    76  	assert.NilError(t, err, "error creating service")
    77  	return resp.ID
    78  }
    79  
    80  // CreateServiceSpec creates a default service-spec, and applies the provided options
    81  func CreateServiceSpec(t *testing.T, opts ...ServiceSpecOpt) swarmtypes.ServiceSpec {
    82  	t.Helper()
    83  	var spec swarmtypes.ServiceSpec
    84  	ServiceWithImage("busybox:latest")(&spec)
    85  	ServiceWithCommand([]string{"/bin/top"})(&spec)
    86  	ServiceWithReplicas(1)(&spec)
    87  
    88  	for _, o := range opts {
    89  		o(&spec)
    90  	}
    91  	return spec
    92  }
    93  
    94  // ServiceWithInit sets whether the service should use init or not
    95  func ServiceWithInit(b *bool) func(*swarmtypes.ServiceSpec) {
    96  	return func(spec *swarmtypes.ServiceSpec) {
    97  		ensureContainerSpec(spec)
    98  		spec.TaskTemplate.ContainerSpec.Init = b
    99  	}
   100  }
   101  
   102  // ServiceWithImage sets the image to use for the service
   103  func ServiceWithImage(image string) func(*swarmtypes.ServiceSpec) {
   104  	return func(spec *swarmtypes.ServiceSpec) {
   105  		ensureContainerSpec(spec)
   106  		spec.TaskTemplate.ContainerSpec.Image = image
   107  	}
   108  }
   109  
   110  // ServiceWithCommand sets the command to use for the service
   111  func ServiceWithCommand(cmd []string) ServiceSpecOpt {
   112  	return func(spec *swarmtypes.ServiceSpec) {
   113  		ensureContainerSpec(spec)
   114  		spec.TaskTemplate.ContainerSpec.Command = cmd
   115  	}
   116  }
   117  
   118  // ServiceWithConfig adds the config reference to the service
   119  func ServiceWithConfig(configRef *swarmtypes.ConfigReference) ServiceSpecOpt {
   120  	return func(spec *swarmtypes.ServiceSpec) {
   121  		ensureContainerSpec(spec)
   122  		spec.TaskTemplate.ContainerSpec.Configs = append(spec.TaskTemplate.ContainerSpec.Configs, configRef)
   123  	}
   124  }
   125  
   126  // ServiceWithSecret adds the secret reference to the service
   127  func ServiceWithSecret(secretRef *swarmtypes.SecretReference) ServiceSpecOpt {
   128  	return func(spec *swarmtypes.ServiceSpec) {
   129  		ensureContainerSpec(spec)
   130  		spec.TaskTemplate.ContainerSpec.Secrets = append(spec.TaskTemplate.ContainerSpec.Secrets, secretRef)
   131  	}
   132  }
   133  
   134  // ServiceWithReplicas sets the replicas for the service
   135  func ServiceWithReplicas(n uint64) ServiceSpecOpt {
   136  	return func(spec *swarmtypes.ServiceSpec) {
   137  		spec.Mode = swarmtypes.ServiceMode{
   138  			Replicated: &swarmtypes.ReplicatedService{
   139  				Replicas: &n,
   140  			},
   141  		}
   142  	}
   143  }
   144  
   145  // ServiceWithMaxReplicas sets the max replicas for the service
   146  func ServiceWithMaxReplicas(n uint64) ServiceSpecOpt {
   147  	return func(spec *swarmtypes.ServiceSpec) {
   148  		ensurePlacement(spec)
   149  		spec.TaskTemplate.Placement.MaxReplicas = n
   150  	}
   151  }
   152  
   153  // ServiceWithName sets the name of the service
   154  func ServiceWithName(name string) ServiceSpecOpt {
   155  	return func(spec *swarmtypes.ServiceSpec) {
   156  		spec.Annotations.Name = name
   157  	}
   158  }
   159  
   160  // ServiceWithNetwork sets the network of the service
   161  func ServiceWithNetwork(network string) ServiceSpecOpt {
   162  	return func(spec *swarmtypes.ServiceSpec) {
   163  		spec.TaskTemplate.Networks = append(spec.TaskTemplate.Networks,
   164  			swarmtypes.NetworkAttachmentConfig{Target: network})
   165  	}
   166  }
   167  
   168  // ServiceWithEndpoint sets the Endpoint of the service
   169  func ServiceWithEndpoint(endpoint *swarmtypes.EndpointSpec) ServiceSpecOpt {
   170  	return func(spec *swarmtypes.ServiceSpec) {
   171  		spec.EndpointSpec = endpoint
   172  	}
   173  }
   174  
   175  // ServiceWithSysctls sets the Sysctls option of the service's ContainerSpec.
   176  func ServiceWithSysctls(sysctls map[string]string) ServiceSpecOpt {
   177  	return func(spec *swarmtypes.ServiceSpec) {
   178  		ensureContainerSpec(spec)
   179  		spec.TaskTemplate.ContainerSpec.Sysctls = sysctls
   180  	}
   181  }
   182  
   183  // GetRunningTasks gets the list of running tasks for a service
   184  func GetRunningTasks(t *testing.T, c client.ServiceAPIClient, serviceID string) []swarmtypes.Task {
   185  	t.Helper()
   186  
   187  	tasks, err := c.TaskList(context.Background(), types.TaskListOptions{
   188  		Filters: filters.NewArgs(
   189  			filters.Arg("service", serviceID),
   190  			filters.Arg("desired-state", "running"),
   191  		),
   192  	})
   193  
   194  	assert.NilError(t, err)
   195  	return tasks
   196  }
   197  
   198  // ExecTask runs the passed in exec config on the given task
   199  func ExecTask(t *testing.T, d *daemon.Daemon, task swarmtypes.Task, config types.ExecConfig) types.HijackedResponse {
   200  	t.Helper()
   201  	client := d.NewClientT(t)
   202  	defer client.Close()
   203  
   204  	ctx := context.Background()
   205  	resp, err := client.ContainerExecCreate(ctx, task.Status.ContainerStatus.ContainerID, config)
   206  	assert.NilError(t, err, "error creating exec")
   207  
   208  	startCheck := types.ExecStartCheck{}
   209  	attach, err := client.ContainerExecAttach(ctx, resp.ID, startCheck)
   210  	assert.NilError(t, err, "error attaching to exec")
   211  	return attach
   212  }
   213  
   214  func ensureContainerSpec(spec *swarmtypes.ServiceSpec) {
   215  	if spec.TaskTemplate.ContainerSpec == nil {
   216  		spec.TaskTemplate.ContainerSpec = &swarmtypes.ContainerSpec{}
   217  	}
   218  }
   219  
   220  func ensurePlacement(spec *swarmtypes.ServiceSpec) {
   221  	if spec.TaskTemplate.Placement == nil {
   222  		spec.TaskTemplate.Placement = &swarmtypes.Placement{}
   223  	}
   224  }