Auto-create system critical prioity classes at API server startup
This commit is contained in:
@@ -19,10 +19,12 @@ package priority
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/scheduling"
|
||||
@@ -32,7 +34,6 @@ import (
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
|
||||
kubelettypes "k8s.io/kubernetes/pkg/kubelet/types"
|
||||
schedulerapi "k8s.io/kubernetes/pkg/scheduler/api"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -154,7 +155,7 @@ func (p *priorityPlugin) admitPod(a admission.Attributes) error {
|
||||
if len(pod.Spec.PriorityClassName) == 0 &&
|
||||
utilfeature.DefaultFeatureGate.Enabled(features.ExperimentalCriticalPodAnnotation) &&
|
||||
kubelettypes.IsCritical(a.GetNamespace(), pod.Annotations) {
|
||||
pod.Spec.PriorityClassName = schedulerapi.SystemClusterCritical
|
||||
pod.Spec.PriorityClassName = scheduling.SystemClusterCritical
|
||||
}
|
||||
if len(pod.Spec.PriorityClassName) == 0 {
|
||||
var err error
|
||||
@@ -163,22 +164,17 @@ func (p *priorityPlugin) admitPod(a admission.Attributes) error {
|
||||
return fmt.Errorf("failed to get default priority class: %v", err)
|
||||
}
|
||||
} else {
|
||||
// First try to resolve by system priority classes.
|
||||
priority, ok = schedulerapi.SystemPriorityClasses[pod.Spec.PriorityClassName]
|
||||
if !ok {
|
||||
// Now that we didn't find any system priority, try resolving by user defined priority classes.
|
||||
pc, err := p.lister.Get(pod.Spec.PriorityClassName)
|
||||
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return admission.NewForbidden(a, fmt.Errorf("no PriorityClass with name %v was found", pod.Spec.PriorityClassName))
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to get PriorityClass with name %s: %v", pod.Spec.PriorityClassName, err)
|
||||
// Try resolving the priority class name.
|
||||
pc, err := p.lister.Get(pod.Spec.PriorityClassName)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return admission.NewForbidden(a, fmt.Errorf("no PriorityClass with name %v was found", pod.Spec.PriorityClassName))
|
||||
}
|
||||
|
||||
priority = pc.Value
|
||||
return fmt.Errorf("failed to get PriorityClass with name %s: %v", pod.Spec.PriorityClassName, err)
|
||||
}
|
||||
|
||||
priority = pc.Value
|
||||
}
|
||||
pod.Spec.Priority = &priority
|
||||
}
|
||||
@@ -192,11 +188,15 @@ func (p *priorityPlugin) validatePriorityClass(a admission.Attributes) error {
|
||||
if !ok {
|
||||
return errors.NewBadRequest("resource was marked with kind PriorityClass but was unable to be converted")
|
||||
}
|
||||
if pc.Value > schedulerapi.HighestUserDefinablePriority {
|
||||
return admission.NewForbidden(a, fmt.Errorf("maximum allowed value of a user defined priority is %v", schedulerapi.HighestUserDefinablePriority))
|
||||
}
|
||||
if _, ok := schedulerapi.SystemPriorityClasses[pc.Name]; ok {
|
||||
return admission.NewForbidden(a, fmt.Errorf("the name of the priority class is a reserved name for system use only: %v", pc.Name))
|
||||
// API server adds system critical priority classes at bootstrapping. We should
|
||||
// not enforce restrictions on adding system level priority classes for API server.
|
||||
if userInfo := a.GetUserInfo(); userInfo == nil || userInfo.GetName() != user.APIServerUser {
|
||||
if pc.Value > scheduling.HighestUserDefinablePriority {
|
||||
return admission.NewForbidden(a, fmt.Errorf("maximum allowed value of a user defined priority is %v", scheduling.HighestUserDefinablePriority))
|
||||
}
|
||||
if strings.HasPrefix(pc.Name, scheduling.SystemPriorityClassPrefix) {
|
||||
return admission.NewForbidden(a, fmt.Errorf("priority class names with '"+scheduling.SystemPriorityClassPrefix+"' prefix are reserved for system use only"))
|
||||
}
|
||||
}
|
||||
// If the new PriorityClass tries to be the default priority, make sure that no other priority class is marked as default.
|
||||
if pc.GlobalDefault {
|
||||
|
@@ -24,13 +24,13 @@ import (
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/scheduling"
|
||||
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
schedulerapi "k8s.io/kubernetes/pkg/scheduler/api"
|
||||
)
|
||||
|
||||
func addPriorityClasses(ctrl *priorityPlugin, priorityClasses []*scheduling.PriorityClass) {
|
||||
@@ -75,6 +75,17 @@ var nondefaultClass1 = &scheduling.PriorityClass{
|
||||
Description: "Just a test priority class",
|
||||
}
|
||||
|
||||
var systemClusterCritical = &scheduling.PriorityClass{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "PriorityClass",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: scheduling.SystemClusterCritical,
|
||||
},
|
||||
Value: scheduling.SystemCriticalPriority,
|
||||
GlobalDefault: true,
|
||||
}
|
||||
|
||||
func TestPriorityClassAdmission(t *testing.T) {
|
||||
var tooHighPriorityClass = &scheduling.PriorityClass{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
@@ -83,7 +94,7 @@ func TestPriorityClassAdmission(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "toohighclass",
|
||||
},
|
||||
Value: schedulerapi.HighestUserDefinablePriority + 1,
|
||||
Value: scheduling.HighestUserDefinablePriority + 1,
|
||||
Description: "Just a test priority class",
|
||||
}
|
||||
|
||||
@@ -92,42 +103,56 @@ func TestPriorityClassAdmission(t *testing.T) {
|
||||
Kind: "PriorityClass",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: schedulerapi.SystemClusterCritical,
|
||||
Name: scheduling.SystemPriorityClassPrefix + "test",
|
||||
},
|
||||
Value: schedulerapi.HighestUserDefinablePriority + 1,
|
||||
Description: "Name conflicts with system priority class names",
|
||||
Value: scheduling.HighestUserDefinablePriority + 1,
|
||||
Description: "Name has system critical prefix",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
existingClasses []*scheduling.PriorityClass
|
||||
newClass *scheduling.PriorityClass
|
||||
userInfo user.Info
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
"one default class",
|
||||
[]*scheduling.PriorityClass{},
|
||||
defaultClass1,
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"more than one default classes",
|
||||
[]*scheduling.PriorityClass{defaultClass1},
|
||||
defaultClass2,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"too high PriorityClass value",
|
||||
[]*scheduling.PriorityClass{},
|
||||
tooHighPriorityClass,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"system name conflict",
|
||||
[]*scheduling.PriorityClass{},
|
||||
systemClass,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"system name allowed for API server",
|
||||
[]*scheduling.PriorityClass{},
|
||||
systemClass,
|
||||
&user.DefaultInfo{
|
||||
Name: user.APIServerUser,
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -146,7 +171,7 @@ func TestPriorityClassAdmission(t *testing.T) {
|
||||
scheduling.Resource("priorityclasses").WithVersion("version"),
|
||||
"",
|
||||
admission.Create,
|
||||
nil,
|
||||
test.userInfo,
|
||||
)
|
||||
err := ctrl.Validate(attrs)
|
||||
glog.Infof("Got %v", err)
|
||||
@@ -322,7 +347,7 @@ func TestPodAdmission(t *testing.T) {
|
||||
Name: containerName,
|
||||
},
|
||||
},
|
||||
PriorityClassName: schedulerapi.SystemClusterCritical,
|
||||
PriorityClassName: scheduling.SystemClusterCritical,
|
||||
},
|
||||
},
|
||||
// pod[5]: mirror Pod with a system priority class name
|
||||
@@ -419,9 +444,9 @@ func TestPodAdmission(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"pod with a system priority class",
|
||||
[]*scheduling.PriorityClass{},
|
||||
[]*scheduling.PriorityClass{systemClusterCritical},
|
||||
*pods[4],
|
||||
schedulerapi.SystemCriticalPriority,
|
||||
scheduling.SystemCriticalPriority,
|
||||
false,
|
||||
},
|
||||
{
|
||||
@@ -440,9 +465,9 @@ func TestPodAdmission(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"mirror pod with system priority class",
|
||||
[]*scheduling.PriorityClass{},
|
||||
[]*scheduling.PriorityClass{systemClusterCritical},
|
||||
*pods[5],
|
||||
schedulerapi.SystemCriticalPriority,
|
||||
scheduling.SystemCriticalPriority,
|
||||
false,
|
||||
},
|
||||
{
|
||||
@@ -454,9 +479,9 @@ func TestPodAdmission(t *testing.T) {
|
||||
},
|
||||
{
|
||||
"pod with critical pod annotation",
|
||||
[]*scheduling.PriorityClass{},
|
||||
[]*scheduling.PriorityClass{systemClusterCritical},
|
||||
*pods[7],
|
||||
schedulerapi.SystemCriticalPriority,
|
||||
scheduling.SystemCriticalPriority,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
Reference in New Issue
Block a user