|
@@ -30,6 +30,9 @@ import (
|
|
|
"github.com/docker/docker/volume"
|
|
|
"github.com/docker/go-connections/nat"
|
|
|
"github.com/go-check/check"
|
|
|
+ "github.com/gotestyourself/gotestyourself/poll"
|
|
|
+ "github.com/stretchr/testify/assert"
|
|
|
+ "github.com/stretchr/testify/require"
|
|
|
"golang.org/x/net/context"
|
|
|
)
|
|
|
|
|
@@ -1921,7 +1924,23 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *check.C) {
|
|
|
{mounttypes.Mount{Type: "volume", Target: destPath + slash}, types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath}},
|
|
|
{mounttypes.Mount{Type: "volume", Target: destPath, Source: "test1"}, types.MountPoint{Type: "volume", Name: "test1", RW: true, Destination: destPath}},
|
|
|
{mounttypes.Mount{Type: "volume", Target: destPath, ReadOnly: true, Source: "test2"}, types.MountPoint{Type: "volume", Name: "test2", RW: false, Destination: destPath}},
|
|
|
- {mounttypes.Mount{Type: "volume", Target: destPath, Source: "test3", VolumeOptions: &mounttypes.VolumeOptions{DriverConfig: &mounttypes.Driver{Name: volume.DefaultDriverName}}}, types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", Name: "test3", RW: true, Destination: destPath}},
|
|
|
+ {
|
|
|
+ mounttypes.Mount{
|
|
|
+ Type: "volume",
|
|
|
+ Target: destPath,
|
|
|
+ Source: "test3",
|
|
|
+ VolumeOptions: &mounttypes.VolumeOptions{
|
|
|
+ DriverConfig: &mounttypes.Driver{Name: volume.DefaultDriverName},
|
|
|
+ },
|
|
|
+ },
|
|
|
+ types.MountPoint{
|
|
|
+ Driver: volume.DefaultDriverName,
|
|
|
+ Type: "volume",
|
|
|
+ Name: "test3",
|
|
|
+ RW: true,
|
|
|
+ Destination: destPath,
|
|
|
+ },
|
|
|
+ },
|
|
|
}
|
|
|
|
|
|
if SameHostDaemon() {
|
|
@@ -1930,7 +1949,19 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *check.C) {
|
|
|
c.Assert(err, checker.IsNil)
|
|
|
defer os.RemoveAll(tmpDir1)
|
|
|
cases = append(cases, []testCase{
|
|
|
- {mounttypes.Mount{Type: "bind", Source: tmpDir1, Target: destPath}, types.MountPoint{Type: "bind", RW: true, Destination: destPath, Source: tmpDir1}},
|
|
|
+ {
|
|
|
+ mounttypes.Mount{
|
|
|
+ Type: "bind",
|
|
|
+ Source: tmpDir1,
|
|
|
+ Target: destPath,
|
|
|
+ },
|
|
|
+ types.MountPoint{
|
|
|
+ Type: "bind",
|
|
|
+ RW: true,
|
|
|
+ Destination: destPath,
|
|
|
+ Source: tmpDir1,
|
|
|
+ },
|
|
|
+ },
|
|
|
{mounttypes.Mount{Type: "bind", Source: tmpDir1, Target: destPath, ReadOnly: true}, types.MountPoint{Type: "bind", RW: false, Destination: destPath, Source: tmpDir1}},
|
|
|
}...)
|
|
|
|
|
@@ -1968,55 +1999,80 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *check.C) {
|
|
|
ID string `json:"Id"`
|
|
|
}
|
|
|
|
|
|
- cli, err := client.NewEnvClient()
|
|
|
- c.Assert(err, checker.IsNil)
|
|
|
- defer cli.Close()
|
|
|
-
|
|
|
+ ctx := context.Background()
|
|
|
+ apiclient := testEnv.APIClient()
|
|
|
for i, x := range cases {
|
|
|
c.Logf("case %d - config: %v", i, x.cfg)
|
|
|
- container, err := cli.ContainerCreate(context.Background(), &containertypes.Config{Image: testImg}, &containertypes.HostConfig{Mounts: []mounttypes.Mount{x.cfg}}, &networktypes.NetworkingConfig{}, "")
|
|
|
- c.Assert(err, checker.IsNil)
|
|
|
-
|
|
|
- id := container.ID
|
|
|
-
|
|
|
- var mps []types.MountPoint
|
|
|
- err = json.NewDecoder(strings.NewReader(inspectFieldJSON(c, id, "Mounts"))).Decode(&mps)
|
|
|
- c.Assert(err, checker.IsNil)
|
|
|
- c.Assert(mps, checker.HasLen, 1)
|
|
|
- c.Assert(mps[0].Destination, checker.Equals, x.expected.Destination)
|
|
|
-
|
|
|
- if len(x.expected.Source) > 0 {
|
|
|
- c.Assert(mps[0].Source, checker.Equals, x.expected.Source)
|
|
|
+ container, err := apiclient.ContainerCreate(
|
|
|
+ ctx,
|
|
|
+ &containertypes.Config{Image: testImg},
|
|
|
+ &containertypes.HostConfig{Mounts: []mounttypes.Mount{x.cfg}},
|
|
|
+ &networktypes.NetworkingConfig{},
|
|
|
+ "")
|
|
|
+ require.NoError(c, err)
|
|
|
+
|
|
|
+ containerInspect, err := apiclient.ContainerInspect(ctx, container.ID)
|
|
|
+ require.NoError(c, err)
|
|
|
+ mps := containerInspect.Mounts
|
|
|
+ require.Len(c, mps, 1)
|
|
|
+ mountPoint := mps[0]
|
|
|
+
|
|
|
+ if x.expected.Source != "" {
|
|
|
+ assert.Equal(c, x.expected.Source, mountPoint.Source)
|
|
|
}
|
|
|
- if len(x.expected.Name) > 0 {
|
|
|
- c.Assert(mps[0].Name, checker.Equals, x.expected.Name)
|
|
|
+ if x.expected.Name != "" {
|
|
|
+ assert.Equal(c, x.expected.Name, mountPoint.Name)
|
|
|
}
|
|
|
- if len(x.expected.Driver) > 0 {
|
|
|
- c.Assert(mps[0].Driver, checker.Equals, x.expected.Driver)
|
|
|
+ if x.expected.Driver != "" {
|
|
|
+ assert.Equal(c, x.expected.Driver, mountPoint.Driver)
|
|
|
}
|
|
|
- c.Assert(mps[0].RW, checker.Equals, x.expected.RW)
|
|
|
- c.Assert(mps[0].Type, checker.Equals, x.expected.Type)
|
|
|
- c.Assert(mps[0].Mode, checker.Equals, x.expected.Mode)
|
|
|
- if len(x.expected.Propagation) > 0 {
|
|
|
- c.Assert(mps[0].Propagation, checker.Equals, x.expected.Propagation)
|
|
|
+ if x.expected.Propagation != "" {
|
|
|
+ assert.Equal(c, x.expected.Propagation, mountPoint.Propagation)
|
|
|
}
|
|
|
-
|
|
|
- out, _, err := dockerCmdWithError("start", "-a", id)
|
|
|
- if (x.cfg.Type != "volume" || (x.cfg.VolumeOptions != nil && x.cfg.VolumeOptions.NoCopy)) && testEnv.DaemonPlatform() != "windows" {
|
|
|
- c.Assert(err, checker.NotNil, check.Commentf("%s\n%v", out, mps[0]))
|
|
|
- } else {
|
|
|
- c.Assert(err, checker.IsNil, check.Commentf("%s\n%v", out, mps[0]))
|
|
|
+ assert.Equal(c, x.expected.RW, mountPoint.RW)
|
|
|
+ assert.Equal(c, x.expected.Type, mountPoint.Type)
|
|
|
+ assert.Equal(c, x.expected.Mode, mountPoint.Mode)
|
|
|
+ assert.Equal(c, x.expected.Destination, mountPoint.Destination)
|
|
|
+
|
|
|
+ err = apiclient.ContainerStart(ctx, container.ID, types.ContainerStartOptions{})
|
|
|
+ require.NoError(c, err)
|
|
|
+ poll.WaitOn(c, containerExit(apiclient, container.ID), poll.WithDelay(time.Second))
|
|
|
+
|
|
|
+ err = apiclient.ContainerRemove(ctx, container.ID, types.ContainerRemoveOptions{
|
|
|
+ RemoveVolumes: true,
|
|
|
+ Force: true,
|
|
|
+ })
|
|
|
+ require.NoError(c, err)
|
|
|
+
|
|
|
+ switch {
|
|
|
+
|
|
|
+ // Named volumes still exist after the container is removed
|
|
|
+ case x.cfg.Type == "volume" && len(x.cfg.Source) > 0:
|
|
|
+ _, err := apiclient.VolumeInspect(ctx, mountPoint.Name)
|
|
|
+ require.NoError(c, err)
|
|
|
+
|
|
|
+ // Bind mounts are never removed with the container
|
|
|
+ case x.cfg.Type == "bind":
|
|
|
+
|
|
|
+ // anonymous volumes are removed
|
|
|
+ default:
|
|
|
+ _, err := apiclient.VolumeInspect(ctx, mountPoint.Name)
|
|
|
+ assert.True(c, client.IsErrNotFound(err))
|
|
|
}
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- dockerCmd(c, "rm", "-fv", id)
|
|
|
- if x.cfg.Type == "volume" && len(x.cfg.Source) > 0 {
|
|
|
- // This should still exist even though we removed the container
|
|
|
- dockerCmd(c, "volume", "inspect", mps[0].Name)
|
|
|
- } else {
|
|
|
- // This should be removed automatically when we removed the container
|
|
|
- out, _, err := dockerCmdWithError("volume", "inspect", mps[0].Name)
|
|
|
- c.Assert(err, checker.NotNil, check.Commentf(out))
|
|
|
+func containerExit(apiclient client.APIClient, name string) func(poll.LogT) poll.Result {
|
|
|
+ return func(logT poll.LogT) poll.Result {
|
|
|
+ container, err := apiclient.ContainerInspect(context.Background(), name)
|
|
|
+ if err != nil {
|
|
|
+ return poll.Error(err)
|
|
|
+ }
|
|
|
+ switch container.State.Status {
|
|
|
+ case "created", "running":
|
|
|
+ return poll.Continue("container %s is %s, waiting for exit", name, container.State.Status)
|
|
|
}
|
|
|
+ return poll.Success()
|
|
|
}
|
|
|
}
|
|
|
|