|
@@ -1,14 +1,17 @@
|
|
package daemon // import "github.com/docker/docker/integration/daemon"
|
|
package daemon // import "github.com/docker/docker/integration/daemon"
|
|
|
|
|
|
import (
|
|
import (
|
|
|
|
+ "bytes"
|
|
"context"
|
|
"context"
|
|
"fmt"
|
|
"fmt"
|
|
|
|
+ "io"
|
|
"net/http"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/http/httptest"
|
|
"os"
|
|
"os"
|
|
"os/exec"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"path/filepath"
|
|
"runtime"
|
|
"runtime"
|
|
|
|
+ "strings"
|
|
"syscall"
|
|
"syscall"
|
|
"testing"
|
|
"testing"
|
|
|
|
|
|
@@ -17,7 +20,9 @@ import (
|
|
"github.com/docker/docker/api/types/mount"
|
|
"github.com/docker/docker/api/types/mount"
|
|
"github.com/docker/docker/api/types/volume"
|
|
"github.com/docker/docker/api/types/volume"
|
|
"github.com/docker/docker/daemon/config"
|
|
"github.com/docker/docker/daemon/config"
|
|
|
|
+ "github.com/docker/docker/errdefs"
|
|
"github.com/docker/docker/integration/internal/container"
|
|
"github.com/docker/docker/integration/internal/container"
|
|
|
|
+ "github.com/docker/docker/pkg/stdcopy"
|
|
"github.com/docker/docker/testutil/daemon"
|
|
"github.com/docker/docker/testutil/daemon"
|
|
"gotest.tools/v3/assert"
|
|
"gotest.tools/v3/assert"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
@@ -432,9 +437,28 @@ func testLiveRestoreVolumeReferences(t *testing.T) {
|
|
Source: v.Name,
|
|
Source: v.Name,
|
|
Target: "/foo",
|
|
Target: "/foo",
|
|
}
|
|
}
|
|
- cID := container.Run(ctx, t, c, container.WithMount(m), container.WithCmd("top"))
|
|
|
|
|
|
+
|
|
|
|
+ const testContent = "hello"
|
|
|
|
+ cID := container.Run(ctx, t, c, container.WithMount(m), container.WithCmd("sh", "-c", "echo "+testContent+">>/foo/test.txt; sleep infinity"))
|
|
defer c.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true})
|
|
defer c.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true})
|
|
|
|
|
|
|
|
+ // Wait until container creates a file in the volume.
|
|
|
|
+ poll.WaitOn(t, func(t poll.LogT) poll.Result {
|
|
|
|
+ stat, err := c.ContainerStatPath(ctx, cID, "/foo/test.txt")
|
|
|
|
+ if err != nil {
|
|
|
|
+ if errdefs.IsNotFound(err) {
|
|
|
|
+ return poll.Continue("file doesn't yet exist")
|
|
|
|
+ }
|
|
|
|
+ return poll.Error(err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if int(stat.Size) != len(testContent)+1 {
|
|
|
|
+ return poll.Error(fmt.Errorf("unexpected test file size: %d", stat.Size))
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return poll.Success()
|
|
|
|
+ })
|
|
|
|
+
|
|
d.Restart(t, "--live-restore", "--iptables=false")
|
|
d.Restart(t, "--live-restore", "--iptables=false")
|
|
|
|
|
|
// Try to remove the volume
|
|
// Try to remove the volume
|
|
@@ -442,6 +466,32 @@ func testLiveRestoreVolumeReferences(t *testing.T) {
|
|
err = c.VolumeRemove(ctx, v.Name, false)
|
|
err = c.VolumeRemove(ctx, v.Name, false)
|
|
assert.ErrorContains(t, err, "volume is in use")
|
|
assert.ErrorContains(t, err, "volume is in use")
|
|
|
|
|
|
|
|
+ t.Run("volume still mounted", func(t *testing.T) {
|
|
|
|
+ skip.If(t, testEnv.IsRootless(), "restarted rootless daemon has a new mount namespace and it won't have the previous mounts")
|
|
|
|
+
|
|
|
|
+ // Check if a new container with the same volume has access to the previous content.
|
|
|
|
+ // This fails if the volume gets unmounted at startup.
|
|
|
|
+ cID2 := container.Run(ctx, t, c, container.WithMount(m), container.WithCmd("cat", "/foo/test.txt"))
|
|
|
|
+ defer c.ContainerRemove(ctx, cID2, types.ContainerRemoveOptions{Force: true})
|
|
|
|
+
|
|
|
|
+ poll.WaitOn(t, container.IsStopped(ctx, c, cID2))
|
|
|
|
+
|
|
|
|
+ inspect, err := c.ContainerInspect(ctx, cID2)
|
|
|
|
+ if assert.Check(t, err) {
|
|
|
|
+ assert.Check(t, is.Equal(inspect.State.ExitCode, 0), "volume doesn't have the same file")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ logs, err := c.ContainerLogs(ctx, cID2, types.ContainerLogsOptions{ShowStdout: true})
|
|
|
|
+ assert.NilError(t, err)
|
|
|
|
+ defer logs.Close()
|
|
|
|
+
|
|
|
|
+ var stdoutBuf bytes.Buffer
|
|
|
|
+ _, err = stdcopy.StdCopy(&stdoutBuf, io.Discard, logs)
|
|
|
|
+ assert.NilError(t, err)
|
|
|
|
+
|
|
|
|
+ assert.Check(t, is.Equal(strings.TrimSpace(stdoutBuf.String()), testContent))
|
|
|
|
+ })
|
|
|
|
+
|
|
// Remove that container which should free the references in the volume
|
|
// Remove that container which should free the references in the volume
|
|
err = c.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true})
|
|
err = c.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true})
|
|
assert.NilError(t, err)
|
|
assert.NilError(t, err)
|