Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #46266 from vvoland/c8d-more-mount-refcount-24
[24.0 backport] c8d integration: Use refcount mounter for diff and export
- Loading branch information
Showing
3 changed files
with
121 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |