diff --git a/components/engine/daemon/cluster/controllers/plugin/controller.go b/components/engine/daemon/cluster/controllers/plugin/controller.go index dbeeb6daa3..f1d6dddb6a 100644 --- a/components/engine/daemon/cluster/controllers/plugin/controller.go +++ b/components/engine/daemon/cluster/controllers/plugin/controller.go @@ -26,7 +26,7 @@ import ( // We'll also end up with many tasks all pointing to the same plugin ID. // // TODO(@cpuguy83): registry auth is intentionally not supported until we work out -// the right way to pass registry crednetials via secrets. +// the right way to pass registry credentials via secrets. type Controller struct { backend Backend spec runtime.PluginSpec diff --git a/components/engine/daemon/graphdriver/lcow/lcow.go b/components/engine/daemon/graphdriver/lcow/lcow.go index 04701c9832..f5a2ee25fe 100644 --- a/components/engine/daemon/graphdriver/lcow/lcow.go +++ b/components/engine/daemon/graphdriver/lcow/lcow.go @@ -409,7 +409,7 @@ func (d *Driver) terminateServiceVM(id, context string, force bool) (err error) svm.signalStopFinished(err) }() - // Now it's possible that the serivce VM failed to start and now we are trying to termiante it. + // Now it's possible that the serivce VM failed to start and now we are trying to terminate it. // In this case, we will relay the error to the goroutines waiting for this vm to stop. if err := svm.getStartError(); err != nil { logrus.Debugf("lcowdriver: terminateservicevm: %s had failed to start up: %s", id, err) diff --git a/components/engine/daemon/logger/logger.go b/components/engine/daemon/logger/logger.go index a548768bf8..b64d77840e 100644 --- a/components/engine/daemon/logger/logger.go +++ b/components/engine/daemon/logger/logger.go @@ -42,7 +42,7 @@ func PutMessage(msg *Message) { messagePool.Put(msg) } -// Message is datastructure that represents piece of output produced by some +// Message is data structure that represents piece of output produced by some // container. The Line member is a slice of an array whose contents can be // changed after a log driver's Log() method returns. // @@ -133,7 +133,7 @@ func (w *LogWatcher) WatchClose() <-chan struct{} { return w.closeNotifier } -// Capability defines the list of capabilties that a driver can implement +// Capability defines the list of capabilities that a driver can implement // These capabilities are not required to be a logging driver, however do // determine how a logging driver can be used type Capability struct { diff --git a/components/engine/integration-cli/docker_api_session_test.go b/components/engine/integration-cli/docker_api_session_test.go deleted file mode 100644 index f1c44892d3..0000000000 --- a/components/engine/integration-cli/docker_api_session_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - "net/http" - - "github.com/docker/docker/integration-cli/checker" - "github.com/docker/docker/integration-cli/request" - "github.com/go-check/check" -) - -func (s *DockerSuite) TestSessionCreate(c *check.C) { - testRequires(c, ExperimentalDaemon) - - res, body, err := request.Post("/session", func(r *http.Request) error { - r.Header.Set("X-Docker-Expose-Session-Uuid", "testsessioncreate") // so we don't block default name if something else is using it - r.Header.Set("Upgrade", "h2c") - return nil - }) - c.Assert(err, checker.IsNil) - c.Assert(res.StatusCode, checker.Equals, http.StatusSwitchingProtocols) - c.Assert(res.Header.Get("Upgrade"), checker.Equals, "h2c") - c.Assert(body.Close(), checker.IsNil) -} - -func (s *DockerSuite) TestSessionCreateWithBadUpgrade(c *check.C) { - testRequires(c, ExperimentalDaemon) - - res, body, err := request.Post("/session") - c.Assert(err, checker.IsNil) - c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) - buf, err := request.ReadBody(body) - c.Assert(err, checker.IsNil) - - out := string(buf) - c.Assert(out, checker.Contains, "no upgrade") - - res, body, err = request.Post("/session", func(r *http.Request) error { - r.Header.Set("Upgrade", "foo") - return nil - }) - c.Assert(err, checker.IsNil) - c.Assert(res.StatusCode, checker.Equals, http.StatusBadRequest) - buf, err = request.ReadBody(body) - c.Assert(err, checker.IsNil) - - out = string(buf) - c.Assert(out, checker.Contains, "not supported") -} diff --git a/components/engine/integration-cli/docker_cli_pause_test.go b/components/engine/integration-cli/docker_cli_pause_test.go deleted file mode 100644 index 682384fc1a..0000000000 --- a/components/engine/integration-cli/docker_cli_pause_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package main - -import ( - "strings" - "time" - - "github.com/docker/docker/integration-cli/checker" - "github.com/docker/docker/integration-cli/cli" - "github.com/go-check/check" -) - -func (s *DockerSuite) TestPause(c *check.C) { - testRequires(c, IsPausable) - - name := "testeventpause" - runSleepingContainer(c, "-d", "--name", name) - - cli.DockerCmd(c, "pause", name) - pausedContainers := strings.Fields( - cli.DockerCmd(c, "ps", "-f", "status=paused", "-q", "-a").Combined(), - ) - c.Assert(len(pausedContainers), checker.Equals, 1) - - cli.DockerCmd(c, "unpause", name) - - out := cli.DockerCmd(c, "events", "--since=0", "--until", daemonUnixTime(c)).Combined() - events := strings.Split(strings.TrimSpace(out), "\n") - actions := eventActionsByIDAndType(c, events, name, "container") - - c.Assert(actions[len(actions)-2], checker.Equals, "pause") - c.Assert(actions[len(actions)-1], checker.Equals, "unpause") -} - -func (s *DockerSuite) TestPauseMultipleContainers(c *check.C) { - testRequires(c, IsPausable) - - containers := []string{ - "testpausewithmorecontainers1", - "testpausewithmorecontainers2", - } - for _, name := range containers { - runSleepingContainer(c, "-d", "--name", name) - } - cli.DockerCmd(c, append([]string{"pause"}, containers...)...) - pausedContainers := strings.Fields( - cli.DockerCmd(c, "ps", "-f", "status=paused", "-q", "-a").Combined(), - ) - c.Assert(len(pausedContainers), checker.Equals, len(containers)) - - cli.DockerCmd(c, append([]string{"unpause"}, containers...)...) - - out := cli.DockerCmd(c, "events", "--since=0", "--until", daemonUnixTime(c)).Combined() - events := strings.Split(strings.TrimSpace(out), "\n") - - for _, name := range containers { - actions := eventActionsByIDAndType(c, events, name, "container") - - c.Assert(actions[len(actions)-2], checker.Equals, "pause") - c.Assert(actions[len(actions)-1], checker.Equals, "unpause") - } -} - -func (s *DockerSuite) TestPauseFailsOnWindowsServerContainers(c *check.C) { - testRequires(c, DaemonIsWindows, NotPausable) - runSleepingContainer(c, "-d", "--name=test") - out, _, _ := dockerCmdWithError("pause", "test") - c.Assert(out, checker.Contains, "cannot pause Windows Server Containers") -} - -func (s *DockerSuite) TestStopPausedContainer(c *check.C) { - testRequires(c, DaemonIsLinux) - - id := runSleepingContainer(c) - cli.WaitRun(c, id) - cli.DockerCmd(c, "pause", id) - cli.DockerCmd(c, "stop", id) - cli.WaitForInspectResult(c, id, "{{.State.Running}}", "false", 30*time.Second) -} diff --git a/components/engine/integration/container/daemon_linux_test.go b/components/engine/integration/container/daemon_linux_test.go new file mode 100644 index 0000000000..872c7ab4cc --- /dev/null +++ b/components/engine/integration/container/daemon_linux_test.go @@ -0,0 +1,84 @@ +package container + +import ( + "context" + "fmt" + "io/ioutil" + "strconv" + "strings" + "testing" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/integration-cli/daemon" + "github.com/stretchr/testify/assert" + "golang.org/x/sys/unix" +) + +// This is a regression test for #36145 +// It ensures that a container can be started when the daemon was improperly +// shutdown when the daemon is brought back up. +// +// The regression is due to improper error handling preventing a container from +// being restored and as such have the resources cleaned up. +// +// To test this, we need to kill dockerd, then kill both the containerd-shim and +// the container process, then start dockerd back up and attempt to start the +// container again. +func TestContainerStartOnDaemonRestart(t *testing.T) { + t.Parallel() + + d := daemon.New(t, "", "dockerd", daemon.Config{}) + d.StartWithBusybox(t, "--iptables=false") + defer d.Stop(t) + + client, err := d.NewClient() + assert.NoError(t, err, "error creating client") + + ctx := context.Background() + c, err := client.ContainerCreate(ctx, + &container.Config{ + Image: "busybox", + Cmd: []string{"top"}, + }, + nil, + nil, + "", + ) + assert.NoError(t, err, "error creating test container") + defer client.ContainerRemove(ctx, c.ID, types.ContainerRemoveOptions{Force: true}) + + err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{}) + assert.NoError(t, err, "error starting test container") + + inspect, err := client.ContainerInspect(ctx, c.ID) + assert.NoError(t, err, "error getting inspect data") + + ppid := getContainerdShimPid(t, inspect) + + err = d.Kill() + assert.NoError(t, err, "failed to kill test daemon") + + err = unix.Kill(inspect.State.Pid, unix.SIGKILL) + assert.NoError(t, err, "failed to kill container process") + + err = unix.Kill(ppid, unix.SIGKILL) + assert.NoError(t, err, "failed to kill containerd-shim") + + d.Start(t, "--iptables=false") + + err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{}) + assert.NoError(t, err, "failed to start test container") +} + +func getContainerdShimPid(t *testing.T, c types.ContainerJSON) int { + statB, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/stat", c.State.Pid)) + assert.NoError(t, err, "error looking up containerd-shim pid") + + // ppid is the 4th entry in `/proc/pid/stat` + ppid, err := strconv.Atoi(strings.Fields(string(statB))[3]) + assert.NoError(t, err, "error converting ppid field to int") + + assert.NotEqual(t, ppid, 1, "got unexpected ppid") + return ppid +} diff --git a/components/engine/integration/container/pause_test.go b/components/engine/integration/container/pause_test.go new file mode 100644 index 0000000000..4e64357221 --- /dev/null +++ b/components/engine/integration/container/pause_test.go @@ -0,0 +1,98 @@ +package container // import "github.com/docker/docker/integration/container" + +import ( + "context" + "io" + "testing" + "time" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/events" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/integration/internal/container" + "github.com/docker/docker/integration/internal/request" + "github.com/docker/docker/internal/testutil" + "github.com/gotestyourself/gotestyourself/poll" + "github.com/gotestyourself/gotestyourself/skip" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPause(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType == "windows" && testEnv.DaemonInfo.Isolation == "process") + + defer setupTest(t)() + client := request.NewAPIClient(t) + ctx := context.Background() + + name := "testeventpause" + cID := container.Run(t, ctx, client, container.WithName(name)) + poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond)) + + since := request.DaemonUnixTime(ctx, t, client, testEnv) + + err := client.ContainerPause(ctx, name) + require.NoError(t, err) + + inspect, err := client.ContainerInspect(ctx, cID) + require.NoError(t, err) + assert.Equal(t, inspect.State.Paused, true) + + err = client.ContainerUnpause(ctx, name) + require.NoError(t, err) + + until := request.DaemonUnixTime(ctx, t, client, testEnv) + + messages, errs := client.Events(ctx, types.EventsOptions{ + Since: since, + Until: until, + Filters: filters.NewArgs(filters.Arg("container", name)), + }) + assert.Equal(t, getEventActions(t, messages, errs), []string{"pause", "unpause"}) +} + +func TestPauseFailsOnWindowsServerContainers(t *testing.T) { + skip.If(t, (testEnv.DaemonInfo.OSType != "windows" || testEnv.DaemonInfo.Isolation != "process")) + + defer setupTest(t)() + client := request.NewAPIClient(t) + ctx := context.Background() + + cID := container.Run(t, ctx, client) + poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond)) + + err := client.ContainerPause(ctx, cID) + testutil.ErrorContains(t, err, "cannot pause Windows Server Containers") +} + +func TestPauseStopPausedContainer(t *testing.T) { + skip.If(t, testEnv.DaemonInfo.OSType != "linux") + + defer setupTest(t)() + client := request.NewAPIClient(t) + ctx := context.Background() + + cID := container.Run(t, ctx, client) + poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond)) + + err := client.ContainerPause(ctx, cID) + require.NoError(t, err) + + err = client.ContainerStop(ctx, cID, nil) + require.NoError(t, err) + + poll.WaitOn(t, containerIsStopped(ctx, client, cID), poll.WithDelay(100*time.Millisecond)) +} + +func getEventActions(t *testing.T, messages <-chan events.Message, errs <-chan error) []string { + actions := []string{} + for { + select { + case err := <-errs: + assert.Equal(t, err == nil || err == io.EOF, true) + return actions + case e := <-messages: + actions = append(actions, e.Status) + } + } +} diff --git a/components/engine/integration/container/stop_test.go b/components/engine/integration/container/stop_test.go index 0a9daff2bd..305596ac85 100644 --- a/components/engine/integration/container/stop_test.go +++ b/components/engine/integration/container/stop_test.go @@ -8,9 +8,8 @@ import ( "time" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" + "github.com/docker/docker/integration/internal/container" "github.com/docker/docker/integration/internal/request" "github.com/gotestyourself/gotestyourself/icmd" "github.com/gotestyourself/gotestyourself/poll" @@ -25,23 +24,9 @@ func TestStopContainerWithRestartPolicyAlways(t *testing.T) { names := []string{"verifyRestart1", "verifyRestart2"} for _, name := range names { - resp, err := client.ContainerCreate(ctx, - &container.Config{ - Cmd: []string{"false"}, - Image: "busybox", - }, - &container.HostConfig{ - RestartPolicy: container.RestartPolicy{ - Name: "always", - }, - }, - &network.NetworkingConfig{}, - name, - ) - require.NoError(t, err) - - err = client.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}) - require.NoError(t, err) + container.Run(t, ctx, client, container.WithName(name), container.WithCmd("false"), func(c *container.TestContainerConfig) { + c.HostConfig.RestartPolicy.Name = "always" + }) } for _, name := range names { @@ -65,25 +50,13 @@ func TestDeleteDevicemapper(t *testing.T) { client := request.NewAPIClient(t) ctx := context.Background() - foo, err := client.ContainerCreate(ctx, - &container.Config{ - Cmd: []string{"echo"}, - Image: "busybox", - }, - &container.HostConfig{}, - &network.NetworkingConfig{}, - "foo", - ) - require.NoError(t, err) + id := container.Run(t, ctx, client, container.WithName("foo"), container.WithCmd("echo")) - err = client.ContainerStart(ctx, foo.ID, types.ContainerStartOptions{}) - require.NoError(t, err) + poll.WaitOn(t, containerIsStopped(ctx, client, id), poll.WithDelay(100*time.Millisecond)) - inspect, err := client.ContainerInspect(ctx, foo.ID) + inspect, err := client.ContainerInspect(ctx, id) require.NoError(t, err) - poll.WaitOn(t, containerIsStopped(ctx, client, foo.ID), poll.WithDelay(100*time.Millisecond)) - deviceID := inspect.GraphDriver.Data["DeviceId"] // Find pool name from device name @@ -94,7 +67,7 @@ func TestDeleteDevicemapper(t *testing.T) { result := icmd.RunCommand("dmsetup", "message", devicePool, "0", fmt.Sprintf("delete %s", deviceID)) result.Assert(t, icmd.Success) - err = client.ContainerRemove(ctx, foo.ID, types.ContainerRemoveOptions{}) + err = client.ContainerRemove(ctx, id, types.ContainerRemoveOptions{}) require.NoError(t, err) } diff --git a/components/engine/integration/container/update_linux_test.go b/components/engine/integration/container/update_linux_test.go index f8138624b9..ef9397c209 100644 --- a/components/engine/integration/container/update_linux_test.go +++ b/components/engine/integration/container/update_linux_test.go @@ -3,7 +3,6 @@ package container // import "github.com/docker/docker/integration/container" import ( "bytes" "context" - "fmt" "io/ioutil" "strconv" "strings" @@ -11,9 +10,10 @@ import ( "time" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" + containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/strslice" "github.com/docker/docker/client" + "github.com/docker/docker/integration/internal/container" "github.com/docker/docker/integration/internal/request" "github.com/docker/docker/pkg/stdcopy" "github.com/gotestyourself/gotestyourself/poll" @@ -31,44 +31,32 @@ func TestUpdateMemory(t *testing.T) { client := request.NewAPIClient(t) ctx := context.Background() - c, err := client.ContainerCreate(ctx, - &container.Config{ - Cmd: []string{"top"}, - Image: "busybox", - }, - &container.HostConfig{ - Resources: container.Resources{ - Memory: 200 * 1024 * 1024, - }, - }, - nil, - "", - ) - require.NoError(t, err) + cID := container.Run(t, ctx, client, func(c *container.TestContainerConfig) { + c.HostConfig.Resources = containertypes.Resources{ + Memory: 200 * 1024 * 1024, + } + }) - err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{}) - require.NoError(t, err) + poll.WaitOn(t, containerIsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond)) - poll.WaitOn(t, containerIsInState(ctx, client, c.ID, "running"), poll.WithDelay(100*time.Millisecond)) - - _, err = client.ContainerUpdate(ctx, c.ID, container.UpdateConfig{ - Resources: container.Resources{ + _, err := client.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{ + Resources: containertypes.Resources{ Memory: 314572800, MemorySwap: 524288000, }, }) require.NoError(t, err) - inspect, err := client.ContainerInspect(ctx, c.ID) + inspect, err := client.ContainerInspect(ctx, cID) require.NoError(t, err) assert.Equal(t, inspect.HostConfig.Memory, int64(314572800)) assert.Equal(t, inspect.HostConfig.MemorySwap, int64(524288000)) - body, err := getContainerSysFSValue(ctx, client, c.ID, "/sys/fs/cgroup/memory/memory.limit_in_bytes") + body, err := getContainerSysFSValue(ctx, client, cID, "/sys/fs/cgroup/memory/memory.limit_in_bytes") require.NoError(t, err) assert.Equal(t, strings.TrimSpace(body), "314572800") - body, err = getContainerSysFSValue(ctx, client, c.ID, "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes") + body, err = getContainerSysFSValue(ctx, client, cID, "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes") require.NoError(t, err) assert.Equal(t, strings.TrimSpace(body), "524288000") } @@ -76,25 +64,11 @@ func TestUpdateMemory(t *testing.T) { func TestUpdateCPUQUota(t *testing.T) { t.Parallel() + defer setupTest(t)() client := request.NewAPIClient(t) ctx := context.Background() - c, err := client.ContainerCreate(ctx, &container.Config{ - Image: "busybox", - Cmd: []string{"top"}, - }, nil, nil, "") - if err != nil { - t.Fatal(err) - } - defer func() { - if err := client.ContainerRemove(ctx, c.ID, types.ContainerRemoveOptions{Force: true}); err != nil { - panic(fmt.Sprintf("failed to clean up after test: %v", err)) - } - }() - - if err := client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{}); err != nil { - t.Fatal(err) - } + cID := container.Run(t, ctx, client) for _, test := range []struct { desc string @@ -105,15 +79,15 @@ func TestUpdateCPUQUota(t *testing.T) { {desc: "a lower value", update: 10000}, {desc: "unset value", update: -1}, } { - if _, err := client.ContainerUpdate(ctx, c.ID, container.UpdateConfig{ - Resources: container.Resources{ + if _, err := client.ContainerUpdate(ctx, cID, containertypes.UpdateConfig{ + Resources: containertypes.Resources{ CPUQuota: test.update, }, }); err != nil { t.Fatal(err) } - inspect, err := client.ContainerInspect(ctx, c.ID) + inspect, err := client.ContainerInspect(ctx, cID) if err != nil { t.Fatal(err) } @@ -122,7 +96,7 @@ func TestUpdateCPUQUota(t *testing.T) { t.Fatalf("quota not updated in the API, expected %d, got: %d", test.update, inspect.HostConfig.CPUQuota) } - execCreate, err := client.ContainerExecCreate(ctx, c.ID, types.ExecConfig{ + execCreate, err := client.ContainerExecCreate(ctx, cID, types.ExecConfig{ Cmd: []string{"/bin/cat", "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"}, AttachStdout: true, AttachStderr: true, diff --git a/components/engine/integration/internal/request/client.go b/components/engine/integration/internal/request/client.go index ca2486af4c..4bfb5c7673 100644 --- a/components/engine/integration/internal/request/client.go +++ b/components/engine/integration/internal/request/client.go @@ -1,12 +1,16 @@ package request // import "github.com/docker/docker/integration/internal/request" import ( + "fmt" "net" "net/http" "testing" "time" + "golang.org/x/net/context" + "github.com/docker/docker/client" + "github.com/docker/docker/internal/test/environment" "github.com/docker/go-connections/sockets" "github.com/docker/go-connections/tlsconfig" "github.com/stretchr/testify/require" @@ -49,3 +53,24 @@ func NewTLSAPIClient(t *testing.T, host, cacertPath, certPath, keyPath string) ( } return client.NewClientWithOpts(client.WithHost(host), client.WithHTTPClient(httpClient)) } + +// daemonTime provides the current time on the daemon host +func daemonTime(ctx context.Context, t *testing.T, client client.APIClient, testEnv *environment.Execution) time.Time { + if testEnv.IsLocalDaemon() { + return time.Now() + } + + info, err := client.Info(ctx) + require.NoError(t, err) + + dt, err := time.Parse(time.RFC3339Nano, info.SystemTime) + require.NoError(t, err, "invalid time format in GET /info response") + return dt +} + +// DaemonUnixTime returns the current time on the daemon host with nanoseconds precision. +// It return the time formatted how the client sends timestamps to the server. +func DaemonUnixTime(ctx context.Context, t *testing.T, client client.APIClient, testEnv *environment.Execution) string { + dt := daemonTime(ctx, t, client, testEnv) + return fmt.Sprintf("%d.%09d", dt.Unix(), int64(dt.Nanosecond())) +} diff --git a/components/engine/integration/service/network_test.go b/components/engine/integration/service/network_test.go index 22b271c8c2..09b0a1f12b 100644 --- a/components/engine/integration/service/network_test.go +++ b/components/engine/integration/service/network_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" + "github.com/docker/docker/integration/internal/container" "github.com/docker/docker/integration/internal/swarm" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -27,20 +27,15 @@ func TestDockerNetworkConnectAlias(t *testing.T) { Attachable: true, }) require.NoError(t, err) - _, err = client.ContainerCreate(ctx, - &container.Config{ - Cmd: []string{"top"}, - Image: "busybox", - }, - &container.HostConfig{}, - &network.NetworkingConfig{ - EndpointsConfig: map[string]*network.EndpointSettings{ + + container.Create(t, ctx, client, container.WithName("ng1"), func(c *container.TestContainerConfig) { + c.NetworkingConfig = &network.NetworkingConfig{ + map[string]*network.EndpointSettings{ name: {}, }, - }, - "ng1", - ) - require.NoError(t, err) + } + }) + err = client.NetworkConnect(ctx, name, "ng1", &network.EndpointSettings{ Aliases: []string{ "aaa", @@ -56,20 +51,14 @@ func TestDockerNetworkConnectAlias(t *testing.T) { assert.Equal(t, len(ng1.NetworkSettings.Networks[name].Aliases), 2) assert.Equal(t, ng1.NetworkSettings.Networks[name].Aliases[0], "aaa") - _, err = client.ContainerCreate(ctx, - &container.Config{ - Cmd: []string{"top"}, - Image: "busybox", - }, - &container.HostConfig{}, - &network.NetworkingConfig{ - EndpointsConfig: map[string]*network.EndpointSettings{ + container.Create(t, ctx, client, container.WithName("ng2"), func(c *container.TestContainerConfig) { + c.NetworkingConfig = &network.NetworkingConfig{ + map[string]*network.EndpointSettings{ name: {}, }, - }, - "ng2", - ) - require.NoError(t, err) + } + }) + err = client.NetworkConnect(ctx, name, "ng2", &network.EndpointSettings{ Aliases: []string{ "bbb", diff --git a/components/engine/integration/session/main_test.go b/components/engine/integration/session/main_test.go new file mode 100644 index 0000000000..fc33025efe --- /dev/null +++ b/components/engine/integration/session/main_test.go @@ -0,0 +1,33 @@ +package session // import "github.com/docker/docker/integration/session" + +import ( + "fmt" + "os" + "testing" + + "github.com/docker/docker/internal/test/environment" +) + +var testEnv *environment.Execution + +func TestMain(m *testing.M) { + var err error + testEnv, err = environment.New() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + err = environment.EnsureFrozenImagesLinux(testEnv) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + testEnv.Print() + os.Exit(m.Run()) +} + +func setupTest(t *testing.T) func() { + environment.ProtectAll(t, testEnv) + return func() { testEnv.Clean(t) } +} diff --git a/components/engine/integration/session/session_test.go b/components/engine/integration/session/session_test.go new file mode 100644 index 0000000000..310f544554 --- /dev/null +++ b/components/engine/integration/session/session_test.go @@ -0,0 +1,48 @@ +package session // import "github.com/docker/docker/integration/session" + +import ( + "net/http" + "testing" + + req "github.com/docker/docker/integration-cli/request" + "github.com/gotestyourself/gotestyourself/skip" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSessionCreate(t *testing.T) { + skip.If(t, !testEnv.DaemonInfo.ExperimentalBuild) + + defer setupTest(t)() + + res, body, err := req.Post("/session", func(r *http.Request) error { + r.Header.Set("X-Docker-Expose-Session-Uuid", "testsessioncreate") // so we don't block default name if something else is using it + r.Header.Set("Upgrade", "h2c") + return nil + }) + require.NoError(t, err) + require.NoError(t, body.Close()) + assert.Equal(t, res.StatusCode, http.StatusSwitchingProtocols) + assert.Equal(t, res.Header.Get("Upgrade"), "h2c") +} + +func TestSessionCreateWithBadUpgrade(t *testing.T) { + skip.If(t, !testEnv.DaemonInfo.ExperimentalBuild) + + res, body, err := req.Post("/session") + require.NoError(t, err) + assert.Equal(t, res.StatusCode, http.StatusBadRequest) + buf, err := req.ReadBody(body) + require.NoError(t, err) + assert.Contains(t, string(buf), "no upgrade") + + res, body, err = req.Post("/session", func(r *http.Request) error { + r.Header.Set("Upgrade", "foo") + return nil + }) + require.NoError(t, err) + assert.Equal(t, res.StatusCode, http.StatusBadRequest) + buf, err = req.ReadBody(body) + require.NoError(t, err) + assert.Contains(t, string(buf), "not supported") +} diff --git a/components/engine/integration/system/event_test.go b/components/engine/integration/system/event_test.go index 5094e188ff..7f04195690 100644 --- a/components/engine/integration/system/event_test.go +++ b/components/engine/integration/system/event_test.go @@ -7,10 +7,9 @@ import ( "time" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" - "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/strslice" + "github.com/docker/docker/integration/internal/container" "github.com/docker/docker/integration/internal/request" "github.com/stretchr/testify/require" ) @@ -20,22 +19,9 @@ func TestEvents(t *testing.T) { ctx := context.Background() client := request.NewAPIClient(t) - container, err := client.ContainerCreate(ctx, - &container.Config{ - Image: "busybox", - Tty: true, - WorkingDir: "/root", - Cmd: strslice.StrSlice([]string{"top"}), - }, - &container.HostConfig{}, - &network.NetworkingConfig{}, - "foo", - ) - require.NoError(t, err) - err = client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{}) - require.NoError(t, err) + cID := container.Run(t, ctx, client) - id, err := client.ContainerExecCreate(ctx, container.ID, + id, err := client.ContainerExecCreate(ctx, cID, types.ExecConfig{ Cmd: strslice.StrSlice([]string{"echo", "hello"}), }, @@ -43,7 +29,7 @@ func TestEvents(t *testing.T) { require.NoError(t, err) filters := filters.NewArgs( - filters.Arg("container", container.ID), + filters.Arg("container", cID), filters.Arg("event", "exec_die"), ) msg, errors := client.Events(ctx, types.EventsOptions{ @@ -61,7 +47,7 @@ func TestEvents(t *testing.T) { select { case m := <-msg: require.Equal(t, m.Type, "container") - require.Equal(t, m.Actor.ID, container.ID) + require.Equal(t, m.Actor.ID, cID) require.Equal(t, m.Action, "exec_die") require.Equal(t, m.Actor.Attributes["execID"], id.ID) require.Equal(t, m.Actor.Attributes["exitCode"], "0") diff --git a/components/engine/libcontainerd/client_daemon.go b/components/engine/libcontainerd/client_daemon.go index eef3a4863d..2c914469a1 100644 --- a/components/engine/libcontainerd/client_daemon.go +++ b/components/engine/libcontainerd/client_daemon.go @@ -159,7 +159,7 @@ func (c *client) Restore(ctx context.Context, id string, attachStdio StdioCallba return attachStdio(dio) } t, err := ctr.Task(ctx, attachIO) - if err != nil && !errdefs.IsNotFound(errors.Cause(err)) { + if err != nil && !containerderrors.IsNotFound(err) { return false, -1, err }