mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-04 01:40:07 +00:00
Merge pull request #124958 from bells17/qhint-volume-binding-storageclass
volumebinding: scheduler queueing hints - StorageClass
This commit is contained in:
commit
89283e0219
@ -25,6 +25,7 @@ import (
|
|||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
storagev1 "k8s.io/api/storage/v1"
|
storagev1 "k8s.io/api/storage/v1"
|
||||||
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
corelisters "k8s.io/client-go/listers/core/v1"
|
corelisters "k8s.io/client-go/listers/core/v1"
|
||||||
@ -98,7 +99,7 @@ func (pl *VolumeBinding) EventsToRegister() []framework.ClusterEventWithHint {
|
|||||||
// Pods may fail because of missing or mis-configured storage class
|
// Pods may fail because of missing or mis-configured storage class
|
||||||
// (e.g., allowedTopologies, volumeBindingMode), and hence may become
|
// (e.g., allowedTopologies, volumeBindingMode), and hence may become
|
||||||
// schedulable upon StorageClass Add or Update events.
|
// schedulable upon StorageClass Add or Update events.
|
||||||
{Event: framework.ClusterEvent{Resource: framework.StorageClass, ActionType: framework.Add | framework.Update}},
|
{Event: framework.ClusterEvent{Resource: framework.StorageClass, ActionType: framework.Add | framework.Update}, QueueingHintFn: pl.isSchedulableAfterStorageClassChange},
|
||||||
|
|
||||||
// We bind PVCs with PVs, so any changes may make the pods schedulable.
|
// We bind PVCs with PVs, so any changes may make the pods schedulable.
|
||||||
{Event: framework.ClusterEvent{Resource: framework.PersistentVolumeClaim, ActionType: framework.Add | framework.Update}, QueueingHintFn: pl.isSchedulableAfterPersistentVolumeClaimChange},
|
{Event: framework.ClusterEvent{Resource: framework.PersistentVolumeClaim, ActionType: framework.Add | framework.Update}, QueueingHintFn: pl.isSchedulableAfterPersistentVolumeClaimChange},
|
||||||
@ -195,6 +196,38 @@ func (pl *VolumeBinding) isSchedulableAfterPersistentVolumeClaimChange(logger kl
|
|||||||
return framework.QueueSkip, nil
|
return framework.QueueSkip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isSchedulableAfterStorageClassChange checks whether an StorageClass event might make a Pod schedulable or not.
|
||||||
|
// Any StorageClass addition and a StorageClass update to allowedTopologies
|
||||||
|
// might make a Pod schedulable.
|
||||||
|
// Note that an update to volume binding mode is not allowed and we don't have to consider while examining the update event.
|
||||||
|
func (pl *VolumeBinding) isSchedulableAfterStorageClassChange(logger klog.Logger, pod *v1.Pod, oldObj, newObj interface{}) (framework.QueueingHint, error) {
|
||||||
|
oldSC, newSC, err := util.As[*storagev1.StorageClass](oldObj, newObj)
|
||||||
|
if err != nil {
|
||||||
|
return framework.Queue, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger = klog.LoggerWithValues(
|
||||||
|
logger,
|
||||||
|
"Pod", klog.KObj(pod),
|
||||||
|
"StorageClass", klog.KObj(newSC),
|
||||||
|
)
|
||||||
|
|
||||||
|
if oldSC == nil {
|
||||||
|
// No further filtering can be made for a creation event,
|
||||||
|
// and we just always return Queue.
|
||||||
|
logger.V(5).Info("A new StorageClass was created, which could make a Pod schedulable")
|
||||||
|
return framework.Queue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !apiequality.Semantic.DeepEqual(newSC.AllowedTopologies, oldSC.AllowedTopologies) {
|
||||||
|
logger.V(5).Info("StorageClass got an update in AllowedTopologies", "AllowedTopologies", newSC.AllowedTopologies)
|
||||||
|
return framework.Queue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.V(5).Info("StorageClass was updated, but it doesn't make this pod schedulable")
|
||||||
|
return framework.QueueSkip, nil
|
||||||
|
}
|
||||||
|
|
||||||
// podHasPVCs returns 2 values:
|
// podHasPVCs returns 2 values:
|
||||||
// - the first one to denote if the given "pod" has any PVC defined.
|
// - the first one to denote if the given "pod" has any PVC defined.
|
||||||
// - the second one to return any error if the requested PVC is illegal.
|
// - the second one to return any error if the requested PVC is illegal.
|
||||||
|
@ -1093,3 +1093,91 @@ func TestIsSchedulableAfterPersistentVolumeClaimChange(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsSchedulableAfterStorageClassChange(t *testing.T) {
|
||||||
|
table := []struct {
|
||||||
|
name string
|
||||||
|
pod *v1.Pod
|
||||||
|
oldSC interface{}
|
||||||
|
newSC interface{}
|
||||||
|
pvcLister tf.PersistentVolumeClaimLister
|
||||||
|
err bool
|
||||||
|
expect framework.QueueingHint
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "When a new StorageClass is created, it returns Queue",
|
||||||
|
pod: makePod("pod-a").Pod,
|
||||||
|
oldSC: nil,
|
||||||
|
newSC: &storagev1.StorageClass{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "sc-a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: false,
|
||||||
|
expect: framework.Queue,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "When the AllowedTopologies are changed, it returns Queue",
|
||||||
|
pod: makePod("pod-a").Pod,
|
||||||
|
oldSC: &storagev1.StorageClass{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "sc-a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
newSC: &storagev1.StorageClass{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "sc-a",
|
||||||
|
},
|
||||||
|
AllowedTopologies: []v1.TopologySelectorTerm{
|
||||||
|
{
|
||||||
|
MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{
|
||||||
|
{
|
||||||
|
Key: "kubernetes.io/hostname",
|
||||||
|
Values: []string{"node-a"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: false,
|
||||||
|
expect: framework.Queue,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "When there are no changes to the StorageClass, it returns QueueSkip",
|
||||||
|
pod: makePod("pod-a").Pod,
|
||||||
|
oldSC: &storagev1.StorageClass{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "sc-a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
newSC: &storagev1.StorageClass{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "sc-a",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: false,
|
||||||
|
expect: framework.QueueSkip,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "type conversion error",
|
||||||
|
oldSC: new(struct{}),
|
||||||
|
newSC: new(struct{}),
|
||||||
|
err: true,
|
||||||
|
expect: framework.Queue,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range table {
|
||||||
|
t.Run(item.name, func(t *testing.T) {
|
||||||
|
pl := &VolumeBinding{PVCLister: item.pvcLister}
|
||||||
|
logger, _ := ktesting.NewTestContext(t)
|
||||||
|
qhint, err := pl.isSchedulableAfterStorageClassChange(logger, item.pod, item.oldSC, item.newSC)
|
||||||
|
if (err != nil) != item.err {
|
||||||
|
t.Errorf("isSchedulableAfterStorageClassChange failed - got: %q", err)
|
||||||
|
}
|
||||||
|
if qhint != item.expect {
|
||||||
|
t.Errorf("QHint does not match: %v, want: %v", qhint, item.expect)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user