Merge pull request #45610 from bsalamat/priority_api
Automatic merge from submit-queue (batch tested with PRs 45610, 47628) Add Priority to Kubernetes API **What this PR does / why we need it**: This is the first in a series of PRs to add priority to Kubernetes API. Subsequent PRs will add priority name resolution to admission controller. **Release note**: ```release-note Add PriorityClassName and Priority fields to PodSpec. ```
This commit is contained in:
@@ -2213,6 +2213,20 @@ type PodSpec struct {
|
||||
// file if specified. This is only valid for non-hostNetwork pods.
|
||||
// +optional
|
||||
HostAliases []HostAlias
|
||||
// If specified, indicates the pod's priority. "SYSTEM" is a special keyword
|
||||
// which indicates the highest priority. Any other name must be defined by
|
||||
// creating a PriorityClass object with that name.
|
||||
// If not specified, the pod priority will be default or zero if there is no
|
||||
// default.
|
||||
// +optional
|
||||
PriorityClassName string
|
||||
// The priority value. Various system components use this field to find the
|
||||
// priority of the pod. When Priority Admission Controller is enabled, it
|
||||
// prevents users from setting this field. The admission controller populates
|
||||
// this field from PriorityClassName.
|
||||
// The higher the value, the higher the priority.
|
||||
// +optional
|
||||
Priority *int32
|
||||
}
|
||||
|
||||
// HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the
|
||||
|
||||
@@ -3532,6 +3532,8 @@ func autoConvert_v1_PodSpec_To_api_PodSpec(in *v1.PodSpec, out *api.PodSpec, s c
|
||||
out.SchedulerName = in.SchedulerName
|
||||
out.Tolerations = *(*[]api.Toleration)(unsafe.Pointer(&in.Tolerations))
|
||||
out.HostAliases = *(*[]api.HostAlias)(unsafe.Pointer(&in.HostAliases))
|
||||
out.PriorityClassName = in.PriorityClassName
|
||||
out.Priority = (*int32)(unsafe.Pointer(in.Priority))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3577,6 +3579,8 @@ func autoConvert_api_PodSpec_To_v1_PodSpec(in *api.PodSpec, out *v1.PodSpec, s c
|
||||
out.SchedulerName = in.SchedulerName
|
||||
out.Tolerations = *(*[]v1.Toleration)(unsafe.Pointer(&in.Tolerations))
|
||||
out.HostAliases = *(*[]v1.HostAlias)(unsafe.Pointer(&in.HostAliases))
|
||||
out.PriorityClassName = in.PriorityClassName
|
||||
out.Priority = (*int32)(unsafe.Pointer(in.Priority))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -276,6 +276,10 @@ var ValidateClusterName = genericvalidation.ValidateClusterName
|
||||
// (where it should be) and this file.
|
||||
var ValidateClassName = NameIsDNSSubdomain
|
||||
|
||||
// ValidatePiorityClassName can be used to check whether the given priority
|
||||
// class name is valid.
|
||||
var ValidatePriorityClassName = NameIsDNSSubdomain
|
||||
|
||||
// TODO update all references to these functions to point to the genericvalidation ones
|
||||
// NameIsDNSSubdomain is a ValidateNameFunc for names that must be a DNS subdomain.
|
||||
func NameIsDNSSubdomain(name string, prefix bool) []string {
|
||||
@@ -2296,6 +2300,20 @@ func ValidatePodSpec(spec *api.PodSpec, fldPath *field.Path) field.ErrorList {
|
||||
allErrs = append(allErrs, ValidateHostAliases(spec.HostAliases, fldPath.Child("hostAliases"))...)
|
||||
}
|
||||
|
||||
if len(spec.PriorityClassName) > 0 {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.PodPriority) {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("priorityClassName"), "Pod priority is disabled by feature-gate"))
|
||||
} else {
|
||||
for _, msg := range ValidatePriorityClassName(spec.PriorityClassName, false) {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("priorityClassName"), spec.PriorityClassName, msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if spec.Priority != nil && !utilfeature.DefaultFeatureGate.Enabled(features.PodPriority) {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("priority"), "Pod priority is disabled by feature-gate"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
||||
@@ -3631,6 +3631,24 @@ func TestValidatePodSpec(t *testing.T) {
|
||||
minGroupID := int64(0)
|
||||
maxGroupID := int64(2147483647)
|
||||
|
||||
priorityEnabled := utilfeature.DefaultFeatureGate.Enabled("PodPriority")
|
||||
defer func() {
|
||||
var err error
|
||||
// restoring the old value
|
||||
if priorityEnabled {
|
||||
err = utilfeature.DefaultFeatureGate.Set("PodPriority=true")
|
||||
} else {
|
||||
err = utilfeature.DefaultFeatureGate.Set("PodPriority=false")
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("Failed to restore feature gate for PodPriority: %v", err)
|
||||
}
|
||||
}()
|
||||
err := utilfeature.DefaultFeatureGate.Set("PodPriority=true")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to enable feature gate for PodPriority: %v", err)
|
||||
return
|
||||
}
|
||||
successCases := []api.PodSpec{
|
||||
{ // Populate basic fields, leave defaults for most.
|
||||
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
|
||||
@@ -3739,6 +3757,13 @@ func TestValidatePodSpec(t *testing.T) {
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
{ // Populate PriorityClassName.
|
||||
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
PriorityClassName: "valid-name",
|
||||
},
|
||||
}
|
||||
for i := range successCases {
|
||||
if errs := ValidatePodSpec(&successCases[i], field.NewPath("field")); len(errs) != 0 {
|
||||
@@ -3909,12 +3934,47 @@ func TestValidatePodSpec(t *testing.T) {
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
},
|
||||
"bad PriorityClassName": {
|
||||
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
PriorityClassName: "InvalidName",
|
||||
},
|
||||
}
|
||||
for k, v := range failureCases {
|
||||
if errs := ValidatePodSpec(&v, field.NewPath("field")); len(errs) == 0 {
|
||||
t.Errorf("expected failure for %q", k)
|
||||
}
|
||||
}
|
||||
|
||||
err = utilfeature.DefaultFeatureGate.Set("PodPriority=false")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to disable feature gate for PodPriority: %v", err)
|
||||
return
|
||||
}
|
||||
priority := int32(100)
|
||||
featuregatedCases := map[string]api.PodSpec{
|
||||
"set PriorityClassName": {
|
||||
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
PriorityClassName: "valid-name",
|
||||
},
|
||||
"set Priority": {
|
||||
Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}},
|
||||
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||
RestartPolicy: api.RestartPolicyAlways,
|
||||
DNSPolicy: api.DNSClusterFirst,
|
||||
Priority: &priority,
|
||||
},
|
||||
}
|
||||
for k, v := range featuregatedCases {
|
||||
if errs := ValidatePodSpec(&v, field.NewPath("field")); len(errs) == 0 {
|
||||
t.Errorf("expected failure due to gated feature: %q", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func extendPodSpecwithTolerations(in api.PodSpec, tolerations []api.Toleration) api.PodSpec {
|
||||
@@ -5781,6 +5841,50 @@ func TestValidatePodUpdate(t *testing.T) {
|
||||
"metadata.annotations[kubernetes.io/config.mirror]",
|
||||
"changed mirror pod annotation",
|
||||
},
|
||||
{
|
||||
api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
NodeName: "node1",
|
||||
PriorityClassName: "bar-priority",
|
||||
},
|
||||
},
|
||||
api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
NodeName: "node1",
|
||||
PriorityClassName: "foo-priority",
|
||||
},
|
||||
},
|
||||
"spec: Forbidden: pod updates",
|
||||
"changed priority class name",
|
||||
},
|
||||
{
|
||||
api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
NodeName: "node1",
|
||||
PriorityClassName: "",
|
||||
},
|
||||
},
|
||||
api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "foo",
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
NodeName: "node1",
|
||||
PriorityClassName: "foo-priority",
|
||||
},
|
||||
},
|
||||
"spec: Forbidden: pod updates",
|
||||
"removed priority class name",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -2619,6 +2619,11 @@ func DeepCopy_api_PodSpec(in interface{}, out interface{}, c *conversion.Cloner)
|
||||
}
|
||||
}
|
||||
}
|
||||
if in.Priority != nil {
|
||||
in, out := &in.Priority, &out.Priority
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,12 @@ const (
|
||||
//
|
||||
// Allows running a "debug container" in a pod namespaces to troubleshoot a running pod.
|
||||
DebugContainers utilfeature.Feature = "DebugContainers"
|
||||
|
||||
// owner: @bsalamat
|
||||
// alpha: v1.8
|
||||
//
|
||||
// Add priority to pods. Priority affects scheduling and preemption of pods.
|
||||
PodPriority utilfeature.Feature = "PodPriority"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -137,6 +143,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
|
||||
PersistentLocalVolumes: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
LocalStorageCapacityIsolation: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
DebugContainers: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
PodPriority: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
|
||||
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
|
||||
// unintentionally on either side:
|
||||
|
||||
Reference in New Issue
Block a user