mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Implement changes into volume plugins for skipping chown
Add a separate function for walking directories
This commit is contained in:
parent
053baaf143
commit
c52d4bf32f
@ -428,7 +428,7 @@ func (b *awsElasticBlockStoreMounter) SetUpAt(dir string, mounterArgs volume.Mou
|
||||
}
|
||||
|
||||
if !b.readOnly {
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup)
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
}
|
||||
|
||||
klog.V(4).Infof("Successfully mounted %s", dir)
|
||||
|
@ -164,7 +164,7 @@ func (m *azureDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) e
|
||||
}
|
||||
|
||||
if volumeSource.ReadOnly == nil || !*volumeSource.ReadOnly {
|
||||
volume.SetVolumeOwnership(m, mounterArgs.FsGroup)
|
||||
volume.SetVolumeOwnership(m, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
}
|
||||
|
||||
klog.V(2).Infof("azureDisk - successfully mounted disk %s on %s", diskName, dir)
|
||||
|
@ -448,7 +448,7 @@ func (b *cinderVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs
|
||||
}
|
||||
|
||||
if !b.readOnly {
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup)
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
}
|
||||
klog.V(3).Infof("Cinder volume %s mounted to %s", b.pdName, dir)
|
||||
|
||||
|
@ -256,7 +256,7 @@ func (b *configMapVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterA
|
||||
return err
|
||||
}
|
||||
|
||||
err = volume.SetVolumeOwnership(b, mounterArgs.FsGroup)
|
||||
err = volume.SetVolumeOwnership(b, mounterArgs.FsGroup, nil)
|
||||
if err != nil {
|
||||
klog.Errorf("Error applying volume ownership settings for group: %v", mounterArgs.FsGroup)
|
||||
return err
|
||||
|
@ -28,6 +28,7 @@ import (
|
||||
"k8s.io/klog"
|
||||
|
||||
api "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
storage "k8s.io/api/storage/v1beta1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@ -281,7 +282,7 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error
|
||||
// The following logic is derived from https://github.com/kubernetes/kubernetes/issues/66323
|
||||
// if fstype is "", then skip fsgroup (could be indication of non-block filesystem)
|
||||
// if fstype is provided and pv.AccessMode == ReadWriteOnly, then apply fsgroup
|
||||
err = c.applyFSGroup(fsType, mounterArgs.FsGroup)
|
||||
err = c.applyFSGroup(fsType, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
if err != nil {
|
||||
// At this point mount operation is successful:
|
||||
// 1. Since volume can not be used by the pod because of invalid permissions, we must return error
|
||||
@ -380,7 +381,7 @@ func (c *csiMountMgr) TearDownAt(dir string) error {
|
||||
// from https://github.com/kubernetes/kubernetes/issues/66323
|
||||
// 1) if fstype is "", then skip fsgroup (could be indication of non-block filesystem)
|
||||
// 2) if fstype is provided and pv.AccessMode == ReadWriteOnly and !c.spec.ReadOnly then apply fsgroup
|
||||
func (c *csiMountMgr) applyFSGroup(fsType string, fsGroup *int64) error {
|
||||
func (c *csiMountMgr) applyFSGroup(fsType string, fsGroup *int64, fsGroupChangePolicy *v1.PodFSGroupChangePolicy) error {
|
||||
if fsGroup != nil {
|
||||
if fsType == "" {
|
||||
klog.V(4).Info(log("mounter.SetupAt WARNING: skipping fsGroup, fsType not provided"))
|
||||
@ -402,7 +403,7 @@ func (c *csiMountMgr) applyFSGroup(fsType string, fsGroup *int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := volume.SetVolumeOwnership(c, fsGroup)
|
||||
err := volume.SetVolumeOwnership(c, fsGroup, fsGroupChangePolicy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/klog"
|
||||
@ -227,7 +227,7 @@ func (b *downwardAPIVolumeMounter) SetUpAt(dir string, mounterArgs volume.Mounte
|
||||
return err
|
||||
}
|
||||
|
||||
err = volume.SetVolumeOwnership(b, mounterArgs.FsGroup)
|
||||
err = volume.SetVolumeOwnership(b, mounterArgs.FsGroup, nil)
|
||||
if err != nil {
|
||||
klog.Errorf("Error applying volume ownership settings for group: %v", mounterArgs.FsGroup)
|
||||
return err
|
||||
|
@ -25,7 +25,7 @@ import (
|
||||
"k8s.io/utils/mount"
|
||||
utilstrings "k8s.io/utils/strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@ -227,7 +227,7 @@ func (ed *emptyDir) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
|
||||
err = fmt.Errorf("unknown storage medium %q", ed.medium)
|
||||
}
|
||||
|
||||
volume.SetVolumeOwnership(ed, mounterArgs.FsGroup)
|
||||
volume.SetVolumeOwnership(ed, mounterArgs.FsGroup, nil)
|
||||
|
||||
// If setting up the quota fails, just log a message but don't actually error out.
|
||||
// We'll use the old du mechanism in this case, at least until we support
|
||||
|
@ -19,6 +19,7 @@ package fc
|
||||
import (
|
||||
"os"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/utils/mount"
|
||||
|
||||
@ -39,7 +40,7 @@ type diskManager interface {
|
||||
}
|
||||
|
||||
// utility to mount a disk based filesystem
|
||||
func diskSetUp(manager diskManager, b fcDiskMounter, volPath string, mounter mount.Interface, fsGroup *int64) error {
|
||||
func diskSetUp(manager diskManager, b fcDiskMounter, volPath string, mounter mount.Interface, fsGroup *int64, fsGroupChangePolicy *v1.PodFSGroupChangePolicy) error {
|
||||
globalPDPath := manager.MakeGlobalPDName(*b.fcDisk)
|
||||
noMnt, err := mounter.IsLikelyNotMountPoint(volPath)
|
||||
|
||||
@ -90,7 +91,7 @@ func diskSetUp(manager diskManager, b fcDiskMounter, volPath string, mounter mou
|
||||
}
|
||||
|
||||
if !b.readOnly {
|
||||
volume.SetVolumeOwnership(&b, fsGroup)
|
||||
volume.SetVolumeOwnership(&b, fsGroup, fsGroupChangePolicy)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -362,7 +362,7 @@ func (b *fcDiskMounter) SetUp(mounterArgs volume.MounterArgs) error {
|
||||
|
||||
func (b *fcDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
|
||||
// diskSetUp checks mountpoints and prevent repeated calls
|
||||
err := diskSetUp(b.manager, *b, dir, b.mounter, mounterArgs.FsGroup)
|
||||
err := diskSetUp(b.manager, *b, dir, b.mounter, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
if err != nil {
|
||||
klog.Errorf("fc: failed to setup")
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ func (f *flexVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs)
|
||||
|
||||
if !f.readOnly {
|
||||
if f.plugin.capabilities.FSGroup {
|
||||
volume.SetVolumeOwnership(f, mounterArgs.FsGroup)
|
||||
volume.SetVolumeOwnership(f, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -361,7 +361,7 @@ func (b *flockerVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArg
|
||||
}
|
||||
|
||||
if !b.readOnly {
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup)
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
}
|
||||
|
||||
klog.V(4).Infof("successfully mounted %s", dir)
|
||||
|
@ -429,7 +429,7 @@ func (b *gcePersistentDiskMounter) SetUpAt(dir string, mounterArgs volume.Mounte
|
||||
}
|
||||
|
||||
if !b.readOnly {
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup)
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
volumeutil "k8s.io/kubernetes/pkg/volume/util"
|
||||
@ -236,7 +236,7 @@ func (b *gitRepoVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArg
|
||||
return fmt.Errorf("failed to exec 'git reset --hard': %s: %v", output, err)
|
||||
}
|
||||
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup)
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup, nil)
|
||||
|
||||
volumeutil.SetReady(b.getMetaDir())
|
||||
return nil
|
||||
|
@ -19,6 +19,7 @@ package iscsi
|
||||
import (
|
||||
"os"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/utils/mount"
|
||||
|
||||
@ -41,7 +42,7 @@ type diskManager interface {
|
||||
// utility to mount a disk based filesystem
|
||||
// globalPDPath: global mount path like, /var/lib/kubelet/plugins/kubernetes.io/iscsi/{ifaceName}/{portal-some_iqn-lun-lun_id}
|
||||
// volPath: pod volume dir path like, /var/lib/kubelet/pods/{podUID}/volumes/kubernetes.io~iscsi/{volumeName}
|
||||
func diskSetUp(manager diskManager, b iscsiDiskMounter, volPath string, mounter mount.Interface, fsGroup *int64) error {
|
||||
func diskSetUp(manager diskManager, b iscsiDiskMounter, volPath string, mounter mount.Interface, fsGroup *int64, fsGroupChangePolicy *v1.PodFSGroupChangePolicy) error {
|
||||
notMnt, err := mounter.IsLikelyNotMountPoint(volPath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
klog.Errorf("cannot validate mountpoint: %s", volPath)
|
||||
@ -95,7 +96,7 @@ func diskSetUp(manager diskManager, b iscsiDiskMounter, volPath string, mounter
|
||||
}
|
||||
|
||||
if !b.readOnly {
|
||||
volume.SetVolumeOwnership(&b, fsGroup)
|
||||
volume.SetVolumeOwnership(&b, fsGroup, fsGroupChangePolicy)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -345,7 +345,7 @@ func (b *iscsiDiskMounter) SetUp(mounterArgs volume.MounterArgs) error {
|
||||
|
||||
func (b *iscsiDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
|
||||
// diskSetUp checks mountpoints and prevent repeated calls
|
||||
err := diskSetUp(b.manager, *b, dir, b.mounter, mounterArgs.FsGroup)
|
||||
err := diskSetUp(b.manager, *b, dir, b.mounter, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
if err != nil {
|
||||
klog.Errorf("iscsi: failed to setup")
|
||||
}
|
||||
|
@ -567,7 +567,7 @@ func (m *localVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs)
|
||||
if !m.readOnly {
|
||||
// Volume owner will be written only once on the first volume mount
|
||||
if len(refs) == 0 {
|
||||
return volume.SetVolumeOwnership(m, mounterArgs.FsGroup)
|
||||
return volume.SetVolumeOwnership(m, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -328,7 +328,7 @@ func (b *portworxVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterAr
|
||||
return err
|
||||
}
|
||||
if !b.readOnly {
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup)
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
}
|
||||
klog.Infof("Portworx Volume %s setup at %s", b.volumeID, dir)
|
||||
return nil
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
authenticationv1 "k8s.io/api/authentication/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@ -239,7 +239,7 @@ func (s *projectedVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterA
|
||||
return err
|
||||
}
|
||||
|
||||
err = volume.SetVolumeOwnership(s, mounterArgs.FsGroup)
|
||||
err = volume.SetVolumeOwnership(s, mounterArgs.FsGroup, nil)
|
||||
if err != nil {
|
||||
klog.Errorf("Error applying volume ownership settings for group: %v", mounterArgs.FsGroup)
|
||||
return err
|
||||
|
@ -58,7 +58,7 @@ type diskManager interface {
|
||||
}
|
||||
|
||||
// utility to mount a disk based filesystem
|
||||
func diskSetUp(manager diskManager, b rbdMounter, volPath string, mounter mount.Interface, fsGroup *int64) error {
|
||||
func diskSetUp(manager diskManager, b rbdMounter, volPath string, mounter mount.Interface, fsGroup *int64, fsGroupChangePolicy *v1.PodFSGroupChangePolicy) error {
|
||||
globalPDPath := manager.MakeGlobalPDName(*b.rbd)
|
||||
notMnt, err := mounter.IsLikelyNotMountPoint(globalPDPath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
@ -96,7 +96,7 @@ func diskSetUp(manager diskManager, b rbdMounter, volPath string, mounter mount.
|
||||
klog.V(3).Infof("rbd: successfully bind mount %s to %s with options %v", globalPDPath, volPath, mountOptions)
|
||||
|
||||
if !b.ReadOnly {
|
||||
volume.SetVolumeOwnership(&b, fsGroup)
|
||||
volume.SetVolumeOwnership(&b, fsGroup, fsGroupChangePolicy)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -838,7 +838,7 @@ func (b *rbdMounter) SetUp(mounterArgs volume.MounterArgs) error {
|
||||
func (b *rbdMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
|
||||
// diskSetUp checks mountpoints and prevent repeated calls
|
||||
klog.V(4).Infof("rbd: attempting to setup at %s", dir)
|
||||
err := diskSetUp(b.manager, *b, dir, b.mounter, mounterArgs.FsGroup)
|
||||
err := diskSetUp(b.manager, *b, dir, b.mounter, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
if err != nil {
|
||||
klog.Errorf("rbd: failed to setup at %s %v", dir, err)
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ func (v *sioVolume) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
|
||||
|
||||
if !v.readOnly && mounterArgs.FsGroup != nil {
|
||||
klog.V(4).Info(log("applying value FSGroup ownership"))
|
||||
volume.SetVolumeOwnership(v, mounterArgs.FsGroup)
|
||||
volume.SetVolumeOwnership(v, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
}
|
||||
|
||||
klog.V(4).Info(log("successfully setup PV %s: volume %s mapped as %s mounted at %s", v.volSpecName, v.volName, devicePath, dir))
|
||||
|
@ -251,7 +251,7 @@ func (b *secretVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs
|
||||
return err
|
||||
}
|
||||
|
||||
err = volume.SetVolumeOwnership(b, mounterArgs.FsGroup)
|
||||
err = volume.SetVolumeOwnership(b, mounterArgs.FsGroup, nil)
|
||||
if err != nil {
|
||||
klog.Errorf("Error applying volume ownership settings for group: %v", mounterArgs.FsGroup)
|
||||
return err
|
||||
|
@ -431,7 +431,7 @@ func (b *storageosMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) e
|
||||
}
|
||||
|
||||
if !b.readOnly {
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup)
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
}
|
||||
klog.V(4).Infof("StorageOS volume setup complete on %s", dir)
|
||||
return nil
|
||||
|
@ -542,9 +542,14 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
|
||||
}
|
||||
|
||||
var fsGroup *int64
|
||||
if volumeToMount.Pod.Spec.SecurityContext != nil &&
|
||||
volumeToMount.Pod.Spec.SecurityContext.FSGroup != nil {
|
||||
fsGroup = volumeToMount.Pod.Spec.SecurityContext.FSGroup
|
||||
var fsGroupChangePolicy *v1.PodFSGroupChangePolicy
|
||||
if podSc := volumeToMount.Pod.Spec.SecurityContext; podSc != nil {
|
||||
if podSc.FSGroup != nil {
|
||||
fsGroup = podSc.FSGroup
|
||||
}
|
||||
if podSc.FSGroupChangePolicy != nil {
|
||||
fsGroupChangePolicy = podSc.FSGroupChangePolicy
|
||||
}
|
||||
}
|
||||
|
||||
devicePath := volumeToMount.DevicePath
|
||||
@ -622,8 +627,9 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
|
||||
|
||||
// Execute mount
|
||||
mountErr := volumeMounter.SetUp(volume.MounterArgs{
|
||||
FsGroup: fsGroup,
|
||||
DesiredSize: volumeToMount.DesiredSizeLimit,
|
||||
FsGroup: fsGroup,
|
||||
DesiredSize: volumeToMount.DesiredSizeLimit,
|
||||
FSGroupChangePolicy: fsGroupChangePolicy,
|
||||
})
|
||||
// Update actual state of world
|
||||
markOpts := MarkVolumeOpts{
|
||||
|
@ -103,8 +103,9 @@ type Attributes struct {
|
||||
|
||||
// MounterArgs provides more easily extensible arguments to Mounter
|
||||
type MounterArgs struct {
|
||||
FsGroup *int64
|
||||
DesiredSize *resource.Quantity
|
||||
FsGroup *int64
|
||||
FSGroupChangePolicy *v1.PodFSGroupChangePolicy
|
||||
DesiredSize *resource.Quantity
|
||||
}
|
||||
|
||||
// Mounter interface provides methods to set up/mount the volume.
|
||||
|
@ -24,7 +24,10 @@ import (
|
||||
|
||||
"os"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -36,60 +39,187 @@ const (
|
||||
// SetVolumeOwnership modifies the given volume to be owned by
|
||||
// fsGroup, and sets SetGid so that newly created files are owned by
|
||||
// fsGroup. If fsGroup is nil nothing is done.
|
||||
func SetVolumeOwnership(mounter Mounter, fsGroup *int64) error {
|
||||
|
||||
func SetVolumeOwnership(mounter Mounter, fsGroup *int64, fsGroupChangePolicy *v1.PodFSGroupChangePolicy) error {
|
||||
if fsGroup == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
fsGroupPolicyEnabled := utilfeature.DefaultFeatureGate.Enabled(features.ConfigurableFSGroupPolicy)
|
||||
|
||||
klog.Warningf("Setting volume ownership for %s and fsGroup set. If the volume has a lot of files then setting volume ownership could be slow, see https://github.com/kubernetes/kubernetes/issues/69699", mounter.GetPath())
|
||||
|
||||
// This code exists for legacy purposes, so as old behaviour is entirely preserved when feature gate is disabled
|
||||
// TODO: remove this when ConfigurableFSGroupPolicy turns beta.
|
||||
if !fsGroupPolicyEnabled {
|
||||
return legacyPermissionChange(mounter, fsGroup)
|
||||
}
|
||||
|
||||
if skipPermissionChange(mounter, fsGroup, fsGroupChangePolicy) {
|
||||
klog.V(3).Infof("skipping permission and ownership change for volume %s", mounter.GetPath())
|
||||
return nil
|
||||
}
|
||||
|
||||
return walkDeep(mounter.GetPath(), func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return changeFilePermission(path, fsGroup, mounter.GetAttributes().ReadOnly, info)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func legacyPermissionChange(mounter Mounter, fsGroup *int64) error {
|
||||
return filepath.Walk(mounter.GetPath(), func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// chown and chmod pass through to the underlying file for symlinks.
|
||||
// Symlinks have a mode of 777 but this really doesn't mean anything.
|
||||
// The permissions of the underlying file are what matter.
|
||||
// However, if one reads the mode of a symlink then chmods the symlink
|
||||
// with that mode, it changes the mode of the underlying file, overridden
|
||||
// the defaultMode and permissions initialized by the volume plugin, which
|
||||
// is not what we want; thus, we skip chown/chmod for symlinks.
|
||||
if info.Mode()&os.ModeSymlink != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
stat, ok := info.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if stat == nil {
|
||||
klog.Errorf("Got nil stat_t for path %v while setting ownership of volume", path)
|
||||
return nil
|
||||
}
|
||||
|
||||
err = os.Chown(path, int(stat.Uid), int(*fsGroup))
|
||||
if err != nil {
|
||||
klog.Errorf("Chown failed on %v: %v", path, err)
|
||||
}
|
||||
|
||||
mask := rwMask
|
||||
if mounter.GetAttributes().ReadOnly {
|
||||
mask = roMask
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
mask |= os.ModeSetgid
|
||||
mask |= execMask
|
||||
}
|
||||
|
||||
err = os.Chmod(path, info.Mode()|mask)
|
||||
if err != nil {
|
||||
klog.Errorf("Chmod failed on %v: %v", path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return changeFilePermission(path, fsGroup, mounter.GetAttributes().ReadOnly, info)
|
||||
})
|
||||
}
|
||||
|
||||
func changeFilePermission(filename string, fsGroup *int64, readonly bool, info os.FileInfo) error {
|
||||
// chown and chmod pass through to the underlying file for symlinks.
|
||||
// Symlinks have a mode of 777 but this really doesn't mean anything.
|
||||
// The permissions of the underlying file are what matter.
|
||||
// However, if one reads the mode of a symlink then chmods the symlink
|
||||
// with that mode, it changes the mode of the underlying file, overridden
|
||||
// the defaultMode and permissions initialized by the volume plugin, which
|
||||
// is not what we want; thus, we skip chown/chmod for symlinks.
|
||||
if info.Mode()&os.ModeSymlink != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
stat, ok := info.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if stat == nil {
|
||||
klog.Errorf("Got nil stat_t for path %v while setting ownership of volume", filename)
|
||||
return nil
|
||||
}
|
||||
|
||||
err := os.Chown(filename, int(stat.Uid), int(*fsGroup))
|
||||
if err != nil {
|
||||
klog.Errorf("Chown failed on %v: %v", filename, err)
|
||||
}
|
||||
|
||||
mask := rwMask
|
||||
if readonly {
|
||||
mask = roMask
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
mask |= os.ModeSetgid
|
||||
mask |= execMask
|
||||
}
|
||||
|
||||
err = os.Chmod(filename, info.Mode()|mask)
|
||||
if err != nil {
|
||||
klog.Errorf("Chmod failed on %v: %v", filename, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func skipPermissionChange(mounter Mounter, fsGroup *int64, fsGroupChangePolicy *v1.PodFSGroupChangePolicy) bool {
|
||||
dir := mounter.GetPath()
|
||||
|
||||
if fsGroupChangePolicy == nil || *fsGroupChangePolicy != v1.OnRootMismatch {
|
||||
klog.V(4).Infof("perform recursive ownership change for %s", dir)
|
||||
return false
|
||||
}
|
||||
return !requiresPermissionChange(mounter.GetPath(), fsGroup, mounter.GetAttributes().ReadOnly)
|
||||
}
|
||||
|
||||
func requiresPermissionChange(rootDir string, fsGroup *int64, readonly bool) bool {
|
||||
fsInfo, err := os.Stat(rootDir)
|
||||
if err != nil {
|
||||
klog.Errorf("performing recursive ownership change on %s because reading permissions of root volume failed: %v", rootDir, err)
|
||||
return true
|
||||
}
|
||||
stat, ok := fsInfo.Sys().(*syscall.Stat_t)
|
||||
if !ok || stat == nil {
|
||||
klog.Errorf("performing recursive ownership change on %s because reading permissions of root volume failed", rootDir)
|
||||
return true
|
||||
}
|
||||
|
||||
if int(stat.Gid) != int(*fsGroup) {
|
||||
klog.V(4).Infof("expected group ownership of volume %s did not match with: %d", rootDir, stat.Gid)
|
||||
return true
|
||||
}
|
||||
unixPerms := rwMask
|
||||
|
||||
if readonly {
|
||||
unixPerms = roMask
|
||||
}
|
||||
|
||||
// if rootDir is not a directory then we should apply permission change anyways
|
||||
if !fsInfo.IsDir() {
|
||||
return true
|
||||
}
|
||||
unixPerms |= execMask
|
||||
filePerm := fsInfo.Mode().Perm()
|
||||
|
||||
// We need to check if actual permissions of root directory is a superset of permissions required by unixPerms
|
||||
// and setgid bits are set in permissions of the directory.
|
||||
if (unixPerms&filePerm != unixPerms) || (fsInfo.Mode()&os.ModeSetgid == 0) {
|
||||
klog.V(4).Infof("performing recursive ownership change on %s because of mismatching mode", rootDir)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// readDirNames reads the directory named by dirname and returns
|
||||
// a list of directory entries.
|
||||
// We are not using filepath.readDirNames because we do not want to sort files found in a directory before changing
|
||||
// permissions for performance reasons.
|
||||
func readDirNames(dirname string) ([]string, error) {
|
||||
f, err := os.Open(dirname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
names, err := f.Readdirnames(-1)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// walkDeep can be used to traverse directories and has two minor differences
|
||||
// from filepath.Walk:
|
||||
// - List of files/dirs is not sorted for performance reasons
|
||||
// - callback walkFunc is invoked on root directory after visiting children dirs and files
|
||||
func walkDeep(root string, walkFunc filepath.WalkFunc) error {
|
||||
info, err := os.Lstat(root)
|
||||
if err != nil {
|
||||
return walkFunc(root, nil, err)
|
||||
}
|
||||
return walk(root, info, walkFunc)
|
||||
}
|
||||
|
||||
func walk(path string, info os.FileInfo, walkFunc filepath.WalkFunc) error {
|
||||
if !info.IsDir() {
|
||||
return walkFunc(path, info, nil)
|
||||
}
|
||||
names, err := readDirNames(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, name := range names {
|
||||
filename := filepath.Join(path, name)
|
||||
fileInfo, err := os.Lstat(filename)
|
||||
if err != nil {
|
||||
if err := walkFunc(filename, fileInfo, err); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = walk(filename, fileInfo, walkFunc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return walkFunc(path, info, nil)
|
||||
}
|
||||
|
162
pkg/volume/volume_linux_test.go
Normal file
162
pkg/volume/volume_linux_test.go
Normal file
@ -0,0 +1,162 @@
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2020 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package volume
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
utiltesting "k8s.io/client-go/util/testing"
|
||||
)
|
||||
|
||||
type localFakeMounter struct {
|
||||
path string
|
||||
attributes Attributes
|
||||
}
|
||||
|
||||
func (l *localFakeMounter) GetPath() string {
|
||||
return l.path
|
||||
}
|
||||
|
||||
func (l *localFakeMounter) GetAttributes() Attributes {
|
||||
return l.attributes
|
||||
}
|
||||
|
||||
func (l *localFakeMounter) CanMount() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *localFakeMounter) SetUp(mounterArgs MounterArgs) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *localFakeMounter) SetUpAt(dir string, mounterArgs MounterArgs) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *localFakeMounter) GetMetrics() (*Metrics, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func TestSkipPermissionChange(t *testing.T) {
|
||||
always := v1.AlwaysChangeVolumePermission
|
||||
onrootMismatch := v1.OnRootMismatch
|
||||
tests := []struct {
|
||||
description string
|
||||
fsGroupChangePolicy *v1.PodFSGroupChangePolicy
|
||||
gidOwnerMatch bool
|
||||
permissionMatch bool
|
||||
sgidMatch bool
|
||||
skipPermssion bool
|
||||
}{
|
||||
{
|
||||
description: "skippermission=false, policy=nil",
|
||||
skipPermssion: false,
|
||||
},
|
||||
{
|
||||
description: "skippermission=false, policy=always",
|
||||
fsGroupChangePolicy: &always,
|
||||
skipPermssion: false,
|
||||
},
|
||||
{
|
||||
description: "skippermission=false, policy=onrootmismatch, gidmatch=false",
|
||||
fsGroupChangePolicy: &onrootMismatch,
|
||||
gidOwnerMatch: false,
|
||||
skipPermssion: false,
|
||||
},
|
||||
{
|
||||
description: "skippermission=false, policy=onrootmismatch, gidmatch=true, permmatch=false",
|
||||
fsGroupChangePolicy: &onrootMismatch,
|
||||
gidOwnerMatch: true,
|
||||
permissionMatch: false,
|
||||
skipPermssion: false,
|
||||
},
|
||||
{
|
||||
description: "skippermission=false, policy=onrootmismatch, gidmatch=true, permmatch=true",
|
||||
fsGroupChangePolicy: &onrootMismatch,
|
||||
gidOwnerMatch: true,
|
||||
permissionMatch: true,
|
||||
skipPermssion: false,
|
||||
},
|
||||
{
|
||||
description: "skippermission=false, policy=onrootmismatch, gidmatch=true, permmatch=true, sgidmatch=true",
|
||||
fsGroupChangePolicy: &onrootMismatch,
|
||||
gidOwnerMatch: true,
|
||||
permissionMatch: true,
|
||||
sgidMatch: true,
|
||||
skipPermssion: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
tmpDir, err := utiltesting.MkTmpdir("volume_linux_test")
|
||||
if err != nil {
|
||||
t.Fatalf("error creating temp dir: %v", err)
|
||||
}
|
||||
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
info, err := os.Lstat(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatalf("error reading permission of tmpdir: %v", err)
|
||||
}
|
||||
|
||||
stat, ok := info.Sys().(*syscall.Stat_t)
|
||||
if !ok || stat == nil {
|
||||
t.Fatalf("error reading permission stats for tmpdir: %s", tmpDir)
|
||||
}
|
||||
|
||||
gid := stat.Gid
|
||||
|
||||
var expectedGid int64
|
||||
|
||||
if test.gidOwnerMatch {
|
||||
expectedGid = int64(gid)
|
||||
} else {
|
||||
expectedGid = int64(gid + 3000)
|
||||
}
|
||||
|
||||
mask := rwMask
|
||||
|
||||
if test.sgidMatch {
|
||||
mask |= os.ModeSetgid
|
||||
}
|
||||
|
||||
if test.permissionMatch {
|
||||
mask |= execMask
|
||||
|
||||
}
|
||||
err = os.Chmod(tmpDir, info.Mode()|mask)
|
||||
if err != nil {
|
||||
t.Errorf("Chmod failed on %v: %v", tmpDir, err)
|
||||
}
|
||||
|
||||
mounter := &localFakeMounter{path: tmpDir}
|
||||
ok = skipPermissionChange(mounter, &expectedGid, test.fsGroupChangePolicy)
|
||||
if ok != test.skipPermssion {
|
||||
t.Errorf("for %s expected skipPermission to be %v got %v", test.description, test.skipPermssion, ok)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
@ -18,6 +18,10 @@ limitations under the License.
|
||||
|
||||
package volume
|
||||
|
||||
func SetVolumeOwnership(mounter Mounter, fsGroup *int64) error {
|
||||
import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func SetVolumeOwnership(mounter Mounter, fsGroup *int64, fsGroupChangePolicy *v1.PodFSGroupChangePolicy) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ func (b *vsphereVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArg
|
||||
os.Remove(dir)
|
||||
return err
|
||||
}
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup)
|
||||
volume.SetVolumeOwnership(b, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
|
||||
klog.V(3).Infof("vSphere volume %s mounted to %s", b.volPath, dir)
|
||||
|
||||
return nil
|
||||
|
Loading…
Reference in New Issue
Block a user