Skip to content

Commit 047d962

Browse files
Merge pull request #2538 from jsafrane/4.22-selinux-fix-completed-pods
OCPBUGS-66338: UPSTREAM: 135629: selinux: Fix the controller to ignore finished pods
2 parents 9d52131 + bbdf0eb commit 047d962

5 files changed

Lines changed: 450 additions & 108 deletions

File tree

pkg/controller/volume/selinuxwarning/cache/volumecache.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,19 @@ func (c *volumeCache) AddVolume(logger klog.Logger, volumeName v1.UniqueVolumeNa
114114
}
115115

116116
// The volume is already known
117-
// Add the pod to the cache or update its properties
118-
volume.pods[podKey] = podInfo{
117+
podInfo := podInfo{
119118
seLinuxLabel: label,
120119
changePolicy: changePolicy,
121120
}
121+
oldPodInfo, found := volume.pods[podKey]
122+
if found && oldPodInfo == podInfo {
123+
// The Pod is already known too and nothing changed since the last update.
124+
// All conflicts were already reported when the Pod was added / updated in the cache last time.
125+
return conflicts
126+
}
127+
128+
// Add the updated pod info to the cache
129+
volume.pods[podKey] = podInfo
122130

123131
// Emit conflicts for the pod
124132
for otherPodKey, otherPodInfo := range volume.pods {

pkg/controller/volume/selinuxwarning/selinux_warning_controller.go

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,9 @@ func NewController(
140140

141141
logger := klog.FromContext(ctx)
142142
_, err = podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
143-
AddFunc: func(obj interface{}) { c.addPod(logger, obj) },
144-
DeleteFunc: func(obj interface{}) { c.deletePod(logger, obj) },
145-
// Not watching updates: Pod volumes and SecurityContext are immutable after creation
143+
AddFunc: func(obj interface{}) { c.enqueuePod(logger, obj) },
144+
UpdateFunc: func(oldObj, newObj interface{}) { c.updatePod(logger, oldObj, newObj) },
145+
DeleteFunc: func(obj interface{}) { c.enqueuePod(logger, obj) },
146146
})
147147
if err != nil {
148148
return nil, err
@@ -178,20 +178,37 @@ func NewController(
178178
return c, nil
179179
}
180180

181-
func (c *Controller) addPod(_ klog.Logger, obj interface{}) {
181+
func (c *Controller) enqueuePod(_ klog.Logger, obj interface{}) {
182182
podRef, err := cache.DeletionHandlingObjectToName(obj)
183183
if err != nil {
184184
utilruntime.HandleError(fmt.Errorf("couldn't get key for pod %#v: %w", obj, err))
185185
}
186186
c.queue.Add(podRef)
187187
}
188188

189-
func (c *Controller) deletePod(_ klog.Logger, obj interface{}) {
190-
podRef, err := cache.DeletionHandlingObjectToName(obj)
191-
if err != nil {
192-
utilruntime.HandleError(fmt.Errorf("couldn't get key for pod %#v: %w", obj, err))
189+
func (c *Controller) updatePod(logger klog.Logger, oldObj, newObj interface{}) {
190+
// Pod.Spec fields that are relevant to this controller are immutable after creation (i.e.
191+
// pod volumes, SELinux labels, privileged flag). React to update only when the Pod
192+
// reaches its final state - kubelet will unmount the Pod volumes and the controller should
193+
// therefore remove them from the cache.
194+
oldPod, ok := oldObj.(*v1.Pod)
195+
if !ok {
196+
return
193197
}
194-
c.queue.Add(podRef)
198+
newPod, ok := newObj.(*v1.Pod)
199+
if !ok {
200+
return
201+
}
202+
203+
// This is an optimization. In theory, passing most pod updates to the controller queue should lead to noop.
204+
// To save some CPU, pass only pod updates that can cause any action in the controller
205+
if oldPod.Status.Phase == newPod.Status.Phase {
206+
return
207+
}
208+
if newPod.Status.Phase != v1.PodFailed && newPod.Status.Phase != v1.PodSucceeded {
209+
return
210+
}
211+
c.enqueuePod(logger, newObj)
195212
}
196213

197214
func (c *Controller) addPVC(logger klog.Logger, obj interface{}) {
@@ -277,11 +294,7 @@ func (c *Controller) enqueueAllPodsForPVC(logger klog.Logger, namespace, name st
277294
return
278295
}
279296
for _, obj := range objs {
280-
podRef, err := cache.DeletionHandlingObjectToName(obj)
281-
if err != nil {
282-
utilruntime.HandleError(fmt.Errorf("couldn't get key for pod %#v: %w", obj, err))
283-
}
284-
c.queue.Add(podRef)
297+
c.enqueuePod(logger, obj)
285298
}
286299
}
287300

@@ -401,6 +414,11 @@ func (c *Controller) sync(ctx context.Context, podRef cache.ObjectName) error {
401414
logger.V(5).Info("Error getting pod from informer", "pod", klog.KObj(pod), "podUID", pod.UID, "err", err)
402415
return err
403416
}
417+
if pod.Status.Phase == v1.PodFailed || pod.Status.Phase == v1.PodSucceeded {
418+
// The pod has reached its final state and kubelet is unmounting is volumes.
419+
// Remove them from the cache.
420+
return c.syncPodDelete(ctx, podRef)
421+
}
404422

405423
return c.syncPod(ctx, pod)
406424
}
@@ -481,8 +499,15 @@ func (c *Controller) syncVolume(logger klog.Logger, pod *v1.Pod, spec *volume.Sp
481499
changePolicy := v1.SELinuxChangePolicyMountOption
482500
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.SELinuxChangePolicy != nil {
483501
changePolicy = *pod.Spec.SecurityContext.SELinuxChangePolicy
502+
logger.V(5).Info("Using Pod SELinux change policy", "pod", klog.KObj(pod), "changePolicy", changePolicy)
484503
}
485-
if !pluginSupportsSELinuxContextMount {
504+
if !pluginSupportsSELinuxContextMount && changePolicy != v1.SELinuxChangePolicyRecursive {
505+
logger.V(5).Info("Volume does not support SELinux context mount, setting changePolicy to Recursive", "pod", klog.KObj(pod), "volume", spec.Name())
506+
changePolicy = v1.SELinuxChangePolicyRecursive
507+
}
508+
509+
if seLinuxLabel == "" && changePolicy != v1.SELinuxChangePolicyRecursive {
510+
logger.V(5).Info("Pod has empty SELinux label, setting changePolicy to Recursive", "pod", klog.KObj(pod))
486511
changePolicy = v1.SELinuxChangePolicyRecursive
487512
}
488513

0 commit comments

Comments
 (0)