integration: Add test for not breaking overlayfs
Check that operations that could potentially perform overlayfs mounts
that could cause undefined behaviors.
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 303e2b124e
)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
parent
f1cc5760d9
commit
54953f2f5a
1 changed files with 111 additions and 0 deletions
111
integration/container/overlayfs_linux_test.go
Normal file
111
integration/container/overlayfs_linux_test.go
Normal file
|
@ -0,0 +1,111 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/dmesg"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/skip"
|
||||
)
|
||||
|
||||
func TestNoOverlayfsWarningsAboutUndefinedBehaviors(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType != "linux", "overlayfs is only available on linux")
|
||||
skip.If(t, testEnv.IsRemoteDaemon(), "local daemon is needed for kernel log access")
|
||||
skip.If(t, testEnv.IsRootless(), "root is needed for reading kernel log")
|
||||
|
||||
defer setupTest(t)()
|
||||
client := testEnv.APIClient()
|
||||
ctx := context.Background()
|
||||
|
||||
cID := container.Run(ctx, t, client, container.WithCmd("sh", "-c", `while true; do echo $RANDOM >>/file; sleep 0.1; done`))
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
operation func(t *testing.T) error
|
||||
}{
|
||||
{name: "diff", operation: func(*testing.T) error {
|
||||
_, err := client.ContainerDiff(ctx, cID)
|
||||
return err
|
||||
}},
|
||||
{name: "export", operation: func(*testing.T) error {
|
||||
rc, err := client.ContainerExport(ctx, cID)
|
||||
if err == nil {
|
||||
defer rc.Close()
|
||||
_, err = io.Copy(io.Discard, rc)
|
||||
}
|
||||
return err
|
||||
}},
|
||||
{name: "cp to container", operation: func(t *testing.T) error {
|
||||
archive, err := archive.Generate("new-file", "hello-world")
|
||||
assert.NilError(t, err, "failed to create a temporary archive")
|
||||
return client.CopyToContainer(ctx, cID, "/", archive, types.CopyToContainerOptions{})
|
||||
}},
|
||||
{name: "cp from container", operation: func(*testing.T) error {
|
||||
rc, _, err := client.CopyFromContainer(ctx, cID, "/file")
|
||||
if err == nil {
|
||||
defer rc.Close()
|
||||
_, err = io.Copy(io.Discard, rc)
|
||||
}
|
||||
|
||||
return err
|
||||
}},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
prev := dmesgLines(256)
|
||||
|
||||
err := tc.operation(t)
|
||||
assert.NilError(t, err)
|
||||
|
||||
after := dmesgLines(2048)
|
||||
|
||||
diff := diffDmesg(prev, after)
|
||||
for _, line := range diff {
|
||||
overlayfs := strings.Contains(line, "overlayfs: ")
|
||||
lowerDirInUse := strings.Contains(line, "lowerdir is in-use as ")
|
||||
upperDirInUse := strings.Contains(line, "upperdir is in-use as ")
|
||||
workDirInuse := strings.Contains(line, "workdir is in-use as ")
|
||||
undefinedBehavior := strings.Contains(line, "will result in undefined behavior")
|
||||
|
||||
if overlayfs && (lowerDirInUse || upperDirInUse || workDirInuse) && undefinedBehavior {
|
||||
t.Errorf("%s caused overlayfs kernel warning: %s", tc.name, line)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func dmesgLines(bytes int) []string {
|
||||
data := dmesg.Dmesg(bytes)
|
||||
return strings.Split(strings.TrimSpace(string(data)), "\n")
|
||||
}
|
||||
|
||||
func diffDmesg(prev, next []string) []string {
|
||||
// All lines have a timestamp, so just take the last one from the previous
|
||||
// log and find it in the new log.
|
||||
lastPrev := prev[len(prev)-1]
|
||||
|
||||
for idx := len(next) - 1; idx >= 0; idx-- {
|
||||
line := next[idx]
|
||||
|
||||
if line == lastPrev {
|
||||
nextIdx := idx + 1
|
||||
if nextIdx < len(next) {
|
||||
return next[nextIdx:]
|
||||
} else {
|
||||
// Found at the last position, log is the same.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return next
|
||||
}
|
Loading…
Add table
Reference in a new issue