Skip to content

Commit 49dabe5

Browse files
committed
Monitor progress tracking for permission change
1 parent 65321bf commit 49dabe5

File tree

9 files changed

+119
-6
lines changed

9 files changed

+119
-6
lines changed

pkg/kubelet/events/event.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const (
6161
VolumeResizeFailed = "VolumeResizeFailed"
6262
VolumeResizeSuccess = "VolumeResizeSuccessful"
6363
FileSystemResizeFailed = "FileSystemResizeFailed"
64+
VolumePermissionChangeInProgress = "VolumePermissionChangeInProgress"
6465
FileSystemResizeSuccess = "FileSystemResizeSuccessful"
6566
FailedMapVolume = "FailedMapVolume"
6667
WarnAlreadyMountedVolume = "AlreadyMountedVolume"

pkg/volume/configmap/configmap.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ func (b *configMapVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterA
246246
setPerms := func(_ string) error {
247247
// This may be the first time writing and new files get created outside the timestamp subdirectory:
248248
// change the permissions on the whole volume and not only in the timestamp directory.
249-
return volume.SetVolumeOwnership(b, dir, mounterArgs.FsGroup, nil /*fsGroupChangePolicy*/, volumeutil.FSGroupCompleteHook(b.plugin, nil))
249+
ownerShipChanger := volume.NewVolumeOwnership(b, dir, mounterArgs.FsGroup, nil /*fsGroupChangePolicy*/, volumeutil.FSGroupCompleteHook(b.plugin, nil))
250+
return ownerShipChanger.ChangePermissions()
250251
}
251252
err = writer.Write(payload, setPerms)
252253
if err != nil {

pkg/volume/csi/csi_mounter.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,9 @@ func (c *csiMountMgr) SetUpAt(dir string, mounterArgs volume.MounterArgs) error
335335
// Driver doesn't support applying FSGroup. Kubelet must apply it instead.
336336

337337
// fullPluginName helps to distinguish different driver from csi plugin
338-
err := volume.SetVolumeOwnership(c, dir, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy, util.FSGroupCompleteHook(c.plugin, c.spec))
338+
ownershipChanger := volume.NewVolumeOwnership(c, dir, mounterArgs.FsGroup, mounterArgs.FSGroupChangePolicy, util.FSGroupCompleteHook(c.plugin, c.spec))
339+
ownershipChanger.AddProgressNotifier(c.pod, mounterArgs.Recorder)
340+
err = ownershipChanger.ChangePermissions()
339341
if err != nil {
340342
// At this point mount operation is successful:
341343
// 1. Since volume can not be used by the pod because of invalid permissions, we must return error

pkg/volume/downwardapi/downwardapi.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ func (b *downwardAPIVolumeMounter) SetUpAt(dir string, mounterArgs volume.Mounte
217217
setPerms := func(_ string) error {
218218
// This may be the first time writing and new files get created outside the timestamp subdirectory:
219219
// change the permissions on the whole volume and not only in the timestamp directory.
220-
return volume.SetVolumeOwnership(b, dir, mounterArgs.FsGroup, nil /*fsGroupChangePolicy*/, volumeutil.FSGroupCompleteHook(b.plugin, nil))
220+
ownershipChanger := volume.NewVolumeOwnership(b, dir, mounterArgs.FsGroup, nil /*fsGroupChangePolicy*/, volumeutil.FSGroupCompleteHook(b.plugin, nil))
221+
return ownershipChanger.ChangePermissions()
221222
}
222223
err = writer.Write(data, setPerms)
223224
if err != nil {

pkg/volume/emptydir/empty_dir.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ package emptydir
1818

1919
import (
2020
"fmt"
21-
"k8s.io/kubernetes/pkg/kubelet/util/swap"
2221
"os"
2322
"path/filepath"
2423

24+
"k8s.io/kubernetes/pkg/kubelet/util/swap"
25+
2526
"k8s.io/klog/v2"
2627
"k8s.io/mount-utils"
2728
utilstrings "k8s.io/utils/strings"
@@ -278,7 +279,8 @@ func (ed *emptyDir) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
278279
err = fmt.Errorf("unknown storage medium %q", ed.medium)
279280
}
280281

281-
volume.SetVolumeOwnership(ed, dir, mounterArgs.FsGroup, nil /*fsGroupChangePolicy*/, volumeutil.FSGroupCompleteHook(ed.plugin, nil))
282+
ownershipChanger := volume.NewVolumeOwnership(ed, dir, mounterArgs.FsGroup, nil /*fsGroupChangePolicy*/, volumeutil.FSGroupCompleteHook(ed.plugin, nil))
283+
ownershipChanger.ChangePermissions()
282284

283285
// If setting up the quota fails, just log a message but don't actually error out.
284286
// We'll use the old du mechanism in this case, at least until we support

pkg/volume/fc/disk_manager.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ func diskSetUp(manager diskManager, b fcDiskMounter, volPath string, mounter mou
9191
}
9292

9393
if !b.readOnly {
94-
volume.SetVolumeOwnership(&b, volPath, fsGroup, fsGroupChangePolicy, util.FSGroupCompleteHook(b.plugin, nil))
94+
ownershipChanger := volume.NewVolumeOwnership(&b, volPath, fsGroup, fsGroupChangePolicy, util.FSGroupCompleteHook(b.plugin, nil))
95+
ownershipChanger.ChangePermissions()
9596
}
9697

9798
return nil

pkg/volume/util/operationexecutor/operation_generator.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,7 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
584584
FsGroup: fsGroup,
585585
DesiredSize: volumeToMount.DesiredSizeLimit,
586586
FSGroupChangePolicy: fsGroupChangePolicy,
587+
Recorder: og.recorder,
587588
SELinuxLabel: volumeToMount.SELinuxLabel,
588589
})
589590
// Update actual state of world

pkg/volume/volume.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"k8s.io/apimachinery/pkg/api/resource"
2424
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2525
"k8s.io/apimachinery/pkg/types"
26+
"k8s.io/client-go/tools/record"
2627
)
2728

2829
// Volume represents a directory used by pods or hosts on a node. All method
@@ -130,6 +131,7 @@ type MounterArgs struct {
130131
FSGroupChangePolicy *v1.PodFSGroupChangePolicy
131132
DesiredSize *resource.Quantity
132133
SELinuxLabel string
134+
Recorder record.EventRecorder
133135
}
134136

135137
// Mounter interface provides methods to set up/mount the volume.

pkg/volume/volume_linux.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,125 @@ limitations under the License.
2020
package volume
2121

2222
import (
23+
"context"
24+
"fmt"
2325
"path/filepath"
26+
"sync/atomic"
2427
"syscall"
2528

2629
"os"
2730
"time"
2831

2932
v1 "k8s.io/api/core/v1"
33+
"k8s.io/client-go/tools/record"
3034
"k8s.io/klog/v2"
35+
"k8s.io/kubernetes/pkg/kubelet/events"
3136
"k8s.io/kubernetes/pkg/volume/util/types"
3237
)
3338

3439
const (
3540
rwMask = os.FileMode(0660)
3641
roMask = os.FileMode(0440)
3742
execMask = os.FileMode(0110)
43+
44+
progressReportDuration = 60 * time.Second
3845
)
3946

47+
type VolumeOwnership struct {
48+
mounter Mounter
49+
dir string
50+
fsGroup *int64
51+
fsGroupChangePolicy *v1.PodFSGroupChangePolicy
52+
completionCallback func(types.CompleteFuncParam)
53+
54+
// for monitoring progress of permission change operation
55+
pod *v1.Pod
56+
fileCounter atomic.Int64
57+
recorder record.EventRecorder
58+
}
59+
60+
func NewVolumeOwnership(mounter Mounter, dir string, fsGroup *int64, fsGroupChangePolicy *v1.PodFSGroupChangePolicy, completeFunc func(types.CompleteFuncParam)) *VolumeOwnership {
61+
vo := &VolumeOwnership{
62+
mounter: mounter,
63+
dir: dir,
64+
fsGroup: fsGroup,
65+
fsGroupChangePolicy: fsGroupChangePolicy,
66+
completionCallback: completeFunc,
67+
}
68+
vo.fileCounter.Store(0)
69+
return vo
70+
}
71+
72+
func (vo *VolumeOwnership) AddProgressNotifier(pod *v1.Pod, recorder record.EventRecorder) *VolumeOwnership {
73+
vo.pod = pod
74+
vo.recorder = recorder
75+
return vo
76+
}
77+
78+
func (vo *VolumeOwnership) ChangePermissions() error {
79+
if vo.fsGroup == nil {
80+
return nil
81+
}
82+
83+
if skipPermissionChange(vo.mounter, vo.dir, vo.fsGroup, vo.fsGroupChangePolicy) {
84+
klog.V(3).InfoS("Skipping permission and ownership change for volume", "path", vo.dir)
85+
return nil
86+
}
87+
88+
ctx, cancel := context.WithCancel(context.Background())
89+
defer cancel()
90+
91+
timer := time.AfterFunc(30*time.Second, func() {
92+
vo.initiateProgressMonitor(ctx)
93+
})
94+
defer timer.Stop()
95+
96+
return vo.changePermissionsRecursively()
97+
}
98+
99+
func (vo *VolumeOwnership) initiateProgressMonitor(ctx context.Context) {
100+
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", vo.dir)
101+
if vo.pod != nil {
102+
go vo.monitorProgress(ctx)
103+
}
104+
}
105+
106+
func (vo *VolumeOwnership) changePermissionsRecursively() error {
107+
err := walkDeep(vo.dir, func(path string, info os.FileInfo, err error) error {
108+
if err != nil {
109+
return err
110+
}
111+
vo.fileCounter.Add(1)
112+
return changeFilePermission(path, vo.fsGroup, vo.mounter.GetAttributes().ReadOnly, info)
113+
})
114+
115+
if vo.completionCallback != nil {
116+
vo.completionCallback(types.CompleteFuncParam{
117+
Err: &err,
118+
})
119+
}
120+
return err
121+
}
122+
123+
func (vo *VolumeOwnership) monitorProgress(ctx context.Context) {
124+
ticker := time.NewTicker(progressReportDuration)
125+
defer ticker.Stop()
126+
for {
127+
select {
128+
case <-ctx.Done():
129+
return
130+
case <-ticker.C:
131+
vo.logWarning()
132+
}
133+
}
134+
}
135+
136+
func (vo *VolumeOwnership) logWarning() {
137+
msg := fmt.Sprintf("Setting volume ownership for %s, processed %d files", vo.dir, vo.fileCounter.Load())
138+
klog.Warning(msg)
139+
vo.recorder.Event(vo.pod, v1.EventTypeWarning, events.VolumePermissionChangeInProgress, msg)
140+
}
141+
40142
// SetVolumeOwnership modifies the given volume to be owned by
41143
// fsGroup, and sets SetGid so that newly created files are owned by
42144
// fsGroup. If fsGroup is nil nothing is done.

0 commit comments

Comments
 (0)