Add configurable mount options to overlay
Allows default mount options to be provided through configuration. Signed-off-by: Derek McGowan <derek@mcg.dev>
This commit is contained in:
parent
98b7dfb870
commit
d115129d1e
@ -44,6 +44,7 @@ const upperdirKey = "containerd.io/snapshot/overlay.upperdir"
|
|||||||
type SnapshotterConfig struct {
|
type SnapshotterConfig struct {
|
||||||
asyncRemove bool
|
asyncRemove bool
|
||||||
upperdirLabel bool
|
upperdirLabel bool
|
||||||
|
mountOptions []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opt is an option to configure the overlay snapshotter
|
// Opt is an option to configure the overlay snapshotter
|
||||||
@ -67,13 +68,21 @@ func WithUpperdirLabel(config *SnapshotterConfig) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMountOptions defines the default mount options used for the overlay mount.
|
||||||
|
// NOTE: Options are not applied to bind mounts.
|
||||||
|
func WithMountOptions(options []string) Opt {
|
||||||
|
return func(config *SnapshotterConfig) error {
|
||||||
|
config.mountOptions = append(config.mountOptions, options...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type snapshotter struct {
|
type snapshotter struct {
|
||||||
root string
|
root string
|
||||||
ms *storage.MetaStore
|
ms *storage.MetaStore
|
||||||
asyncRemove bool
|
asyncRemove bool
|
||||||
upperdirLabel bool
|
upperdirLabel bool
|
||||||
indexOff bool
|
options []string
|
||||||
userxattr bool // whether to enable "userxattr" mount option
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSnapshotter returns a Snapshotter which uses overlayfs. The overlayfs
|
// NewSnapshotter returns a Snapshotter which uses overlayfs. The overlayfs
|
||||||
@ -105,10 +114,20 @@ func NewSnapshotter(root string, opts ...Opt) (snapshots.Snapshotter, error) {
|
|||||||
if err := os.Mkdir(filepath.Join(root, "snapshots"), 0700); err != nil && !os.IsExist(err) {
|
if err := os.Mkdir(filepath.Join(root, "snapshots"), 0700); err != nil && !os.IsExist(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// figure out whether "userxattr" option is recognized by the kernel && needed
|
|
||||||
userxattr, err := overlayutils.NeedsUserXAttr(root)
|
if !hasOption(config.mountOptions, "userxattr", false) {
|
||||||
if err != nil {
|
// figure out whether "userxattr" option is recognized by the kernel && needed
|
||||||
logrus.WithError(err).Warnf("cannot detect whether \"userxattr\" option needs to be used, assuming to be %v", userxattr)
|
userxattr, err := overlayutils.NeedsUserXAttr(root)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Warnf("cannot detect whether \"userxattr\" option needs to be used, assuming to be %v", userxattr)
|
||||||
|
}
|
||||||
|
if userxattr {
|
||||||
|
config.mountOptions = append(config.mountOptions, "userxattr")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasOption(config.mountOptions, "index", false) && supportsIndex() {
|
||||||
|
config.mountOptions = append(config.mountOptions, "index=off")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &snapshotter{
|
return &snapshotter{
|
||||||
@ -116,11 +135,23 @@ func NewSnapshotter(root string, opts ...Opt) (snapshots.Snapshotter, error) {
|
|||||||
ms: ms,
|
ms: ms,
|
||||||
asyncRemove: config.asyncRemove,
|
asyncRemove: config.asyncRemove,
|
||||||
upperdirLabel: config.upperdirLabel,
|
upperdirLabel: config.upperdirLabel,
|
||||||
indexOff: supportsIndex(),
|
options: config.mountOptions,
|
||||||
userxattr: userxattr,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasOption(options []string, key string, hasValue bool) bool {
|
||||||
|
for _, option := range options {
|
||||||
|
if hasValue {
|
||||||
|
if strings.HasPrefix(option, key) && len(option) > len(key) && option[len(key)] == '=' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else if option == key {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Stat returns the info for an active or committed snapshot by name or
|
// Stat returns the info for an active or committed snapshot by name or
|
||||||
// key.
|
// key.
|
||||||
//
|
//
|
||||||
@ -453,17 +484,8 @@ func (o *snapshotter) mounts(s storage.Snapshot) []mount.Mount {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var options []string
|
|
||||||
|
|
||||||
// set index=off when mount overlayfs
|
|
||||||
if o.indexOff {
|
|
||||||
options = append(options, "index=off")
|
|
||||||
}
|
|
||||||
|
|
||||||
if o.userxattr {
|
|
||||||
options = append(options, "userxattr")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
options := o.options
|
||||||
if s.Kind == snapshots.KindActive {
|
if s.Kind == snapshots.KindActive {
|
||||||
options = append(options,
|
options = append(options,
|
||||||
fmt.Sprintf("workdir=%s", o.workPath(s.ID)),
|
fmt.Sprintf("workdir=%s", o.workPath(s.ID)),
|
||||||
|
@ -70,7 +70,7 @@ func TestOverlay(t *testing.T) {
|
|||||||
testOverlayOverlayRead(t, newSnapshotter)
|
testOverlayOverlayRead(t, newSnapshotter)
|
||||||
})
|
})
|
||||||
t.Run("TestOverlayView", func(t *testing.T) {
|
t.Run("TestOverlayView", func(t *testing.T) {
|
||||||
testOverlayView(t, newSnapshotter)
|
testOverlayView(t, newSnapshotterWithOpts(append(opts, WithMountOptions([]string{"volatile"}))...))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -329,7 +329,7 @@ func testOverlayView(t *testing.T, newSnapshotter testsuite.SnapshotterFunc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
supportsIndex := supportsIndex()
|
supportsIndex := supportsIndex()
|
||||||
expectedOptions := 2
|
expectedOptions := 3
|
||||||
if !supportsIndex {
|
if !supportsIndex {
|
||||||
expectedOptions--
|
expectedOptions--
|
||||||
}
|
}
|
||||||
@ -346,13 +346,16 @@ func testOverlayView(t *testing.T, newSnapshotter testsuite.SnapshotterFunc) {
|
|||||||
}
|
}
|
||||||
lowers := getParents(ctx, o, root, "/tmp/view2")
|
lowers := getParents(ctx, o, root, "/tmp/view2")
|
||||||
expected = fmt.Sprintf("lowerdir=%s:%s", lowers[0], lowers[1])
|
expected = fmt.Sprintf("lowerdir=%s:%s", lowers[0], lowers[1])
|
||||||
optIdx := 1
|
optIdx := 2
|
||||||
if !supportsIndex {
|
if !supportsIndex {
|
||||||
optIdx--
|
optIdx--
|
||||||
}
|
}
|
||||||
if userxattr {
|
if userxattr {
|
||||||
optIdx++
|
optIdx++
|
||||||
}
|
}
|
||||||
|
if m.Options[0] != "volatile" {
|
||||||
|
t.Error("expected option first option to be provided option \"volatile\"")
|
||||||
|
}
|
||||||
if m.Options[optIdx] != expected {
|
if m.Options[optIdx] != expected {
|
||||||
t.Errorf("expected option %q but received %q", expected, m.Options[optIdx])
|
t.Errorf("expected option %q but received %q", expected, m.Options[optIdx])
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,9 @@ type Config struct {
|
|||||||
RootPath string `toml:"root_path"`
|
RootPath string `toml:"root_path"`
|
||||||
UpperdirLabel bool `toml:"upperdir_label"`
|
UpperdirLabel bool `toml:"upperdir_label"`
|
||||||
SyncRemove bool `toml:"sync_remove"`
|
SyncRemove bool `toml:"sync_remove"`
|
||||||
|
|
||||||
|
// MountOptions are options used for the overlay mount (not used on bind mounts)
|
||||||
|
MountOptions []string `toml:"mount_options"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -60,6 +63,10 @@ func init() {
|
|||||||
oOpts = append(oOpts, overlay.AsynchronousRemove)
|
oOpts = append(oOpts, overlay.AsynchronousRemove)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(config.MountOptions) > 0 {
|
||||||
|
oOpts = append(oOpts, overlay.WithMountOptions(config.MountOptions))
|
||||||
|
}
|
||||||
|
|
||||||
ic.Meta.Exports["root"] = root
|
ic.Meta.Exports["root"] = root
|
||||||
return overlay.NewSnapshotter(root, oOpts...)
|
return overlay.NewSnapshotter(root, oOpts...)
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user