mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-07 11:13:48 +00:00
Merge pull request #115768 from AxeZhan/volumebinding
feature(volumebinding): Implement PreScore for VolumeBinding plugin to skip score
This commit is contained in:
commit
c02f5bc0f8
@ -260,6 +260,7 @@ leaderElection:
|
|||||||
{Name: "NodePorts"},
|
{Name: "NodePorts"},
|
||||||
}
|
}
|
||||||
plugins.PreScore.Enabled = []config.Plugin{
|
plugins.PreScore.Enabled = []config.Plugin{
|
||||||
|
{Name: "VolumeBinding"},
|
||||||
{Name: "NodeResourcesFit"},
|
{Name: "NodeResourcesFit"},
|
||||||
{Name: "InterPodAffinity"},
|
{Name: "InterPodAffinity"},
|
||||||
{Name: "TaintToleration"},
|
{Name: "TaintToleration"},
|
||||||
|
@ -107,6 +107,7 @@ var ExpandedPluginsV1 = &config.Plugins{
|
|||||||
{Name: names.TaintToleration},
|
{Name: names.TaintToleration},
|
||||||
{Name: names.NodeAffinity},
|
{Name: names.NodeAffinity},
|
||||||
{Name: names.NodeResourcesFit},
|
{Name: names.NodeResourcesFit},
|
||||||
|
{Name: names.VolumeBinding},
|
||||||
{Name: names.PodTopologySpread},
|
{Name: names.PodTopologySpread},
|
||||||
{Name: names.InterPodAffinity},
|
{Name: names.InterPodAffinity},
|
||||||
{Name: names.NodeResourcesBalancedAllocation},
|
{Name: names.NodeResourcesBalancedAllocation},
|
||||||
|
@ -53,6 +53,9 @@ type stateData struct {
|
|||||||
// it's initialized in the PreFilter phase
|
// it's initialized in the PreFilter phase
|
||||||
podVolumesByNode map[string]*PodVolumes
|
podVolumesByNode map[string]*PodVolumes
|
||||||
podVolumeClaims *PodVolumeClaims
|
podVolumeClaims *PodVolumeClaims
|
||||||
|
// hasStaticBindings declares whether the pod contains one or more StaticBinding.
|
||||||
|
// If not, vloumeBinding will skip score extension point.
|
||||||
|
hasStaticBindings bool
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +77,7 @@ var _ framework.PreFilterPlugin = &VolumeBinding{}
|
|||||||
var _ framework.FilterPlugin = &VolumeBinding{}
|
var _ framework.FilterPlugin = &VolumeBinding{}
|
||||||
var _ framework.ReservePlugin = &VolumeBinding{}
|
var _ framework.ReservePlugin = &VolumeBinding{}
|
||||||
var _ framework.PreBindPlugin = &VolumeBinding{}
|
var _ framework.PreBindPlugin = &VolumeBinding{}
|
||||||
|
var _ framework.PreScorePlugin = &VolumeBinding{}
|
||||||
var _ framework.ScorePlugin = &VolumeBinding{}
|
var _ framework.ScorePlugin = &VolumeBinding{}
|
||||||
var _ framework.EnqueueExtensions = &VolumeBinding{}
|
var _ framework.EnqueueExtensions = &VolumeBinding{}
|
||||||
|
|
||||||
@ -258,10 +262,26 @@ func (pl *VolumeBinding) Filter(ctx context.Context, cs *framework.CycleState, p
|
|||||||
// multiple goroutines call `Filter` on different nodes simultaneously and the `CycleState` may be duplicated, so we must use a local lock here
|
// multiple goroutines call `Filter` on different nodes simultaneously and the `CycleState` may be duplicated, so we must use a local lock here
|
||||||
state.Lock()
|
state.Lock()
|
||||||
state.podVolumesByNode[node.Name] = podVolumes
|
state.podVolumesByNode[node.Name] = podVolumes
|
||||||
|
state.hasStaticBindings = state.hasStaticBindings || (podVolumes != nil && len(podVolumes.StaticBindings) > 0)
|
||||||
state.Unlock()
|
state.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PreScore invoked at the preScore extension point. It checks whether volumeBinding can skip Score
|
||||||
|
func (pl *VolumeBinding) PreScore(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodes []*v1.Node) *framework.Status {
|
||||||
|
if pl.scorer == nil {
|
||||||
|
return framework.NewStatus(framework.Skip)
|
||||||
|
}
|
||||||
|
state, err := getStateData(cs)
|
||||||
|
if err != nil {
|
||||||
|
return framework.AsStatus(err)
|
||||||
|
}
|
||||||
|
if state.hasStaticBindings {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return framework.NewStatus(framework.Skip)
|
||||||
|
}
|
||||||
|
|
||||||
// Score invoked at the score extension point.
|
// Score invoked at the score extension point.
|
||||||
func (pl *VolumeBinding) Score(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
|
func (pl *VolumeBinding) Score(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
|
||||||
if pl.scorer == nil {
|
if pl.scorer == nil {
|
||||||
|
@ -85,6 +85,7 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
wantStateAfterPreFilter *stateData
|
wantStateAfterPreFilter *stateData
|
||||||
wantFilterStatus []*framework.Status
|
wantFilterStatus []*framework.Status
|
||||||
wantScores []int64
|
wantScores []int64
|
||||||
|
wantPreScoreStatus *framework.Status
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "pod has not pvcs",
|
name: "pod has not pvcs",
|
||||||
@ -96,9 +97,7 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
wantFilterStatus: []*framework.Status{
|
wantFilterStatus: []*framework.Status{
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
wantScores: []int64{
|
wantPreScoreStatus: framework.NewStatus(framework.Skip),
|
||||||
0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "all bound",
|
name: "all bound",
|
||||||
@ -125,9 +124,7 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
wantFilterStatus: []*framework.Status{
|
wantFilterStatus: []*framework.Status{
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
wantScores: []int64{
|
wantPreScoreStatus: framework.NewStatus(framework.Skip),
|
||||||
0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "all bound with local volumes",
|
name: "all bound with local volumes",
|
||||||
@ -164,9 +161,7 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
wantFilterStatus: []*framework.Status{
|
wantFilterStatus: []*framework.Status{
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
wantScores: []int64{
|
wantPreScoreStatus: framework.NewStatus(framework.Skip),
|
||||||
0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "PVC does not exist",
|
name: "PVC does not exist",
|
||||||
@ -239,9 +234,7 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
wantFilterStatus: []*framework.Status{
|
wantFilterStatus: []*framework.Status{
|
||||||
framework.NewStatus(framework.UnschedulableAndUnresolvable, string(ErrReasonBindConflict)),
|
framework.NewStatus(framework.UnschedulableAndUnresolvable, string(ErrReasonBindConflict)),
|
||||||
},
|
},
|
||||||
wantScores: []int64{
|
wantPreScoreStatus: framework.NewStatus(framework.Skip),
|
||||||
0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bound and unbound unsatisfied",
|
name: "bound and unbound unsatisfied",
|
||||||
@ -279,9 +272,7 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
wantFilterStatus: []*framework.Status{
|
wantFilterStatus: []*framework.Status{
|
||||||
framework.NewStatus(framework.UnschedulableAndUnresolvable, string(ErrReasonNodeConflict), string(ErrReasonBindConflict)),
|
framework.NewStatus(framework.UnschedulableAndUnresolvable, string(ErrReasonNodeConflict), string(ErrReasonBindConflict)),
|
||||||
},
|
},
|
||||||
wantScores: []int64{
|
wantPreScoreStatus: framework.NewStatus(framework.Skip),
|
||||||
0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pvc not found",
|
name: "pvc not found",
|
||||||
@ -320,9 +311,7 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
wantFilterStatus: []*framework.Status{
|
wantFilterStatus: []*framework.Status{
|
||||||
framework.NewStatus(framework.UnschedulableAndUnresolvable, `node(s) unavailable due to one or more pvc(s) bound to non-existent pv(s)`),
|
framework.NewStatus(framework.UnschedulableAndUnresolvable, `node(s) unavailable due to one or more pvc(s) bound to non-existent pv(s)`),
|
||||||
},
|
},
|
||||||
wantScores: []int64{
|
wantPreScoreStatus: framework.NewStatus(framework.Skip),
|
||||||
0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pv not found claim lost",
|
name: "pv not found claim lost",
|
||||||
@ -878,6 +867,15 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
assert.Equal(t, item.wantFilterStatus[i], gotStatus)
|
assert.Equal(t, item.wantFilterStatus[i], gotStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.Logf("Verify: call PreScore and check status")
|
||||||
|
gotPreScoreStatus := p.PreScore(ctx, state, item.pod, item.nodes)
|
||||||
|
if diff := cmp.Diff(item.wantPreScoreStatus, gotPreScoreStatus); diff != "" {
|
||||||
|
t.Errorf("state got after prescore does not match (-want,+got):\n%s", diff)
|
||||||
|
}
|
||||||
|
if !gotPreScoreStatus.IsSuccess() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
t.Logf("Verify: Score")
|
t.Logf("Verify: Score")
|
||||||
for i, node := range item.nodes {
|
for i, node := range item.nodes {
|
||||||
score, status := p.Score(ctx, state, item.pod, node.Name)
|
score, status := p.Score(ctx, state, item.pod, node.Name)
|
||||||
|
Loading…
Reference in New Issue
Block a user