Skip to content

Commit 7a30cf8

Browse files
authored
Merge pull request kubernetes#91241 from pancernik/scheduler-plugin-args-validation
Move Scheduler plugin args validation to apis/config/validation
2 parents c5aa1ed + 85be9c1 commit 7a30cf8

File tree

12 files changed

+380
-326
lines changed

12 files changed

+380
-326
lines changed

cmd/kube-scheduler/app/options/deprecated.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"k8s.io/apimachinery/pkg/util/validation/field"
2424
"k8s.io/kubernetes/pkg/scheduler/algorithmprovider"
2525
kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
26+
"k8s.io/kubernetes/pkg/scheduler/apis/config/validation"
2627
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity"
2728
)
2829

@@ -79,7 +80,7 @@ func (o *DeprecatedOptions) Validate() []error {
7980
errs = append(errs, field.Required(field.NewPath("policyConfigFile"), "required when --use-legacy-policy-config is true"))
8081
}
8182

82-
if err := interpodaffinity.ValidateHardPodAffinityWeight(field.NewPath("hardPodAffinitySymmetricWeight"), o.HardPodAffinitySymmetricWeight); err != nil {
83+
if err := validation.ValidateHardPodAffinityWeight(field.NewPath("hardPodAffinitySymmetricWeight"), o.HardPodAffinitySymmetricWeight); err != nil {
8384
errs = append(errs, err)
8485
}
8586

pkg/scheduler/apis/config/validation/BUILD

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
22

33
go_library(
44
name = "go_default_library",
5-
srcs = ["validation.go"],
5+
srcs = [
6+
"validation.go",
7+
"validation_pluginargs.go",
8+
],
69
importpath = "k8s.io/kubernetes/pkg/scheduler/apis/config/validation",
710
visibility = ["//visibility:public"],
811
deps = [
912
"//pkg/apis/core/v1/helper:go_default_library",
1013
"//pkg/scheduler/apis/config:go_default_library",
1114
"//staging/src/k8s.io/api/core/v1:go_default_library",
15+
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library",
1216
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
1317
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
1418
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
@@ -20,10 +24,14 @@ go_library(
2024

2125
go_test(
2226
name = "go_default_test",
23-
srcs = ["validation_test.go"],
27+
srcs = [
28+
"validation_pluginargs_test.go",
29+
"validation_test.go",
30+
],
2431
embed = [":go_default_library"],
2532
deps = [
2633
"//pkg/scheduler/apis/config:go_default_library",
34+
"//staging/src/k8s.io/api/core/v1:go_default_library",
2735
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
2836
"//staging/src/k8s.io/component-base/config:go_default_library",
2937
],
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package validation
18+
19+
import (
20+
"fmt"
21+
22+
v1 "k8s.io/api/core/v1"
23+
metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
24+
"k8s.io/apimachinery/pkg/util/sets"
25+
"k8s.io/apimachinery/pkg/util/validation/field"
26+
"k8s.io/kubernetes/pkg/scheduler/apis/config"
27+
)
28+
29+
// ValidateInterPodAffinityArgs validates that InterPodAffinityArgs are correct.
30+
func ValidateInterPodAffinityArgs(args config.InterPodAffinityArgs) error {
31+
return ValidateHardPodAffinityWeight(field.NewPath("hardPodAffinityWeight"), args.HardPodAffinityWeight)
32+
}
33+
34+
// ValidateHardPodAffinityWeight validates that weight is within allowed range.
35+
func ValidateHardPodAffinityWeight(path *field.Path, w int32) error {
36+
const (
37+
minHardPodAffinityWeight = 0
38+
maxHardPodAffinityWeight = 100
39+
)
40+
41+
if w < minHardPodAffinityWeight || w > maxHardPodAffinityWeight {
42+
msg := fmt.Sprintf("not in valid range [%d-%d]", minHardPodAffinityWeight, maxHardPodAffinityWeight)
43+
return field.Invalid(path, w, msg)
44+
}
45+
return nil
46+
}
47+
48+
// ValidateNodeLabelArgs validates that NodeLabelArgs are correct.
49+
func ValidateNodeLabelArgs(args config.NodeLabelArgs) error {
50+
if err := validateNoConflict(args.PresentLabels, args.AbsentLabels); err != nil {
51+
return err
52+
}
53+
if err := validateNoConflict(args.PresentLabelsPreference, args.AbsentLabelsPreference); err != nil {
54+
return err
55+
}
56+
return nil
57+
}
58+
59+
// validateNoConflict validates that presentLabels and absentLabels do not conflict.
60+
func validateNoConflict(presentLabels []string, absentLabels []string) error {
61+
m := make(map[string]struct{}, len(presentLabels))
62+
for _, l := range presentLabels {
63+
m[l] = struct{}{}
64+
}
65+
for _, l := range absentLabels {
66+
if _, ok := m[l]; ok {
67+
return fmt.Errorf("detecting at least one label (e.g., %q) that exist in both the present(%+v) and absent(%+v) label list", l, presentLabels, absentLabels)
68+
}
69+
}
70+
return nil
71+
}
72+
73+
// ValidatePodTopologySpreadArgs validates that PodTopologySpreadArgs are correct.
74+
// It replicates the validation from pkg/apis/core/validation.validateTopologySpreadConstraints
75+
// with an additional check for .labelSelector to be nil.
76+
func ValidatePodTopologySpreadArgs(args *config.PodTopologySpreadArgs) error {
77+
var allErrs field.ErrorList
78+
path := field.NewPath("defaultConstraints")
79+
80+
for i, c := range args.DefaultConstraints {
81+
p := path.Index(i)
82+
if c.MaxSkew <= 0 {
83+
f := p.Child("maxSkew")
84+
allErrs = append(allErrs, field.Invalid(f, c.MaxSkew, "must be greater than zero"))
85+
}
86+
allErrs = append(allErrs, validateTopologyKey(p.Child("topologyKey"), c.TopologyKey)...)
87+
if err := validateWhenUnsatisfiable(p.Child("whenUnsatisfiable"), c.WhenUnsatisfiable); err != nil {
88+
allErrs = append(allErrs, err)
89+
}
90+
if c.LabelSelector != nil {
91+
f := field.Forbidden(p.Child("labelSelector"), "constraint must not define a selector, as they deduced for each pod")
92+
allErrs = append(allErrs, f)
93+
}
94+
if err := validateConstraintNotRepeat(path, args.DefaultConstraints, i); err != nil {
95+
allErrs = append(allErrs, err)
96+
}
97+
}
98+
if len(allErrs) == 0 {
99+
return nil
100+
}
101+
return allErrs.ToAggregate()
102+
}
103+
104+
func validateTopologyKey(p *field.Path, v string) field.ErrorList {
105+
var allErrs field.ErrorList
106+
if len(v) == 0 {
107+
allErrs = append(allErrs, field.Required(p, "can not be empty"))
108+
} else {
109+
allErrs = append(allErrs, metav1validation.ValidateLabelName(v, p)...)
110+
}
111+
return allErrs
112+
}
113+
114+
func validateWhenUnsatisfiable(p *field.Path, v v1.UnsatisfiableConstraintAction) *field.Error {
115+
supportedScheduleActions := sets.NewString(string(v1.DoNotSchedule), string(v1.ScheduleAnyway))
116+
117+
if len(v) == 0 {
118+
return field.Required(p, "can not be empty")
119+
}
120+
if !supportedScheduleActions.Has(string(v)) {
121+
return field.NotSupported(p, v, supportedScheduleActions.List())
122+
}
123+
return nil
124+
}
125+
126+
func validateConstraintNotRepeat(path *field.Path, constraints []v1.TopologySpreadConstraint, idx int) *field.Error {
127+
c := &constraints[idx]
128+
for i := range constraints[:idx] {
129+
other := &constraints[i]
130+
if c.TopologyKey == other.TopologyKey && c.WhenUnsatisfiable == other.WhenUnsatisfiable {
131+
return field.Duplicate(path.Index(idx), fmt.Sprintf("{%v, %v}", c.TopologyKey, c.WhenUnsatisfiable))
132+
}
133+
}
134+
return nil
135+
}

0 commit comments

Comments
 (0)