Implement changes into volume plugins for skipping chown

Add a separate function for walking directories
This commit is contained in:
Hemant Kumar 2020-02-26 16:59:22 -05:00
parent 053baaf143
commit c52d4bf32f
29 changed files with 392 additions and 86 deletions

View File

@ -428,7 +428,7 @@ func (b *awsElasticBlockStoreMounter) SetUpAt(dir string, mounterArgs volume.Mou
} }
if !b.readOnly { if !b.readOnly {
volume.SetVolumeOwnership(b, mounterArgs.FsGroup) volume.SetVolumeOwnership(b, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
} }
klog.V(4).Infof("Successfully mounted %s", dir) klog.V(4).Infof("Successfully mounted %s", dir)

View File

@ -164,7 +164,7 @@ func (m *azureDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) e
} }
if volumeSource.ReadOnly == nil || !*volumeSource.ReadOnly { 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) klog.V(2).Infof("azureDisk - successfully mounted disk %s on %s", diskName, dir)

View File

@ -448,7 +448,7 @@ func (b *cinderVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs
} }
if !b.readOnly { 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) klog.V(3).Infof("Cinder volume %s mounted to %s", b.pdName, dir)

View File

@ -256,7 +256,7 @@ func (b *configMapVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterA
return err return err
} }
err = volume.SetVolumeOwnership(b, mounterArgs.FsGroup) err = volume.SetVolumeOwnership(b, mounterArgs.FsGroup, nil)
if err != nil { if err != nil {
klog.Errorf("Error applying volume ownership settings for group: %v", mounterArgs.FsGroup) klog.Errorf("Error applying volume ownership settings for group: %v", mounterArgs.FsGroup)
return err return err

View File

@ -28,6 +28,7 @@ import (
"k8s.io/klog" "k8s.io/klog"
api "k8s.io/api/core/v1" api "k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
storage "k8s.io/api/storage/v1beta1" storage "k8s.io/api/storage/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types" "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 // 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 "", then skip fsgroup (could be indication of non-block filesystem)
// if fstype is provided and pv.AccessMode == ReadWriteOnly, then apply fsgroup // 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 { if err != nil {
// At this point mount operation is successful: // 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 // 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 // from https://github.com/kubernetes/kubernetes/issues/66323
// 1) if fstype is "", then skip fsgroup (could be indication of non-block filesystem) // 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 // 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 fsGroup != nil {
if fsType == "" { if fsType == "" {
klog.V(4).Info(log("mounter.SetupAt WARNING: skipping fsGroup, fsType not provided")) 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 return nil
} }
err := volume.SetVolumeOwnership(c, fsGroup) err := volume.SetVolumeOwnership(c, fsGroup, fsGroupChangePolicy)
if err != nil { if err != nil {
return err return err
} }

View File

@ -20,7 +20,7 @@ import (
"fmt" "fmt"
"path/filepath" "path/filepath"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/klog" "k8s.io/klog"
@ -227,7 +227,7 @@ func (b *downwardAPIVolumeMounter) SetUpAt(dir string, mounterArgs volume.Mounte
return err return err
} }
err = volume.SetVolumeOwnership(b, mounterArgs.FsGroup) err = volume.SetVolumeOwnership(b, mounterArgs.FsGroup, nil)
if err != nil { if err != nil {
klog.Errorf("Error applying volume ownership settings for group: %v", mounterArgs.FsGroup) klog.Errorf("Error applying volume ownership settings for group: %v", mounterArgs.FsGroup)
return err return err

View File

@ -25,7 +25,7 @@ import (
"k8s.io/utils/mount" "k8s.io/utils/mount"
utilstrings "k8s.io/utils/strings" utilstrings "k8s.io/utils/strings"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "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) 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. // 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 // We'll use the old du mechanism in this case, at least until we support

View File

@ -19,6 +19,7 @@ package fc
import ( import (
"os" "os"
v1 "k8s.io/api/core/v1"
"k8s.io/klog" "k8s.io/klog"
"k8s.io/utils/mount" "k8s.io/utils/mount"
@ -39,7 +40,7 @@ type diskManager interface {
} }
// utility to mount a disk based filesystem // 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) globalPDPath := manager.MakeGlobalPDName(*b.fcDisk)
noMnt, err := mounter.IsLikelyNotMountPoint(volPath) noMnt, err := mounter.IsLikelyNotMountPoint(volPath)
@ -90,7 +91,7 @@ func diskSetUp(manager diskManager, b fcDiskMounter, volPath string, mounter mou
} }
if !b.readOnly { if !b.readOnly {
volume.SetVolumeOwnership(&b, fsGroup) volume.SetVolumeOwnership(&b, fsGroup, fsGroupChangePolicy)
} }
return nil return nil

View File

@ -362,7 +362,7 @@ func (b *fcDiskMounter) SetUp(mounterArgs volume.MounterArgs) error {
func (b *fcDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { func (b *fcDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
// diskSetUp checks mountpoints and prevent repeated calls // 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 { if err != nil {
klog.Errorf("fc: failed to setup") klog.Errorf("fc: failed to setup")
} }

View File

@ -93,7 +93,7 @@ func (f *flexVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs)
if !f.readOnly { if !f.readOnly {
if f.plugin.capabilities.FSGroup { if f.plugin.capabilities.FSGroup {
volume.SetVolumeOwnership(f, mounterArgs.FsGroup) volume.SetVolumeOwnership(f, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
} }
} }

View File

@ -361,7 +361,7 @@ func (b *flockerVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArg
} }
if !b.readOnly { if !b.readOnly {
volume.SetVolumeOwnership(b, mounterArgs.FsGroup) volume.SetVolumeOwnership(b, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
} }
klog.V(4).Infof("successfully mounted %s", dir) klog.V(4).Infof("successfully mounted %s", dir)

View File

@ -429,7 +429,7 @@ func (b *gcePersistentDiskMounter) SetUpAt(dir string, mounterArgs volume.Mounte
} }
if !b.readOnly { if !b.readOnly {
volume.SetVolumeOwnership(b, mounterArgs.FsGroup) volume.SetVolumeOwnership(b, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
} }
return nil return nil
} }

View File

@ -22,7 +22,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume"
volumeutil "k8s.io/kubernetes/pkg/volume/util" 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) 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()) volumeutil.SetReady(b.getMetaDir())
return nil return nil

View File

@ -19,6 +19,7 @@ package iscsi
import ( import (
"os" "os"
v1 "k8s.io/api/core/v1"
"k8s.io/klog" "k8s.io/klog"
"k8s.io/utils/mount" "k8s.io/utils/mount"
@ -41,7 +42,7 @@ type diskManager interface {
// utility to mount a disk based filesystem // 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} // 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} // 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) notMnt, err := mounter.IsLikelyNotMountPoint(volPath)
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
klog.Errorf("cannot validate mountpoint: %s", volPath) klog.Errorf("cannot validate mountpoint: %s", volPath)
@ -95,7 +96,7 @@ func diskSetUp(manager diskManager, b iscsiDiskMounter, volPath string, mounter
} }
if !b.readOnly { if !b.readOnly {
volume.SetVolumeOwnership(&b, fsGroup) volume.SetVolumeOwnership(&b, fsGroup, fsGroupChangePolicy)
} }
return nil return nil

View File

@ -345,7 +345,7 @@ func (b *iscsiDiskMounter) SetUp(mounterArgs volume.MounterArgs) error {
func (b *iscsiDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { func (b *iscsiDiskMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
// diskSetUp checks mountpoints and prevent repeated calls // 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 { if err != nil {
klog.Errorf("iscsi: failed to setup") klog.Errorf("iscsi: failed to setup")
} }

View File

@ -567,7 +567,7 @@ func (m *localVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs)
if !m.readOnly { if !m.readOnly {
// Volume owner will be written only once on the first volume mount // Volume owner will be written only once on the first volume mount
if len(refs) == 0 { if len(refs) == 0 {
return volume.SetVolumeOwnership(m, mounterArgs.FsGroup) return volume.SetVolumeOwnership(m, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy)
} }
} }
return nil return nil

View File

@ -328,7 +328,7 @@ func (b *portworxVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterAr
return err return err
} }
if !b.readOnly { 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) klog.Infof("Portworx Volume %s setup at %s", b.volumeID, dir)
return nil return nil

View File

@ -20,7 +20,7 @@ import (
"fmt" "fmt"
authenticationv1 "k8s.io/api/authentication/v1" authenticationv1 "k8s.io/api/authentication/v1"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
@ -239,7 +239,7 @@ func (s *projectedVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterA
return err return err
} }
err = volume.SetVolumeOwnership(s, mounterArgs.FsGroup) err = volume.SetVolumeOwnership(s, mounterArgs.FsGroup, nil)
if err != nil { if err != nil {
klog.Errorf("Error applying volume ownership settings for group: %v", mounterArgs.FsGroup) klog.Errorf("Error applying volume ownership settings for group: %v", mounterArgs.FsGroup)
return err return err

View File

@ -58,7 +58,7 @@ type diskManager interface {
} }
// utility to mount a disk based filesystem // 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) globalPDPath := manager.MakeGlobalPDName(*b.rbd)
notMnt, err := mounter.IsLikelyNotMountPoint(globalPDPath) notMnt, err := mounter.IsLikelyNotMountPoint(globalPDPath)
if err != nil && !os.IsNotExist(err) { 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) klog.V(3).Infof("rbd: successfully bind mount %s to %s with options %v", globalPDPath, volPath, mountOptions)
if !b.ReadOnly { if !b.ReadOnly {
volume.SetVolumeOwnership(&b, fsGroup) volume.SetVolumeOwnership(&b, fsGroup, fsGroupChangePolicy)
} }
return nil return nil

View File

@ -838,7 +838,7 @@ func (b *rbdMounter) SetUp(mounterArgs volume.MounterArgs) error {
func (b *rbdMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error { func (b *rbdMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
// diskSetUp checks mountpoints and prevent repeated calls // diskSetUp checks mountpoints and prevent repeated calls
klog.V(4).Infof("rbd: attempting to setup at %s", dir) 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 { if err != nil {
klog.Errorf("rbd: failed to setup at %s %v", dir, err) klog.Errorf("rbd: failed to setup at %s %v", dir, err)
} }

View File

@ -157,7 +157,7 @@ func (v *sioVolume) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
if !v.readOnly && mounterArgs.FsGroup != nil { if !v.readOnly && mounterArgs.FsGroup != nil {
klog.V(4).Info(log("applying value FSGroup ownership")) 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)) klog.V(4).Info(log("successfully setup PV %s: volume %s mapped as %s mounted at %s", v.volSpecName, v.volName, devicePath, dir))

View File

@ -251,7 +251,7 @@ func (b *secretVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs
return err return err
} }
err = volume.SetVolumeOwnership(b, mounterArgs.FsGroup) err = volume.SetVolumeOwnership(b, mounterArgs.FsGroup, nil)
if err != nil { if err != nil {
klog.Errorf("Error applying volume ownership settings for group: %v", mounterArgs.FsGroup) klog.Errorf("Error applying volume ownership settings for group: %v", mounterArgs.FsGroup)
return err return err

View File

@ -431,7 +431,7 @@ func (b *storageosMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) e
} }
if !b.readOnly { 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) klog.V(4).Infof("StorageOS volume setup complete on %s", dir)
return nil return nil

View File

@ -542,9 +542,14 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
} }
var fsGroup *int64 var fsGroup *int64
if volumeToMount.Pod.Spec.SecurityContext != nil && var fsGroupChangePolicy *v1.PodFSGroupChangePolicy
volumeToMount.Pod.Spec.SecurityContext.FSGroup != nil { if podSc := volumeToMount.Pod.Spec.SecurityContext; podSc != nil {
fsGroup = volumeToMount.Pod.Spec.SecurityContext.FSGroup if podSc.FSGroup != nil {
fsGroup = podSc.FSGroup
}
if podSc.FSGroupChangePolicy != nil {
fsGroupChangePolicy = podSc.FSGroupChangePolicy
}
} }
devicePath := volumeToMount.DevicePath devicePath := volumeToMount.DevicePath
@ -624,6 +629,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
mountErr := volumeMounter.SetUp(volume.MounterArgs{ mountErr := volumeMounter.SetUp(volume.MounterArgs{
FsGroup: fsGroup, FsGroup: fsGroup,
DesiredSize: volumeToMount.DesiredSizeLimit, DesiredSize: volumeToMount.DesiredSizeLimit,
FSGroupChangePolicy: fsGroupChangePolicy,
}) })
// Update actual state of world // Update actual state of world
markOpts := MarkVolumeOpts{ markOpts := MarkVolumeOpts{

View File

@ -104,6 +104,7 @@ type Attributes struct {
// MounterArgs provides more easily extensible arguments to Mounter // MounterArgs provides more easily extensible arguments to Mounter
type MounterArgs struct { type MounterArgs struct {
FsGroup *int64 FsGroup *int64
FSGroupChangePolicy *v1.PodFSGroupChangePolicy
DesiredSize *resource.Quantity DesiredSize *resource.Quantity
} }

View File

@ -24,7 +24,10 @@ import (
"os" "os"
v1 "k8s.io/api/core/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/klog" "k8s.io/klog"
"k8s.io/kubernetes/pkg/features"
) )
const ( const (
@ -36,19 +39,45 @@ const (
// SetVolumeOwnership modifies the given volume to be owned by // SetVolumeOwnership modifies the given volume to be owned by
// fsGroup, and sets SetGid so that newly created files are owned by // fsGroup, and sets SetGid so that newly created files are owned by
// fsGroup. If fsGroup is nil nothing is done. // 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 { if fsGroup == nil {
return 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()) 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 { return filepath.Walk(mounter.GetPath(), func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
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. // chown and chmod pass through to the underlying file for symlinks.
// Symlinks have a mode of 777 but this really doesn't mean anything. // Symlinks have a mode of 777 but this really doesn't mean anything.
// The permissions of the underlying file are what matter. // The permissions of the underlying file are what matter.
@ -66,17 +95,17 @@ func SetVolumeOwnership(mounter Mounter, fsGroup *int64) error {
} }
if stat == nil { if stat == nil {
klog.Errorf("Got nil stat_t for path %v while setting ownership of volume", path) klog.Errorf("Got nil stat_t for path %v while setting ownership of volume", filename)
return nil return nil
} }
err = os.Chown(path, int(stat.Uid), int(*fsGroup)) err := os.Chown(filename, int(stat.Uid), int(*fsGroup))
if err != nil { if err != nil {
klog.Errorf("Chown failed on %v: %v", path, err) klog.Errorf("Chown failed on %v: %v", filename, err)
} }
mask := rwMask mask := rwMask
if mounter.GetAttributes().ReadOnly { if readonly {
mask = roMask mask = roMask
} }
@ -85,11 +114,112 @@ func SetVolumeOwnership(mounter Mounter, fsGroup *int64) error {
mask |= execMask mask |= execMask
} }
err = os.Chmod(path, info.Mode()|mask) err = os.Chmod(filename, info.Mode()|mask)
if err != nil { if err != nil {
klog.Errorf("Chmod failed on %v: %v", path, err) klog.Errorf("Chmod failed on %v: %v", filename, err)
} }
return nil 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)
} }

View 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)
}
})
}
}

View File

@ -18,6 +18,10 @@ limitations under the License.
package volume 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 return nil
} }

View File

@ -270,7 +270,7 @@ func (b *vsphereVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArg
os.Remove(dir) os.Remove(dir)
return err 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) klog.V(3).Infof("vSphere volume %s mounted to %s", b.volPath, dir)
return nil return nil