Skip to content

Commit ce8cccb

Browse files
authored
Merge pull request kubernetes#81072 from draveness/feature/runtime-class-scheduling-admission-plugin
[RuntimeClassScheduling] Update runtime class admission plugin - Part2
2 parents e2f57be + 5732c63 commit ce8cccb

File tree

3 files changed

+225
-37
lines changed

3 files changed

+225
-37
lines changed

plugin/pkg/admission/runtimeclass/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ go_library(
1010
"//pkg/apis/node:go_default_library",
1111
"//pkg/apis/node/v1beta1:go_default_library",
1212
"//pkg/features:go_default_library",
13+
"//pkg/util/tolerations:go_default_library",
1314
"//staging/src/k8s.io/api/node/v1beta1:go_default_library",
1415
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
1516
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",

plugin/pkg/admission/runtimeclass/admission.go

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
node "k8s.io/kubernetes/pkg/apis/node"
3939
nodev1beta1 "k8s.io/kubernetes/pkg/apis/node/v1beta1"
4040
"k8s.io/kubernetes/pkg/features"
41+
"k8s.io/kubernetes/pkg/util/tolerations"
4142
)
4243

4344
// PluginName indicates name of admission plugin.
@@ -81,6 +82,9 @@ func (r *RuntimeClass) ValidateInitialization() error {
8182

8283
// Admit makes an admission decision based on the request attributes
8384
func (r *RuntimeClass) Admit(ctx context.Context, attributes admission.Attributes, o admission.ObjectInterfaces) error {
85+
if !utilfeature.DefaultFeatureGate.Enabled(features.RuntimeClass) {
86+
return nil
87+
}
8488

8589
// Ignore all calls to subresources or resources other than pods.
8690
if shouldIgnore(attributes) {
@@ -92,18 +96,20 @@ func (r *RuntimeClass) Admit(ctx context.Context, attributes admission.Attribute
9296
return err
9397
}
9498
if utilfeature.DefaultFeatureGate.Enabled(features.PodOverhead) {
95-
err = setOverhead(attributes, pod, runtimeClass)
96-
if err != nil {
99+
if err := setOverhead(attributes, pod, runtimeClass); err != nil {
97100
return err
98101
}
99102
}
100103

104+
if err := setScheduling(attributes, pod, runtimeClass); err != nil {
105+
return err
106+
}
107+
101108
return nil
102109
}
103110

104111
// Validate makes sure that pod adhere's to RuntimeClass's definition
105112
func (r *RuntimeClass) Validate(ctx context.Context, attributes admission.Attributes, o admission.ObjectInterfaces) error {
106-
107113
// Ignore all calls to subresources or resources other than pods.
108114
if shouldIgnore(attributes) {
109115
return nil
@@ -114,7 +120,7 @@ func (r *RuntimeClass) Validate(ctx context.Context, attributes admission.Attrib
114120
return err
115121
}
116122
if utilfeature.DefaultFeatureGate.Enabled(features.PodOverhead) {
117-
if err = validateOverhead(attributes, pod, runtimeClass); err != nil {
123+
if err := validateOverhead(attributes, pod, runtimeClass); err != nil {
118124
return err
119125
}
120126
}
@@ -131,34 +137,33 @@ func NewRuntimeClass() *RuntimeClass {
131137

132138
// prepareObjects returns pod and runtimeClass types from the given admission attributes
133139
func (r *RuntimeClass) prepareObjects(attributes admission.Attributes) (pod *api.Pod, runtimeClass *v1beta1.RuntimeClass, err error) {
134-
135140
pod, ok := attributes.GetObject().(*api.Pod)
136141
if !ok {
137142
return nil, nil, apierrors.NewBadRequest("Resource was marked with kind Pod but was unable to be converted")
138143
}
139144

145+
if pod.Spec.RuntimeClassName == nil {
146+
return pod, nil, nil
147+
}
148+
140149
// get RuntimeClass object
141-
if pod.Spec.RuntimeClassName != nil {
142-
runtimeClass, err = r.runtimeClassLister.Get(*pod.Spec.RuntimeClassName)
143-
if err != nil {
144-
return pod, nil, err
145-
}
150+
runtimeClass, err = r.runtimeClassLister.Get(*pod.Spec.RuntimeClassName)
151+
if apierrors.IsNotFound(err) {
152+
return pod, nil, admission.NewForbidden(attributes, fmt.Errorf("pod rejected: RuntimeClass %q not found", *pod.Spec.RuntimeClassName))
146153
}
147154

148-
// return the pod and runtimeClass. If no RuntimeClass is specified in PodSpec, runtimeClass will be nil
149-
return pod, runtimeClass, nil
155+
// return the pod and runtimeClass.
156+
return pod, runtimeClass, err
150157
}
151158

152159
func setOverhead(a admission.Attributes, pod *api.Pod, runtimeClass *v1beta1.RuntimeClass) (err error) {
153-
154160
if runtimeClass == nil || runtimeClass.Overhead == nil {
155161
return nil
156162
}
157163

158164
// convert to internal type and assign to pod's Overhead
159165
nodeOverhead := &node.Overhead{}
160-
err = nodev1beta1.Convert_v1beta1_Overhead_To_node_Overhead(runtimeClass.Overhead, nodeOverhead, nil)
161-
if err != nil {
166+
if err = nodev1beta1.Convert_v1beta1_Overhead_To_node_Overhead(runtimeClass.Overhead, nodeOverhead, nil); err != nil {
162167
return err
163168
}
164169

@@ -172,13 +177,43 @@ func setOverhead(a admission.Attributes, pod *api.Pod, runtimeClass *v1beta1.Run
172177
return nil
173178
}
174179

175-
func validateOverhead(a admission.Attributes, pod *api.Pod, runtimeClass *v1beta1.RuntimeClass) (err error) {
180+
func setScheduling(a admission.Attributes, pod *api.Pod, runtimeClass *v1beta1.RuntimeClass) (err error) {
181+
if runtimeClass == nil || runtimeClass.Scheduling == nil {
182+
return nil
183+
}
184+
185+
// convert to internal type and assign to pod's Scheduling
186+
nodeScheduling := &node.Scheduling{}
187+
if err = nodev1beta1.Convert_v1beta1_Scheduling_To_node_Scheduling(runtimeClass.Scheduling, nodeScheduling, nil); err != nil {
188+
return err
189+
}
190+
191+
runtimeNodeSelector := nodeScheduling.NodeSelector
192+
newNodeSelector := pod.Spec.NodeSelector
193+
if newNodeSelector == nil {
194+
newNodeSelector = runtimeNodeSelector
195+
} else {
196+
for key, runtimeClassValue := range runtimeNodeSelector {
197+
if podValue, ok := newNodeSelector[key]; ok && podValue != runtimeClassValue {
198+
return admission.NewForbidden(a, fmt.Errorf("conflict: runtimeClass.scheduling.nodeSelector[%s] = %s; pod.spec.nodeSelector[%s] = %s", key, runtimeClassValue, key, podValue))
199+
}
200+
newNodeSelector[key] = runtimeClassValue
201+
}
202+
}
203+
204+
newTolerations := tolerations.MergeTolerations(pod.Spec.Tolerations, nodeScheduling.Tolerations)
176205

206+
pod.Spec.NodeSelector = newNodeSelector
207+
pod.Spec.Tolerations = newTolerations
208+
209+
return nil
210+
}
211+
212+
func validateOverhead(a admission.Attributes, pod *api.Pod, runtimeClass *v1beta1.RuntimeClass) (err error) {
177213
if runtimeClass != nil && runtimeClass.Overhead != nil {
178214
// If the Overhead set doesn't match what is provided in the RuntimeClass definition, reject the pod
179215
nodeOverhead := &node.Overhead{}
180-
err := nodev1beta1.Convert_v1beta1_Overhead_To_node_Overhead(runtimeClass.Overhead, nodeOverhead, nil)
181-
if err != nil {
216+
if err := nodev1beta1.Convert_v1beta1_Overhead_To_node_Overhead(runtimeClass.Overhead, nodeOverhead, nil); err != nil {
182217
return err
183218
}
184219
if !apiequality.Semantic.DeepEqual(nodeOverhead.PodFixed, pod.Spec.Overhead) {

0 commit comments

Comments
 (0)