mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-08-19 20:46:42 +00:00
* fix: do not mutate on update and bound pvcs Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * fix: do not mutate on update and bound pvcs Signed-off-by: Oliver Baehler <oliver@sudo-i.net> --------- Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
77 lines
2.2 KiB
Go
77 lines
2.2 KiB
Go
// Copyright 2020-2026 Project Capsule Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package pvc
|
|
|
|
import (
|
|
admissionv1 "k8s.io/api/admission/v1"
|
|
corev1 "k8s.io/api/core/v1"
|
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
|
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
|
|
|
"github.com/projectcapsule/capsule/pkg/runtime/handlers"
|
|
)
|
|
|
|
func Handler(handler ...handlers.TypedHandlerWithTenant[*corev1.PersistentVolumeClaim]) handlers.Handler {
|
|
return &handlers.TypedTenantHandler[*corev1.PersistentVolumeClaim]{
|
|
Factory: func() *corev1.PersistentVolumeClaim {
|
|
return &corev1.PersistentVolumeClaim{}
|
|
},
|
|
Handlers: handler,
|
|
Predicate: requiresPVCSpecValidation,
|
|
}
|
|
}
|
|
|
|
func MutatingHandler(handler ...handlers.TypedHandlerWithTenant[*corev1.PersistentVolumeClaim]) handlers.Handler {
|
|
return &handlers.TypedTenantHandler[*corev1.PersistentVolumeClaim]{
|
|
Factory: func() *corev1.PersistentVolumeClaim {
|
|
return &corev1.PersistentVolumeClaim{}
|
|
},
|
|
Handlers: handler,
|
|
Predicate: func(
|
|
req admission.Request,
|
|
pvc *corev1.PersistentVolumeClaim,
|
|
oldPVC *corev1.PersistentVolumeClaim,
|
|
) bool {
|
|
if !requiresPVCSpecValidation(req, pvc, oldPVC) {
|
|
return false
|
|
}
|
|
|
|
if pvc.Spec.Selector != nil {
|
|
return true
|
|
}
|
|
|
|
return req.Operation == admissionv1.Create && pvc.Spec.VolumeName != ""
|
|
},
|
|
}
|
|
}
|
|
|
|
func requiresPVCSpecValidation(
|
|
req admission.Request,
|
|
pvc *corev1.PersistentVolumeClaim,
|
|
oldPVC *corev1.PersistentVolumeClaim,
|
|
) bool {
|
|
// A bound PVC's volume binding fields, including its selector, are immutable.
|
|
// Reapplying the tenant selector during an update would make otherwise valid
|
|
// metadata or resize updates fail for claims created before Capsule enforced it.
|
|
if req.Operation == admissionv1.Update &&
|
|
isBoundPVC(oldPVC) {
|
|
return false
|
|
}
|
|
|
|
// Finalizer cleanup must remain possible after a bound PV has disappeared.
|
|
// Continue validating any update that changes the PVC spec.
|
|
if req.Operation != admissionv1.Update ||
|
|
pvc == nil ||
|
|
oldPVC == nil ||
|
|
pvc.DeletionTimestamp == nil {
|
|
return true
|
|
}
|
|
|
|
return !apiequality.Semantic.DeepEqual(pvc.Spec, oldPVC.Spec)
|
|
}
|
|
|
|
func isBoundPVC(pvc *corev1.PersistentVolumeClaim) bool {
|
|
return pvc != nil && pvc.Status.Phase == corev1.ClaimBound
|
|
}
|