diff --git a/runsc/boot/mount_hints_test.go b/runsc/boot/mount_hints_test.go index da8028c550..0544e394fe 100644 --- a/runsc/boot/mount_hints_test.go +++ b/runsc/boot/mount_hints_test.go @@ -257,7 +257,7 @@ func TestRootfsHintHappy(t *testing.T) { Annotations: map[string]string{ RootfsPrefix + "source": imagePath, RootfsPrefix + "type": erofs.Name, - RootfsPrefix + "overlay": config.MemoryOverlay.String(), + RootfsPrefix + "overlay": config.OverlayMediumMemory().String(), }, } hint, err := NewRootfsHint(spec) @@ -272,7 +272,7 @@ func TestRootfsHintHappy(t *testing.T) { if hint.Mount.Type != erofs.Name { t.Errorf("rootfs type, want: %q, got: %q", erofs.Name, hint.Mount.Type) } - if hint.Overlay != config.MemoryOverlay { + if hint.Overlay.MediumType() != config.MemoryOverlay { t.Errorf("rootfs overlay, want: %q, got: %q", config.MemoryOverlay, hint.Overlay) } } @@ -317,7 +317,7 @@ func TestRootfsHintErrors(t *testing.T) { RootfsPrefix + "invalid": "invalid", RootfsPrefix + "source": imagePath, RootfsPrefix + "type": erofs.Name, - RootfsPrefix + "overlay": config.MemoryOverlay.String(), + RootfsPrefix + "overlay": config.OverlayMediumMemory().String(), }, error: "invalid rootfs annotation", }, @@ -325,7 +325,7 @@ func TestRootfsHintErrors(t *testing.T) { name: "missing source", annotations: map[string]string{ RootfsPrefix + "type": erofs.Name, - RootfsPrefix + "overlay": config.MemoryOverlay.String(), + RootfsPrefix + "overlay": config.OverlayMediumMemory().String(), }, error: "rootfs annotations missing required field", }, @@ -333,7 +333,7 @@ func TestRootfsHintErrors(t *testing.T) { name: "missing type", annotations: map[string]string{ RootfsPrefix + "source": imagePath, - RootfsPrefix + "overlay": config.MemoryOverlay.String(), + RootfsPrefix + "overlay": config.OverlayMediumMemory().String(), }, error: "rootfs annotations missing required field", }, diff --git a/runsc/config/config.go b/runsc/config/config.go index 7b7fc9e87d..232b2409bf 100644 --- a/runsc/config/config.go +++ b/runsc/config/config.go @@ -493,7 +493,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: OverlayMediumMemory()} } return c.Overlay2 } @@ -844,49 +844,82 @@ func (g HostFifo) AllowOpen() bool { return g&HostFifoOpen != 0 } -// OverlayMedium describes how overlay medium is configured. -type OverlayMedium string +// OverlayMediumType describes types of overlay medium. +type OverlayMediumType string const ( // NoOverlay indicates that no overlay will be applied. - NoOverlay = OverlayMedium("") + NoOverlay = OverlayMediumType("") // MemoryOverlay indicates that the overlay is backed by app memory. - MemoryOverlay = OverlayMedium("memory") + MemoryOverlay = OverlayMediumType("memory") // SelfOverlay indicates that the overlaid mount is backed by itself. - SelfOverlay = OverlayMedium("self") + SelfOverlay = OverlayMediumType("self") + + AnonOverlay = OverlayMediumType("dir") - // AnonOverlayPrefix is the prefix that users should specify in the + // anonOverlayPrefix is the prefix that users should specify in the // config for the anonymous overlay. - AnonOverlayPrefix = "dir=" + anonOverlayPrefix = "dir=" ) +// OverlayMedium describes how overlay medium is configured. +type OverlayMedium struct { + medium OverlayMediumType + // Set iff medium is AnonOverlay. + dir string +} + +func OverlayMediumNoOverlay() OverlayMedium { + return OverlayMedium{medium: NoOverlay} +} + +func OverlayMediumMemory() OverlayMedium { + return OverlayMedium{medium: MemoryOverlay} +} + // String returns a human-readable string representing the overlay medium config. func (m OverlayMedium) String() string { - return string(m) + switch m.medium { + case NoOverlay, MemoryOverlay, SelfOverlay: + return string(m.medium) + case AnonOverlay: + return fmt.Sprintf("%s=%s", AnonOverlay, m.dir) + default: + panic(fmt.Sprintf("Invalid overlay medium %q", m.medium)) + } } // Set sets the value. Set(String()) should be idempotent. func (m *OverlayMedium) Set(v string) error { - switch OverlayMedium(v) { - case NoOverlay, MemoryOverlay, SelfOverlay: // OK + switch OverlayMediumType(v) { + case NoOverlay, MemoryOverlay, SelfOverlay: + { + *m = OverlayMedium{medium: OverlayMediumType(v), dir: ""} + return nil + } default: - if !strings.HasPrefix(v, AnonOverlayPrefix) { + if !strings.HasPrefix(v, anonOverlayPrefix) { return fmt.Errorf("unexpected medium: %q", v) } - if hostFileDir := strings.TrimPrefix(v, AnonOverlayPrefix); !filepath.IsAbs(hostFileDir) { + hostFileDir := strings.TrimPrefix(v, anonOverlayPrefix) + if !filepath.IsAbs(hostFileDir) { return fmt.Errorf("overlay host file directory should be an absolute path, got %q", hostFileDir) } + *m = OverlayMedium{medium: OverlayMediumType(v), dir: hostFileDir} } - *m = OverlayMedium(v) return nil } +func (m OverlayMedium) MediumType() OverlayMediumType { + return m.medium +} + // IsBackedByAnon indicates whether the overlaid mount is backed by a host file // in an anonymous directory. func (m OverlayMedium) IsBackedByAnon() bool { - return strings.HasPrefix(string(m), AnonOverlayPrefix) + return m.medium == AnonOverlay } // HostFileDir indicates the directory in which the overlay-backing host file @@ -895,9 +928,9 @@ func (m OverlayMedium) IsBackedByAnon() bool { // Precondition: m.IsBackedByAnon(). func (m OverlayMedium) HostFileDir() string { if !m.IsBackedByAnon() { - panic(fmt.Sprintf("anonymous overlay medium = %q does not have %v prefix", m, AnonOverlayPrefix)) + panic(fmt.Sprintf("anonymous overlay medium = %q does not have %v prefix", m, anonOverlayPrefix)) } - return strings.TrimPrefix(string(m), AnonOverlayPrefix) + return m.dir } // Overlay2 holds the configuration for setting up overlay filesystems for the @@ -910,7 +943,7 @@ type Overlay2 struct { func defaultOverlay2() *Overlay2 { // Rootfs overlay is enabled by default and backed by a file in rootfs itself. - return &Overlay2{rootMount: true, subMounts: false, medium: SelfOverlay} + return &Overlay2{rootMount: true, subMounts: false, medium: OverlayMedium{medium: SelfOverlay}} } // Set implements flag.Value. Set(String()) should be idempotent. @@ -918,7 +951,7 @@ func (o *Overlay2) Set(v string) error { if v == "none" { o.rootMount = false o.subMounts = false - o.medium = NoOverlay + o.medium = OverlayMediumNoOverlay() return nil } vs := strings.Split(v, ":") @@ -963,13 +996,13 @@ func (o Overlay2) String() string { // Enabled returns true if the overlay option is enabled for any mounts. func (o *Overlay2) Enabled() bool { - return o.medium != NoOverlay + return o.medium.medium != NoOverlay } // RootOverlayMedium returns the overlay medium config of the root mount. func (o *Overlay2) RootOverlayMedium() OverlayMedium { if !o.rootMount { - return NoOverlay + return OverlayMediumNoOverlay() } return o.medium } @@ -977,7 +1010,7 @@ func (o *Overlay2) RootOverlayMedium() OverlayMedium { // SubMountOverlayMedium returns the overlay medium config of submounts. func (o *Overlay2) SubMountOverlayMedium() OverlayMedium { if !o.subMounts { - return NoOverlay + return OverlayMediumNoOverlay() } return o.medium } diff --git a/runsc/config/flags.go b/runsc/config/flags.go index c7094e7e9e..b5c7c2e1ac 100644 --- a/runsc/config/flags.go +++ b/runsc/config/flags.go @@ -193,7 +193,7 @@ func checkOverlay2(name string, value string) error { if err := o.Set(value); err != nil { return fmt.Errorf("invalid overlay2 annotation: %w", err) } - switch o.medium { + switch o.medium.MediumType() { case NoOverlay, MemoryOverlay, SelfOverlay: return nil default: diff --git a/runsc/container/container.go b/runsc/container/container.go index d480e1e511..eb95cfe949 100644 --- a/runsc/container/container.go +++ b/runsc/container/container.go @@ -911,7 +911,7 @@ func createGoferConf(overlayMedium config.OverlayMedium, mountType string, mount default: return boot.GoferMountConf{}, fmt.Errorf("unsupported mount type %q in mount hint", mountType) } - switch overlayMedium { + switch overlayMedium.MediumType() { case config.NoOverlay: return boot.GoferMountConf{Lower: lower, Upper: boot.NoOverlay}, nil case config.MemoryOverlay: @@ -947,7 +947,7 @@ func (c *Container) initGoferConfs(ovlConf config.Overlay2, mountHints *boot.Pod } } if c.Spec.Root.Readonly { - overlayMedium = config.NoOverlay + overlayMedium = config.OverlayMediumNoOverlay() } goferConf, err := createGoferConf(overlayMedium, mountType, c.Spec.Root.Path) if err != nil { @@ -963,12 +963,12 @@ func (c *Container) initGoferConfs(ovlConf config.Overlay2, mountHints *boot.Pod overlayMedium = ovlConf.SubMountOverlayMedium() mountType = boot.Bind if specutils.IsReadonlyMount(c.Spec.Mounts[i].Options) { - overlayMedium = config.NoOverlay + overlayMedium = config.OverlayMediumNoOverlay() } if hint := mountHints.FindMount(c.Spec.Mounts[i].Source); hint != nil { // Note that we want overlayMedium=self even if this is a read-only mount so that // the shared mount is created correctly. Future containers may mount this writably. - overlayMedium = config.SelfOverlay + overlayMedium = config.OverlayMediumNoOverlay() if !specutils.IsGoferMount(hint.Mount) { mountType = hint.Mount.Type } diff --git a/runsc/container/container_test.go b/runsc/container/container_test.go index 44d235c0ce..1138b30189 100644 --- a/runsc/container/container_test.go +++ b/runsc/container/container_test.go @@ -3486,7 +3486,7 @@ func TestRootfsEROFS(t *testing.T) { spec.Annotations[boot.RootfsPrefix+"source"] = rootfsImage // Disable the overlay, as we want to be sure that rootfs will always be // shown as EROFS in mountinfo. - spec.Annotations[boot.RootfsPrefix+"overlay"] = config.NoOverlay.String() + spec.Annotations[boot.RootfsPrefix+"overlay"] = config.OverlayMediumNoOverlay().String() conf := testutil.TestConfig(t) @@ -3563,7 +3563,7 @@ func TestCheckpointRestoreEROFS(t *testing.T) { // a writeable and savable overlay for rootfs, which allows the sentry to // create the mount point for the bind mount of the temporary directory shared // between host and test container. - spec.Annotations[boot.RootfsPrefix+"overlay"] = config.MemoryOverlay.String() + spec.Annotations[boot.RootfsPrefix+"overlay"] = config.OverlayMediumMemory().String() return spec }) })