diff --git a/runsc/cli/main.go b/runsc/cli/main.go index 2f764322d..0772ff818 100644 --- a/runsc/cli/main.go +++ b/runsc/cli/main.go @@ -233,8 +233,7 @@ func Main() { log.Infof("\t\tPlatform: %v", conf.Platform) log.Infof("\t\tFileAccess: %v", conf.FileAccess) log.Infof("\t\tDirectfs: %t", conf.DirectFS) - overlay2 := conf.GetOverlay2() - log.Infof("\t\tOverlay: Root=%t, SubMounts=%t, Medium=%q", overlay2.RootMount, overlay2.SubMounts, overlay2.Medium) + log.Infof("\t\tOverlay: %s", conf.GetOverlay2()) log.Infof("\t\tNetwork: %v, logging: %t", conf.Network, conf.LogPackets) log.Infof("\t\tStrace: %t, max size: %d, syscalls: %s", conf.Strace, conf.StraceLogSize, conf.StraceSyscalls) log.Infof("\t\tIOURING: %t", conf.IOUring) diff --git a/runsc/cmd/do.go b/runsc/cmd/do.go index 8292f9040..07889e7ab 100644 --- a/runsc/cmd/do.go +++ b/runsc/cmd/do.go @@ -149,9 +149,9 @@ func (c *Do) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcommand // 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"} + conf.Overlay2.Set("all:memory") } else { - conf.Overlay2 = config.Overlay2{RootMount: false, SubMounts: false, Medium: ""} + conf.Overlay2.Set("none") } absRoot, err := resolvePath(c.root) if err != nil { diff --git a/runsc/config/config.go b/runsc/config/config.go index 0ac7b3069..2a4f15136 100644 --- a/runsc/config/config.go +++ b/runsc/config/config.go @@ -360,7 +360,7 @@ func (c *Config) GetOverlay2() Overlay2 { panic(fmt.Sprintf("Overlay2 cannot be set when --overlay=true")) } // Using a deprecated flag, honor it to avoid breaking users. - return Overlay2{RootMount: true, SubMounts: true, Medium: "memory"} + return Overlay2{rootMount: true, subMounts: true, medium: "memory"} } return c.Overlay2 } @@ -692,22 +692,22 @@ func (g HostFifo) AllowOpen() bool { // Overlay2 holds the configuration for setting up overlay filesystems for the // container. type Overlay2 struct { - RootMount bool - SubMounts bool - Medium string + rootMount bool + subMounts bool + medium string } func defaultOverlay2() *Overlay2 { // Rootfs overlay is enabled by default and backed by a file in rootfs itself. - return &Overlay2{RootMount: true, SubMounts: false, Medium: "self"} + return &Overlay2{rootMount: true, subMounts: false, medium: "self"} } // Set implements flag.Value. func (o *Overlay2) Set(v string) error { if v == "none" { - o.RootMount = false - o.SubMounts = false - o.Medium = "" + o.rootMount = false + o.subMounts = false + o.medium = "" return nil } vs := strings.Split(v, ":") @@ -717,22 +717,22 @@ func (o *Overlay2) Set(v string) error { switch mount := vs[0]; mount { case "root": - o.RootMount = true + o.rootMount = true case "all": - o.RootMount = true - o.SubMounts = true + o.rootMount = true + o.subMounts = true default: return fmt.Errorf("unexpected mount specifier for --overlay2: %q", mount) } - o.Medium = vs[1] - switch o.Medium { + o.medium = vs[1] + switch o.medium { case "memory", "self": // OK default: - if !strings.HasPrefix(o.Medium, "dir=") { - return fmt.Errorf("unexpected medium specifier for --overlay2: %q", o.Medium) + if !strings.HasPrefix(o.medium, "dir=") { + return fmt.Errorf("unexpected medium specifier for --overlay2: %q", o.medium) } - if hostFileDir := strings.TrimPrefix(o.Medium, "dir="); !filepath.IsAbs(hostFileDir) { + if hostFileDir := strings.TrimPrefix(o.medium, "dir="); !filepath.IsAbs(hostFileDir) { return fmt.Errorf("overlay host file directory should be an absolute path, got %q", hostFileDir) } } @@ -746,36 +746,46 @@ func (o *Overlay2) Get() any { // String implements flag.Value. func (o Overlay2) String() string { - if !o.RootMount && !o.SubMounts { + if !o.rootMount && !o.subMounts { return "none" } res := "" switch { - case o.RootMount && o.SubMounts: + case o.rootMount && o.subMounts: res = "all" - case o.RootMount: + case o.rootMount: res = "root" default: panic("invalid state of subMounts = true and rootMount = false") } - return res + ":" + o.Medium + return res + ":" + o.medium } // Enabled returns true if the overlay option is enabled for any mounts. func (o *Overlay2) Enabled() bool { - return o.RootMount || o.SubMounts + return o.rootMount || o.subMounts +} + +// RootEnabled returns true if the overlay is enabled for the root mount. +func (o *Overlay2) RootEnabled() bool { + return o.rootMount +} + +// SubMountEnabled returns true if the overlay is enabled for submounts. +func (o *Overlay2) SubMountEnabled() bool { + return o.subMounts } // IsBackedByMemory indicates whether the overlay is backed by app memory. func (o *Overlay2) IsBackedByMemory() bool { - return o.Enabled() && o.Medium == "memory" + return o.Enabled() && o.medium == "memory" } // IsBackedBySelf indicates whether the overlaid mounts are backed by // themselves. func (o *Overlay2) IsBackedBySelf() bool { - return o.Enabled() && o.Medium == "self" + return o.Enabled() && o.medium == "self" } // HostFileDir indicates the directory in which the overlay-backing host file @@ -783,10 +793,10 @@ func (o *Overlay2) IsBackedBySelf() bool { // // Precondition: o.IsBackedByHostFile() && !o.IsBackedBySelf(). func (o *Overlay2) HostFileDir() string { - if !strings.HasPrefix(o.Medium, "dir=") { - panic(fmt.Sprintf("Overlay2.Medium = %q does not have dir= prefix when overlay is backed by a host file", o.Medium)) + if !strings.HasPrefix(o.medium, "dir=") { + panic(fmt.Sprintf("Overlay2.Medium = %q does not have dir= prefix when overlay is backed by a host file", o.medium)) } - hostFileDir := strings.TrimPrefix(o.Medium, "dir=") + hostFileDir := strings.TrimPrefix(o.medium, "dir=") if !filepath.IsAbs(hostFileDir) { panic(fmt.Sprintf("overlay host file directory should be an absolute path, got %q", hostFileDir)) } diff --git a/runsc/config/config_test.go b/runsc/config/config_test.go index ab7ba1e83..5261fb154 100644 --- a/runsc/config/config_test.go +++ b/runsc/config/config_test.go @@ -477,7 +477,7 @@ func TestOverrideAllowlist(t *testing.T) { func TestBundles(t *testing.T) { noChange := func(t *testing.T, old, new *Config) { t.Helper() - if diff := cmp.Diff(old, new, cmp.AllowUnexported(Config{})); diff != "" { + if diff := cmp.Diff(old, new, cmp.AllowUnexported(Config{}, Overlay2{})); diff != "" { t.Errorf("different configs:\n%+v\nvs\n%+v\nDiff:\n%s", old, new, diff) } } diff --git a/runsc/container/container.go b/runsc/container/container.go index 4e3a5a619..b509615a4 100644 --- a/runsc/container/container.go +++ b/runsc/container/container.go @@ -871,7 +871,7 @@ func (c *Container) createOverlayFilestores(mountHints *boot.PodMountHints) ([]* var overlayMediums []boot.OverlayMedium // Handle root mount first. - shouldOverlay := c.OverlayConf.RootMount && !c.Spec.Root.Readonly + shouldOverlay := c.OverlayConf.RootEnabled() && !c.Spec.Root.Readonly filestore, medium, err := c.createOverlayFilestore(c.Spec.Root.Path, shouldOverlay, nil /* hint */) if err != nil { return nil, nil, err @@ -887,7 +887,7 @@ func (c *Container) createOverlayFilestores(mountHints *boot.PodMountHints) ([]* continue } hint := mountHints.FindMount(&c.Spec.Mounts[i]) - shouldOverlay := c.OverlayConf.SubMounts && !specutils.IsReadonlyMount(c.Spec.Mounts[i].Options) + shouldOverlay := c.OverlayConf.SubMountEnabled() && !specutils.IsReadonlyMount(c.Spec.Mounts[i].Options) filestore, medium, err := c.createOverlayFilestore(c.Spec.Mounts[i].Source, shouldOverlay, hint) if err != nil { return nil, nil, err diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go index b52c0babc..89dd31743 100644 --- a/runsc/container/container_test.go +++ b/runsc/container/container_test.go @@ -417,7 +417,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.Overlay2.Set("none") c.Platform = p cs[p] = c } @@ -427,7 +427,7 @@ func configs(t *testing.T, noOverlay bool) map[string]*config.Config { for _, p := range ps { c := testutil.TestConfig(t) c.Platform = p - c.Overlay2 = config.Overlay2{RootMount: true, SubMounts: true, Medium: "memory"} + c.Overlay2.Set("all:memory") cs[p+"-overlay"] = c } } @@ -622,12 +622,14 @@ func TestExePath(t *testing.T) { t.Fatalf("error making directory: %v", err) } + defaultConf := testutil.TestConfig(t) + defaultConf.Overlay2.Set("none") + overlayConf := testutil.TestConfig(t) + overlayConf.Overlay2.Set("all:memory") configs := map[string]*config.Config{ - "default": testutil.TestConfig(t), - "overlay": testutil.TestConfig(t), + "default": defaultConf, + "overlay": overlayConf, } - 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) { diff --git a/runsc/container/multi_container_test.go b/runsc/container/multi_container_test.go index b9f04f39c..c7628eda3 100644 --- a/runsc/container/multi_container_test.go +++ b/runsc/container/multi_container_test.go @@ -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.Overlay2 = config.Overlay2{RootMount: true, SubMounts: true, Medium: "memory"} + conf.Overlay2.Set("all:memory") specs, ids := createSpecs(cmdRoot, cmd, cmd) for _, s := range specs { s.Root.Readonly = false @@ -2231,10 +2231,7 @@ func TestMultiContainerOverlayLeaks(t *testing.T) { conf.RootDir = rootDir // Configure root overlay backed by rootfs itself. - conf.Overlay2 = config.Overlay2{ - RootMount: true, - Medium: "self", - } + conf.Overlay2.Set("root:self") // Root container will just sleep. sleep := []string{"sleep", "100"} @@ -2336,10 +2333,7 @@ func TestMultiContainerMemoryLeakStress(t *testing.T) { // Configure root overlay (backed by memory) so that containers can create // files in the root directory. - conf.Overlay2 = config.Overlay2{ - RootMount: true, - Medium: "memory", - } + conf.Overlay2.Set("root:memory") // Root container will just sleep. sleep := []string{"sleep", "1000"} diff --git a/runsc/container/shared_volume_test.go b/runsc/container/shared_volume_test.go index 7d274de38..592a8eb2a 100644 --- a/runsc/container/shared_volume_test.go +++ b/runsc/container/shared_volume_test.go @@ -33,7 +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.Overlay2.Set("none") conf.FileAccess = config.FileAccessShared // Main process just sleeps. We will use "exec" to probe the state of @@ -182,7 +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.Overlay2.Set("none") conf.FileAccess = config.FileAccessShared // Main process just sleeps. We will use "exec" to probe the state of @@ -266,11 +266,7 @@ func TestSharedVolumeFile(t *testing.T) { // wrapped in an overlay are not visible externally. func TestSharedVolumeOverlay(t *testing.T) { conf := testutil.TestConfig(t) - conf.Overlay2 = config.Overlay2{ - RootMount: true, - SubMounts: true, - Medium: "dir=/tmp", - } + conf.Overlay2.Set("all:dir=/tmp") // File that will be used to check consistency inside/outside sandbox. // Note that TmpDir() is set up as a shared volume by NewSpecWithArgs(). So