Skip to content

Commit efe159e

Browse files
authored
Merge pull request kubernetes#86224 from ahg-g/ahg-prefilters
Wrap host ports metadata in a prefilter
2 parents ae57548 + c54dbd8 commit efe159e

File tree

6 files changed

+80
-62
lines changed

6 files changed

+80
-62
lines changed

pkg/scheduler/algorithm/predicates/metadata.go

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -304,34 +304,17 @@ func (m *podFitsResourcesMetadata) clone() *podFitsResourcesMetadata {
304304
return &copy
305305
}
306306

307-
type podFitsHostPortsMetadata struct {
308-
podPorts []*v1.ContainerPort
309-
}
310-
311-
func (m *podFitsHostPortsMetadata) clone() *podFitsHostPortsMetadata {
312-
if m == nil {
313-
return nil
314-
}
315-
316-
copy := podFitsHostPortsMetadata{}
317-
copy.podPorts = append([]*v1.ContainerPort(nil), m.podPorts...)
318-
319-
return &copy
320-
}
321-
322307
// NOTE: When new fields are added/removed or logic is changed, please make sure that
323308
// RemovePod, AddPod, and ShallowCopy functions are updated to work with the new changes.
324309
type predicateMetadata struct {
325-
pod *v1.Pod
326-
podBestEffort bool
310+
pod *v1.Pod
327311

328312
// evenPodsSpreadMetadata holds info of the minimum match number on each topology spread constraint,
329313
// and the match number of all valid topology pairs.
330314
evenPodsSpreadMetadata *evenPodsSpreadMetadata
331315

332316
serviceAffinityMetadata *serviceAffinityMetadata
333317
podFitsResourcesMetadata *podFitsResourcesMetadata
334-
podFitsHostPortsMetadata *podFitsHostPortsMetadata
335318
}
336319

