diff --git a/integration/config/config_test.go b/integration/config/config_test.go index 275ba0dcc3..6ebfd2df8b 100644 --- a/integration/config/config_test.go +++ b/integration/config/config_test.go @@ -333,15 +333,20 @@ func TestTemplatedConfig(t *testing.T) { outBuf.Reset() errBuf.Reset() + // Read the mount table rather than running mount(8): busybox's mount stops + // parsing at an over-long entry and drops it along with everything after it, + // and the task carries one - the init binary is bind-mounted from an overlay + // whose options list every lower directory. /proc/mounts is what mount(8) + // reads anyway, and cat doesn't parse it. resp = swarm.ExecTask(ctx, t, d, tasks[0], client.ExecCreateOptions{ - Cmd: []string{"mount"}, + Cmd: []string{"cat", "/proc/mounts"}, AttachStdout: true, AttachStderr: true, }) _, err = stdcopy.StdCopy(&outBuf, &errBuf, resp.Reader) assert.NilError(t, err) - assert.Check(t, is.Contains(outBuf.String(), "tmpfs on /templated_config type tmpfs"), "expected to be mounted as tmpfs") + assert.Check(t, is.Contains(outBuf.String(), "tmpfs /templated_config tmpfs"), "expected to be mounted as tmpfs") assert.Check(t, is.Equal(errBuf.String(), "")) } diff --git a/integration/internal/swarm/service.go b/integration/internal/swarm/service.go index 5035264737..603fb5e04d 100644 --- a/integration/internal/swarm/service.go +++ b/integration/internal/swarm/service.go @@ -68,13 +68,23 @@ func CreateService(ctx context.Context, t *testing.T, d *daemon.Daemon, opts ... return resp.ID } -// CreateServiceSpec creates a default service-spec, and applies the provided options +// CreateServiceSpec creates a default service-spec, and applies the provided options. +// +// The defaults include running tasks under an init, so a test that wants the +// daemon's own default instead has to say so with ServiceWithInit(nil) - saying +// nothing gets the init. func CreateServiceSpec(t *testing.T, opts ...ServiceSpecOpt) swarmtypes.ServiceSpec { t.Helper() var spec swarmtypes.ServiceSpec ServiceWithImage("busybox:latest")(&spec) ServiceWithCommand([]string{"/bin/top"})(&spec) ServiceWithReplicas(1)(&spec) + // Run tasks under an init. None of the commands these tests run install a + // SIGTERM handler, and a signal sent to PID 1 has no default action - so as + // PID 1 they ignore the stop signal, and every task teardown waits out the + // container's whole stop timeout before the kill. An init takes PID 1 and + // forwards the signal to a process the default action applies to. + ServiceWithInit(new(true))(&spec) for _, o := range opts { o(&spec) diff --git a/integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go b/integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go index 53eaa48b7f..6849667f34 100644 --- a/integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go +++ b/integration/network/bridge/iptablesdoc/iptablesdoc_linux_test.go @@ -366,6 +366,8 @@ func createServices(ctx context.Context, t *testing.T, d *daemon.Daemon, section ContainerSpec: &swarmtypes.ContainerSpec{ Image: "busybox:latest", Command: []string{"/bin/top"}, + // top ignores SIGTERM as PID 1; an init forwards it. + Init: new(true), }, }, EndpointSpec: &swarmtypes.EndpointSpec{ diff --git a/integration/secret/secret_test.go b/integration/secret/secret_test.go index 1c2dc7a4da..91a559fa9f 100644 --- a/integration/secret/secret_test.go +++ b/integration/secret/secret_test.go @@ -355,15 +355,20 @@ func TestTemplatedSecret(t *testing.T) { outBuf.Reset() errBuf.Reset() + // Read the mount table rather than running mount(8): busybox's mount stops + // parsing at an over-long entry and drops it along with everything after it, + // and the task carries one - the init binary is bind-mounted from an overlay + // whose options list every lower directory. /proc/mounts is what mount(8) + // reads anyway, and cat doesn't parse it. resp = swarm.ExecTask(ctx, t, d, tasks[0], client.ExecCreateOptions{ - Cmd: []string{"mount"}, + Cmd: []string{"cat", "/proc/mounts"}, AttachStdout: true, AttachStderr: true, }) _, err = stdcopy.StdCopy(&outBuf, &errBuf, resp.Reader) assert.NilError(t, err) - assert.Check(t, is.Contains(outBuf.String(), "tmpfs on /run/secrets/templated_secret type tmpfs"), "expected to be mounted as tmpfs") + assert.Check(t, is.Contains(outBuf.String(), "tmpfs /run/secrets/templated_secret tmpfs"), "expected to be mounted as tmpfs") assert.Check(t, is.Equal(errBuf.String(), "")) } diff --git a/integration/service/create_test.go b/integration/service/create_test.go index 8ca6d6b8b1..f7c4018e81 100644 --- a/integration/service/create_test.go +++ b/integration/service/create_test.go @@ -44,7 +44,10 @@ func testServiceCreateInit(ctx context.Context, daemonEnabled bool) func(t *test booleanTrue := true booleanFalse := false - serviceID := swarm.CreateService(ctx, t, d) + // An unset Init delegates to the daemon configuration, which is what this + // case is about - so ask for it explicitly, rather than relying on the + // spec helper leaving it unset. + serviceID := swarm.CreateService(ctx, t, d, swarm.ServiceWithInit(nil)) poll.WaitOn(t, swarm.RunningTasksCount(ctx, apiClient, serviceID, 1), swarm.ServicePoll) i := inspectServiceContainer(ctx, t, apiClient, serviceID) // HostConfig.Init == nil means that it delegates to daemon configuration