Auto-create system critical prioity classes at API server startup

This commit is contained in:
Bobby (Babak) Salamat
2018-02-22 17:38:17 -08:00
parent 79257fe611
commit ebda9584f9
9 changed files with 180 additions and 63 deletions

View File

@@ -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 {

View File

@@ -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,
},
}