Prepare to make root overlay the default.

We plan on making --overlay2=root:self the default for runsc. That will be a
risky change which might need rollbacks. This change is in preparation for
that. We manually set --overlay2=none in places where we don't want the
overlay configuration to impact. This change should be a noop. The intention
for this change is to make the risky change very small and limited to just
flipping a flag.

PiperOrigin-RevId: 513930702
This commit is contained in:
Ayush Ranjan
2023-03-04 00:46:47 -08:00
committed by gVisor bot
parent 37a308744b
commit 1b7a4e2a05
13 changed files with 96 additions and 85 deletions
+3 -3
View File
@@ -266,17 +266,17 @@ simple-tests: unit-tests # Compatibility target.
INTEGRATION_TARGETS := //test/image:image_test //test/e2e:integration_test
docker-tests: load-basic $(RUNTIME_BIN)
@$(call install_runtime,$(RUNTIME),) # Clear flags.
@$(call install_runtime,$(RUNTIME),--overlay2=none)
@$(call install_runtime,$(RUNTIME)-fdlimit,--fdlimit=2000) # Used by TestRlimitNoFile.
@$(call install_runtime,$(RUNTIME)-dcache,--fdlimit=2000 --dcache=100) # Used by TestDentryCacheLimit.
@$(call install_runtime,$(RUNTIME)-host-uds,--host-uds=all) # Used by TestHostSocketConnect.
@$(call install_runtime,$(RUNTIME)-overlay,--overlay2=all:self) # Used by TestOverlay*.
@$(call install_runtime,$(RUNTIME)-no-overlay,--overlay2=none) # Used by TestCheckpointRestore.
@$(call test_runtime,$(RUNTIME),$(INTEGRATION_TARGETS) //test/e2e:integration_runtime_test)
.PHONY: docker-tests
# TODO(b/241832602): Run overlay tests with host filestore option after S/R support is added.
overlay-tests: load-basic $(RUNTIME_BIN)
@$(call install_runtime,$(RUNTIME),--overlay2=all:memory)
@$(call install_runtime,$(RUNTIME),--overlay2=all:dir=/tmp)
@$(call test_runtime,$(RUNTIME),--test_env=TEST_OVERLAY=true $(INTEGRATION_TARGETS))
.PHONY: overlay-tests
+1 -1
View File
@@ -17,7 +17,7 @@ package tmpfs
// afterLoad is called by stateify.
func (fs *filesystem) afterLoad() {
if fs.privateMF {
// TODO(b/241832602): Add S/R support.
// TODO(b/271612187): Add S/R support.
panic("S/R not supported for private memory files")
}
fs.mf = fs.mfp.MemoryFile()
+14
View File
@@ -467,6 +467,20 @@ func WaitForHTTP(ip string, port int, timeout time.Duration) error {
return Poll(cb, timeout)
}
// HTTPRequestSucceeds sends a request to a given url and checks that the status is OK.
func HTTPRequestSucceeds(client http.Client, server string, port int) error {
url := fmt.Sprintf("http://%s:%d", server, port)
// Ensure that content is being served.
resp, err := client.Get(url)
if err != nil {
return fmt.Errorf("error reaching http server: %v", err)
}
if want := http.StatusOK; resp.StatusCode != want {
return fmt.Errorf("wrong response code, got: %d, want: %d", resp.StatusCode, want)
}
return nil
}
// Reaper reaps child processes.
type Reaper struct {
// mu protects ch, which will be nil if the reaper is not running.
+6 -3
View File
@@ -146,9 +146,12 @@ func (c *Do) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcommand
return util.Errorf("Error to retrieve hostname: %v", err)
}
// If c.overlay is set, then forcefully enable overlay.
if overlay2 := conf.GetOverlay2(); c.overlay && !overlay2.Enabled() {
conf.Overlay = true
// If c.overlay is set, then enable overlay.
conf.Overlay = false // conf.Overlay is deprecated.
if c.overlay {
conf.Overlay2 = config.Overlay2{RootMount: true, SubMounts: true, Medium: "memory"}
} else {
conf.Overlay2 = config.Overlay2{RootMount: false, SubMounts: false, Medium: ""}
}
absRoot, err := resolvePath(c.root)
if err != nil {
+4 -2
View File
@@ -322,7 +322,7 @@ func (c *Config) validate() error {
return fmt.Errorf("overlay flag has been replaced with overlay2 flag")
}
if overlay2 := c.GetOverlay2(); c.FileAccess == FileAccessShared && overlay2.Enabled() {
return fmt.Errorf("overlay flag is incompatible with shared file access")
return fmt.Errorf("overlay flag is incompatible with shared file access for rootfs")
}
if c.NumNetworkChannels <= 0 {
return fmt.Errorf("num_network_channels must be > 0, got: %d", c.NumNetworkChannels)
@@ -705,7 +705,9 @@ func defaultOverlay2() *Overlay2 {
// Set implements flag.Value.
func (o *Overlay2) Set(v string) error {
if v == "none" {
// Defaults are correct.
o.RootMount = false
o.SubMounts = false
o.Medium = ""
return nil
}
vs := strings.Split(v, ":")
+1 -1
View File
@@ -252,7 +252,7 @@ func TestValidationFail(t *testing.T) {
name: "shared+overlay",
flags: map[string]string{
"file-access": "shared",
"overlay": "true",
"overlay2": "root:self",
},
error: "overlay flag is incompatible",
},
+4 -2
View File
@@ -408,6 +408,7 @@ func configs(t *testing.T, noOverlay bool) map[string]*config.Config {
cs := make(map[string]*config.Config)
for _, p := range ps {
c := testutil.TestConfig(t)
c.Overlay2 = config.Overlay2{RootMount: false, SubMounts: false, Medium: ""}
c.Platform = p
cs[p] = c
}
@@ -417,7 +418,7 @@ func configs(t *testing.T, noOverlay bool) map[string]*config.Config {
for _, p := range ps {
c := testutil.TestConfig(t)
c.Platform = p
c.Overlay = true
c.Overlay2 = config.Overlay2{RootMount: true, SubMounts: true, Medium: "memory"}
cs[p+"-overlay"] = c
}
}
@@ -616,7 +617,8 @@ func TestExePath(t *testing.T) {
"default": testutil.TestConfig(t),
"overlay": testutil.TestConfig(t),
}
configs["overlay"].Overlay = true
configs["default"].Overlay2 = config.Overlay2{RootMount: false, SubMounts: false, Medium: ""}
configs["overlay"].Overlay2 = config.Overlay2{RootMount: true, SubMounts: true, Medium: "memory"}
for name, conf := range configs {
t.Run(name, func(t *testing.T) {
+1 -1
View File
@@ -1086,7 +1086,7 @@ func TestMultiContainerDifferentFilesystems(t *testing.T) {
// Make sure overlay is enabled, and none of the root filesystems are
// read-only, otherwise we won't be able to create the file.
conf.Overlay = true
conf.Overlay2 = config.Overlay2{RootMount: true, SubMounts: true, Medium: "memory"}
specs, ids := createSpecs(cmdRoot, cmd, cmd)
for _, s := range specs {
s.Root.Readonly = false
+2 -5
View File
@@ -33,6 +33,7 @@ import (
// into and out of the sandbox.
func TestSharedVolume(t *testing.T) {
conf := testutil.TestConfig(t)
conf.Overlay2 = config.Overlay2{RootMount: false, SubMounts: false, Medium: ""}
conf.FileAccess = config.FileAccessShared
// Main process just sleeps. We will use "exec" to probe the state of
@@ -145,11 +146,6 @@ func TestSharedVolume(t *testing.T) {
t.Errorf("stat %q got error %v, wanted nil", filename, err)
}
// File should exist outside the sandbox.
if _, err := os.Stat(filename); err != nil {
t.Errorf("stat %q got error %v, wanted nil", filename, err)
}
// Delete the file from within the sandbox.
argsRemove := &control.ExecArgs{
Filename: "/bin/rm",
@@ -186,6 +182,7 @@ func checkFile(conf *config.Config, c *Container, filename string, want []byte)
// is reflected inside.
func TestSharedVolumeFile(t *testing.T) {
conf := testutil.TestConfig(t)
conf.Overlay2 = config.Overlay2{RootMount: false, SubMounts: false, Medium: ""}
conf.FileAccess = config.FileAccessShared
// Main process just sleeps. We will use "exec" to probe the state of
+54
View File
@@ -27,6 +27,7 @@ import (
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"path/filepath"
"strconv"
@@ -213,3 +214,56 @@ func TestOverlayRootfsWhiteout(t *testing.T) {
t.Errorf("root directory contains a file/directory whose name contains %q: output = %q", boot.SelfOverlayFilestorePrefix, got)
}
}
// TODO(b/271612187): Once S/R support is added for file-backed overlays, move
// this test to integration_test.go so it can run with the default runsc
// configuration which uses file-backed overlay.
func TestCheckpointRestore(t *testing.T) {
if !testutil.IsCheckpointSupported() {
t.Skip("Pause/resume is not supported.")
}
dockerutil.EnsureDockerExperimentalEnabled()
ctx := context.Background()
d := dockerutil.MakeContainerWithRuntime(ctx, t, "-no-overlay")
defer d.CleanUp(ctx)
// Start the container.
port := 8080
if err := d.Spawn(ctx, dockerutil.RunOpts{
Image: "basic/python",
Ports: []int{port}, // See Dockerfile.
}); err != nil {
t.Fatalf("docker run failed: %v", err)
}
// Create a snapshot.
if err := d.Checkpoint(ctx, "test"); err != nil {
t.Fatalf("docker checkpoint failed: %v", err)
}
if err := d.WaitTimeout(ctx, defaultWait); err != nil {
t.Fatalf("wait failed: %v", err)
}
// TODO(b/143498576): Remove Poll after github.com/moby/moby/issues/38963 is fixed.
if err := testutil.Poll(func() error { return d.Restore(ctx, "test") }, defaultWait); err != nil {
t.Fatalf("docker restore failed: %v", err)
}
// Find container IP address.
ip, err := d.FindIP(ctx, false)
if err != nil {
t.Fatalf("docker.FindIP failed: %v", err)
}
// Wait until it's up and running.
if err := testutil.WaitForHTTP(ip.String(), port, defaultWait); err != nil {
t.Fatalf("WaitForHTTP() timeout: %v", err)
}
// Check if container is working again.
client := http.Client{Timeout: defaultWait}
if err := testutil.HTTPRequestSucceeds(client, ip.String(), port); err != nil {
t.Error("http request failed:", err)
}
}
+3 -67
View File
@@ -56,20 +56,6 @@ func TestMain(m *testing.M) {
os.Exit(m.Run())
}
// httpRequestSucceeds sends a request to a given url and checks that the status is OK.
func httpRequestSucceeds(client http.Client, server string, port int) error {
url := fmt.Sprintf("http://%s:%d", server, port)
// Ensure that content is being served.
resp, err := client.Get(url)
if err != nil {
return fmt.Errorf("error reaching http server: %v", err)
}
if want := http.StatusOK; resp.StatusCode != want {
return fmt.Errorf("wrong response code, got: %d, want: %d", resp.StatusCode, want)
}
return nil
}
// TestLifeCycle tests a basic Create/Start/Stop docker container life cycle.
func TestLifeCycle(t *testing.T) {
ctx := context.Background()
@@ -96,7 +82,7 @@ func TestLifeCycle(t *testing.T) {
t.Fatalf("WaitForHTTP() timeout: %v", err)
}
client := http.Client{Timeout: defaultWait}
if err := httpRequestSucceeds(client, ip.String(), port); err != nil {
if err := testutil.HTTPRequestSucceeds(client, ip.String(), port); err != nil {
t.Errorf("http request failed: %v", err)
}
@@ -139,7 +125,7 @@ func TestPauseResume(t *testing.T) {
// Check that container is working.
client := http.Client{Timeout: defaultWait}
if err := httpRequestSucceeds(client, ip.String(), port); err != nil {
if err := testutil.HTTPRequestSucceeds(client, ip.String(), port); err != nil {
t.Error("http request failed:", err)
}
@@ -171,57 +157,7 @@ func TestPauseResume(t *testing.T) {
// Check if container is working again.
client = http.Client{Timeout: defaultWait}
if err := httpRequestSucceeds(client, ip.String(), port); err != nil {
t.Error("http request failed:", err)
}
}
func TestCheckpointRestore(t *testing.T) {
if !testutil.IsCheckpointSupported() {
t.Skip("Pause/resume is not supported.")
}
dockerutil.EnsureDockerExperimentalEnabled()
ctx := context.Background()
d := dockerutil.MakeContainer(ctx, t)
defer d.CleanUp(ctx)
// Start the container.
port := 8080
if err := d.Spawn(ctx, dockerutil.RunOpts{
Image: "basic/python",
Ports: []int{port}, // See Dockerfile.
}); err != nil {
t.Fatalf("docker run failed: %v", err)
}
// Create a snapshot.
if err := d.Checkpoint(ctx, "test"); err != nil {
t.Fatalf("docker checkpoint failed: %v", err)
}
if err := d.WaitTimeout(ctx, defaultWait); err != nil {
t.Fatalf("wait failed: %v", err)
}
// TODO(b/143498576): Remove Poll after github.com/moby/moby/issues/38963 is fixed.
if err := testutil.Poll(func() error { return d.Restore(ctx, "test") }, defaultWait); err != nil {
t.Fatalf("docker restore failed: %v", err)
}
// Find container IP address.
ip, err := d.FindIP(ctx, false)
if err != nil {
t.Fatalf("docker.FindIP failed: %v", err)
}
// Wait until it's up and running.
if err := testutil.WaitForHTTP(ip.String(), port, defaultWait); err != nil {
t.Fatalf("WaitForHTTP() timeout: %v", err)
}
// Check if container is working again.
client := http.Client{Timeout: defaultWait}
if err := httpRequestSucceeds(client, ip.String(), port); err != nil {
if err := testutil.HTTPRequestSucceeds(client, ip.String(), port); err != nil {
t.Error("http request failed:", err)
}
}
+2
View File
@@ -238,6 +238,8 @@ func runRunsc(tc *gtest.TestCase, spec *specs.Spec) error {
}
if *overlay {
args = append(args, "-overlay2=all:dir=/tmp")
} else {
args = append(args, "-overlay2=none")
}
if *debug {
args = append(args, "-debug", "-log-packets=true")
+1
View File
@@ -8,3 +8,4 @@ test_readline,b/162980389,TestReadline hangs forever
test_resource,b/76174079,
test_signal,,Flaky - signal: alarm clock
test_socket,,Broken test
test_os,b/271473320,TestScandir.test_attributes fails with overlay
1 test name bug id comment
8 test_resource b/76174079
9 test_signal Flaky - signal: alarm clock
10 test_socket Broken test
11 test_os b/271473320 TestScandir.test_attributes fails with overlay