337320
// Ensure that predicateMetadata implements algorithm.Metadata.
@@ -396,7 +379,6 @@ func (f *MetadataProducerFactory) GetPredicateMetadata(pod *v1.Pod, sharedLister
396379
pod: pod,
397380
evenPodsSpreadMetadata: evenPodsSpreadMetadata,
398381
podFitsResourcesMetadata: getPodFitsResourcesMetedata(pod),
399-
podFitsHostPortsMetadata: getPodFitsHostPortsMetadata(pod),
400382
}
401383
for predicateName, precomputeFunc := range predicateMetadataProducers {
402384
klog.V(10).Infof("Precompute: %v", predicateName)
@@ -405,12 +387,6 @@ func (f *MetadataProducerFactory) GetPredicateMetadata(pod *v1.Pod, sharedLister
405387
return predicateMetadata
406388
}
407389

408-
func getPodFitsHostPortsMetadata(pod *v1.Pod) *podFitsHostPortsMetadata {
409-
return &podFitsHostPortsMetadata{
410-
podPorts: schedutil.GetContainerPorts(pod),
411-
}
412-
}
413-
414390
func getPodFitsResourcesMetedata(pod *v1.Pod) *podFitsResourcesMetadata {
415391
return &podFitsResourcesMetadata{
416392
podRequest: GetResourceRequest(pod),
@@ -638,10 +614,8 @@ func (meta *predicateMetadata) AddPod(addedPod *v1.Pod, node *v1.Node) error {
638614
// its maps and slices, but it does not copy the contents of pointer values.
639615
func (meta *predicateMetadata) ShallowCopy() Metadata {
640616
newPredMeta := &predicateMetadata{
641-
pod: meta.pod,
642-
podBestEffort: meta.podBestEffort,
617+
pod: meta.pod,
643618
}
644-
newPredMeta.podFitsHostPortsMetadata = meta.podFitsHostPortsMetadata.clone()
645619
newPredMeta.evenPodsSpreadMetadata = meta.evenPodsSpreadMetadata.clone()
646620
newPredMeta.serviceAffinityMetadata = meta.serviceAffinityMetadata.clone()
647621
newPredMeta.podFitsResourcesMetadata = meta.podFitsResourcesMetadata.clone()

pkg/scheduler/algorithm/predicates/metadata_test.go

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,6 @@ func predicateMetadataEquivalent(meta1, meta2 *predicateMetadata) error {
6161
if !reflect.DeepEqual(meta1.pod, meta2.pod) {
6262
return fmt.Errorf("pods are not the same")
6363
}
64-
if meta1.podBestEffort != meta2.podBestEffort {
65-
return fmt.Errorf("podBestEfforts are not equal")
66-
}
67-
if len(meta1.podFitsHostPortsMetadata.podPorts) != len(meta2.podFitsHostPortsMetadata.podPorts) {
68-
return fmt.Errorf("podPorts are not equal")
69-
}
70-
for !reflect.DeepEqual(meta1.podFitsHostPortsMetadata.podPorts, meta2.podFitsHostPortsMetadata.podPorts) {
71-
return fmt.Errorf("podPorts are not equal")
72-
}
73-
7464
if meta1.serviceAffinityMetadata != nil {
7565
sortablePods1 := sortablePods(meta1.serviceAffinityMetadata.matchingPodList)
7666
sort.Sort(sortablePods1)
@@ -238,25 +228,13 @@ func TestPredicateMetadata_ShallowCopy(t *testing.T) {
238228
Namespace: "testns",
239229
},
240230
},
241-
podBestEffort: true,
242231
podFitsResourcesMetadata: &podFitsResourcesMetadata{
243232
podRequest: &schedulernodeinfo.Resource{
244233
MilliCPU: 1000,
245234
Memory: 300,
246235
AllowedPodNumber: 4,
247236
},
248237
},
249-
podFitsHostPortsMetadata: &podFitsHostPortsMetadata{
250-
podPorts: []*v1.ContainerPort{
251-
{
252-
Name: "name",
253-
HostPort: 10,
254-
ContainerPort: 20,
255-
Protocol: "TCP",
256-
HostIP: "1.2.3.4",
257-
},
258-
},
259-
},
260238
evenPodsSpreadMetadata: &evenPodsSpreadMetadata{
261239
tpKeyToCriticalPaths: map[string]*criticalPaths{
262240
"name": {{"nodeA", 1}, {"nodeC", 2}},

pkg/scheduler/algorithm/predicates/predicates.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,13 +1097,18 @@ func (s *ServiceAffinity) checkServiceAffinity(pod *v1.Pod, meta Metadata, nodeI
10971097
return false, []PredicateFailureReason{ErrServiceAffinityViolated}, nil
10981098
}
10991099

1100-
// PodFitsHostPorts checks if a node has free ports for the requested pod ports.
1101-
func PodFitsHostPorts(pod *v1.Pod, meta Metadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) {
1102-
var wantPorts []*v1.ContainerPort
1103-
if predicateMeta, ok := meta.(*predicateMetadata); ok && predicateMeta.podFitsHostPortsMetadata != nil {
1104-
wantPorts = predicateMeta.podFitsHostPortsMetadata.podPorts
1105-
} else {
1106-
// We couldn't parse metadata - fallback to computing it.
1100+
// PodFitsHostPorts is a wrapper around PodFitsHostPortsPredicate. This is needed until
1101+
// we are able to get rid of the FitPredicate function signature.
1102+
// TODO(#85822): remove this function once predicate registration logic is deleted.
1103+
func PodFitsHostPorts(pod *v1.Pod, _ Metadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) {
1104+
return PodFitsHostPortsPredicate(pod, nil, nodeInfo)
1105+
}
1106+
1107+
// PodFitsHostPortsPredicate checks if a node has free ports for the requested pod ports.
1108+
func PodFitsHostPortsPredicate(pod *v1.Pod, meta []*v1.ContainerPort, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) {
1109+
wantPorts := meta
1110+
if wantPorts == nil {
1111+
// Fallback to computing it.
11071112
wantPorts = schedutil.GetContainerPorts(pod)
11081113
}
11091114
if len(wantPorts) == 0 {

pkg/scheduler/framework/plugins/nodeports/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ go_library(
1010
"//pkg/scheduler/framework/plugins/migration:go_default_library",
1111
"//pkg/scheduler/framework/v1alpha1:go_default_library",
1212
"//pkg/scheduler/nodeinfo:go_default_library",
13+
"//pkg/scheduler/util:go_default_library",
1314
"//staging/src/k8s.io/api/core/v1:go_default_library",
1415
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
16+
"//vendor/k8s.io/klog:go_default_library",
1517
],
1618
)
1719

pkg/scheduler/framework/plugins/nodeports/node_ports.go

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,31 +18,85 @@ package nodeports
1818

1919
import (
2020
"context"
21+
"fmt"
2122

2223
v1 "k8s.io/api/core/v1"
2324
"k8s.io/apimachinery/pkg/runtime"
25+
"k8s.io/klog"
26+
2427
"k8s.io/kubernetes/pkg/scheduler/algorithm/predicates"
2528
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/migration"
2629
framework "k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1"
2730
"k8s.io/kubernetes/pkg/scheduler/nodeinfo"
31+
schedutil "k8s.io/kubernetes/pkg/scheduler/util"
2832
)
2933

3034
// NodePorts is a plugin that checks if a node has free ports for the requested pod ports.
3135
type NodePorts struct{}
3236

3337
var _ framework.FilterPlugin = &NodePorts{}
3438

35-
// Name is the name of the plugin used in the plugin registry and configurations.
36-
const Name = "NodePorts"
39+
const (
40+
// Name is the name of the plugin used in the plugin registry and configurations.
41+
Name = "NodePorts"
42+
43+
// preFilterStateKey is the key in CycleState to InterPodAffinity pre-computed data.
44+
// Using the name of the plugin will likely help us avoid collisions with other plugins.
45+
preFilterStateKey = "PreFilter" + Name
46+
)
47+
48+
type preFilterState []*v1.ContainerPort
49+
50+
// Clone the prefilter state.
51+
func (s preFilterState) Clone() framework.StateData {
52+
// The state is not impacted by adding/removing existing pods, hence we don't need to make a deep copy.
53+
return s
54+
}
3755

3856
// Name returns name of the plugin. It is used in logs, etc.
3957
func (pl *NodePorts) Name() string {
4058
return Name
4159
}
4260

61+
// PreFilter invoked at the prefilter extension point.
62+
func (pl *NodePorts) PreFilter(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod) *framework.Status {
63+
s := schedutil.GetContainerPorts(pod)
64+
cycleState.Write(preFilterStateKey, preFilterState(s))
65+
return nil
66+
}
67+
68+
// PreFilterExtensions do not exist for this plugin.
69+
func (pl *NodePorts) PreFilterExtensions() framework.PreFilterExtensions {
70+
return nil
71+
}
72+
73+
func getPreFilterState(cycleState *framework.CycleState) (preFilterState, error) {
74+
if cycleState == nil {
75+
return nil, fmt.Errorf("invalid nil CycleState")
76+
}
77+
78+
c, err := cycleState.Read(preFilterStateKey)
79+
if err != nil {
80+
// The metadata wasn't pre-computed in prefilter. We ignore the error for now since
81+
// Filter is able to handle that by computing it again.
82+
klog.Error(err)
83+
return nil, nil
84+
}
85+
86+
s, ok := c.(preFilterState)
87+
if !ok {
88+
return nil, fmt.Errorf("%+v convert to nodeports.preFilterState error", c)
89+
}
90+
return s, nil
91+
}
92+
4393
// Filter invoked at the filter extension point.
44-
func (pl *NodePorts) Filter(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, nodeInfo *nodeinfo.NodeInfo) *framework.Status {
45-
_, reasons, err := predicates.PodFitsHostPorts(pod, nil, nodeInfo)
94+
func (pl *NodePorts) Filter(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, nodeInfo *nodeinfo.NodeInfo) *framework.Status {
95+
state, err := getPreFilterState(cycleState)
96+
if err != nil {
97+
return framework.NewStatus(framework.Error, err.Error())
98+
}
99+
_, reasons, err := predicates.PodFitsHostPortsPredicate(pod, state, nodeInfo)
46100
return migration.PredicateResultToFrameworkStatus(reasons, err)
47101
}
48102

pkg/scheduler/framework/plugins/nodeports/node_ports_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,12 @@ func TestNodePorts(t *testing.T) {
150150
for _, test := range tests {
151151
t.Run(test.name, func(t *testing.T) {
152152
p, _ := New(nil, nil)
153-
gotStatus := p.(framework.FilterPlugin).Filter(context.Background(), nil, test.pod, test.nodeInfo)
153+
cycleState := framework.NewCycleState()
154+
preFilterStatus := p.(framework.PreFilterPlugin).PreFilter(context.Background(), cycleState, test.pod)
155+
if !preFilterStatus.IsSuccess() {
156+
t.Errorf("prefilter failed with status: %v", preFilterStatus)
157+
}
158+
gotStatus := p.(framework.FilterPlugin).Filter(context.Background(), cycleState, test.pod, test.nodeInfo)
154159
if !reflect.DeepEqual(gotStatus, test.wantStatus) {
155160
t.Errorf("status does not match: %v, want: %v", gotStatus, test.wantStatus)
156161
}

0 commit comments

Comments
 (0)