mirror of
https://github.com/kubernetes/kubernetes.git
synced 2026-06-10 17:35:44 -04:00
Merge 391f1d9c3c into e136f39334
This commit is contained in:
commit
83e41da8b6
40 changed files with 868 additions and 123 deletions
8
api/openapi-spec/swagger.json
generated
8
api/openapi-spec/swagger.json
generated
|
|
@ -19976,6 +19976,10 @@
|
|||
"$ref": "#/definitions/io.k8s.api.scheduling.v1alpha2.PodGroupTemplateReference",
|
||||
"description": "PodGroupTemplateRef references an optional PodGroup template within other object (e.g. Workload) that was used to create the PodGroup. This field is immutable."
|
||||
},
|
||||
"preemptionPolicy": {
|
||||
"description": "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is immutable. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"type": "string"
|
||||
},
|
||||
"priority": {
|
||||
"description": "Priority is the value of priority of this pod group. Various system components use this field to find the priority of the pod group. 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. This field is immutable. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"format": "int32",
|
||||
|
|
@ -20055,6 +20059,10 @@
|
|||
"description": "Name is a unique identifier for the PodGroupTemplate within the Workload. It must be a DNS label. This field is immutable.",
|
||||
"type": "string"
|
||||
},
|
||||
"preemptionPolicy": {
|
||||
"description": "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"type": "string"
|
||||
},
|
||||
"priority": {
|
||||
"description": "Priority is the value of priority of pod groups created from this template. Various system components use this field to find the priority of the pod group. 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. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"format": "int32",
|
||||
|
|
|
|||
|
|
@ -211,6 +211,11 @@
|
|||
],
|
||||
"description": "PodGroupTemplateRef references an optional PodGroup template within other object (e.g. Workload) that was used to create the PodGroup. This field is immutable."
|
||||
},
|
||||
"preemptionPolicy": {
|
||||
"default": "PreemptLowerPriority",
|
||||
"description": "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is immutable. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"type": "string"
|
||||
},
|
||||
"priority": {
|
||||
"description": "Priority is the value of priority of this pod group. Various system components use this field to find the priority of the pod group. 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. This field is immutable. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"format": "int32",
|
||||
|
|
@ -300,6 +305,10 @@
|
|||
"description": "Name is a unique identifier for the PodGroupTemplate within the Workload. It must be a DNS label. This field is immutable.",
|
||||
"type": "string"
|
||||
},
|
||||
"preemptionPolicy": {
|
||||
"description": "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"type": "string"
|
||||
},
|
||||
"priority": {
|
||||
"description": "Priority is the value of priority of pod groups created from this template. Various system components use this field to find the priority of the pod group. 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. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"format": "int32",
|
||||
|
|
|
|||
|
|
@ -22698,20 +22698,20 @@ func TestValidateSecret(t *testing.T) {
|
|||
secret core.Secret
|
||||
valid bool
|
||||
}{
|
||||
"valid": {validSecret(), true},
|
||||
"empty name": {emptyName, false},
|
||||
"invalid name": {invalidName, false},
|
||||
"empty namespace": {emptyNs, false},
|
||||
"invalid namespace": {invalidNs, false},
|
||||
"over max size": {overMaxSize, false},
|
||||
"invalid key": {invalidKey, false},
|
||||
"valid service-account-token secret": {validServiceAccountTokenSecret(), true},
|
||||
"empty service-account-token annotation": {emptyTokenAnnotation, false},
|
||||
"valid": {validSecret(), true},
|
||||
"empty name": {emptyName, false},
|
||||
"invalid name": {invalidName, false},
|
||||
"empty namespace": {emptyNs, false},
|
||||
"invalid namespace": {invalidNs, false},
|
||||
"over max size": {overMaxSize, false},
|
||||
"invalid key": {invalidKey, false},
|
||||
"valid service-account-token secret": {validServiceAccountTokenSecret(), true},
|
||||
"empty service-account-token annotation": {emptyTokenAnnotation, false},
|
||||
"missing service-account-token annotation": {missingTokenAnnotation, false},
|
||||
"missing service-account-token annotations": {missingTokenAnnotations, false},
|
||||
"leading dot key": {leadingDotKey, true},
|
||||
"dot key": {dotKey, false},
|
||||
"double dot key": {doubleDotKey, false},
|
||||
"leading dot key": {leadingDotKey, true},
|
||||
"dot key": {dotKey, false},
|
||||
"double dot key": {doubleDotKey, false},
|
||||
}
|
||||
|
||||
for name, tc := range tests {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||
if s.Spec.DisruptionMode == nil {
|
||||
s.Spec.DisruptionMode = new(scheduling.DisruptionModePod)
|
||||
}
|
||||
if s.Spec.PreemptionPolicy == nil {
|
||||
preemptLowerPriority := core.PreemptLowerPriority
|
||||
s.Spec.PreemptionPolicy = &preemptLowerPriority
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,6 +244,16 @@ type PodGroupTemplate struct {
|
|||
// +featureGate=WorkloadAwarePreemption
|
||||
// +optional
|
||||
Priority *int32
|
||||
|
||||
// PreemptionPolicy is the Policy for preempting pods with lower priority.
|
||||
// One of Never, PreemptLowerPriority.
|
||||
// Defaults to PreemptLowerPriority if unset.
|
||||
// This field is available only when the WorkloadAwarePreemption feature gate
|
||||
// is enabled.
|
||||
//
|
||||
// +featureGate=WorkloadAwarePreemption
|
||||
// +optional
|
||||
PreemptionPolicy *core.PreemptionPolicy
|
||||
}
|
||||
|
||||
// PodGroupSchedulingPolicy defines the scheduling configuration for a PodGroup.
|
||||
|
|
@ -456,6 +466,17 @@ type PodGroupSpec struct {
|
|||
// +featureGate=WorkloadAwarePreemption
|
||||
// +optional
|
||||
Priority *int32
|
||||
|
||||
// PreemptionPolicy is the Policy for preempting pods with lower priority.
|
||||
// One of Never, PreemptLowerPriority.
|
||||
// Defaults to PreemptLowerPriority if unset.
|
||||
// This field is immutable.
|
||||
// This field is available only when the WorkloadAwarePreemption feature gate
|
||||
// is enabled.
|
||||
//
|
||||
// +featureGate=WorkloadAwarePreemption
|
||||
// +optional
|
||||
PreemptionPolicy *core.PreemptionPolicy
|
||||
}
|
||||
|
||||
// PodGroupStatus represents information about the status of a pod group.
|
||||
|
|
|
|||
|
|
@ -24,10 +24,12 @@ package v1alpha2
|
|||
import (
|
||||
unsafe "unsafe"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
schedulingv1alpha2 "k8s.io/api/scheduling/v1alpha2"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
core "k8s.io/kubernetes/pkg/apis/core"
|
||||
scheduling "k8s.io/kubernetes/pkg/apis/scheduling"
|
||||
)
|
||||
|
||||
|
|
@ -411,6 +413,7 @@ func autoConvert_v1alpha2_PodGroupSpec_To_scheduling_PodGroupSpec(in *scheduling
|
|||
out.DisruptionMode = (*scheduling.DisruptionMode)(unsafe.Pointer(in.DisruptionMode))
|
||||
out.PriorityClassName = in.PriorityClassName
|
||||
out.Priority = (*int32)(unsafe.Pointer(in.Priority))
|
||||
out.PreemptionPolicy = (*core.PreemptionPolicy)(unsafe.Pointer(in.PreemptionPolicy))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -429,6 +432,7 @@ func autoConvert_scheduling_PodGroupSpec_To_v1alpha2_PodGroupSpec(in *scheduling
|
|||
out.DisruptionMode = (*schedulingv1alpha2.DisruptionMode)(unsafe.Pointer(in.DisruptionMode))
|
||||
out.PriorityClassName = in.PriorityClassName
|
||||
out.Priority = (*int32)(unsafe.Pointer(in.Priority))
|
||||
out.PreemptionPolicy = (*v1.PreemptionPolicy)(unsafe.Pointer(in.PreemptionPolicy))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -438,7 +442,7 @@ func Convert_scheduling_PodGroupSpec_To_v1alpha2_PodGroupSpec(in *scheduling.Pod
|
|||
}
|
||||
|
||||
func autoConvert_v1alpha2_PodGroupStatus_To_scheduling_PodGroupStatus(in *schedulingv1alpha2.PodGroupStatus, out *scheduling.PodGroupStatus, s conversion.Scope) error {
|
||||
out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions))
|
||||
out.Conditions = *(*[]metav1.Condition)(unsafe.Pointer(&in.Conditions))
|
||||
out.ResourceClaimStatuses = *(*[]scheduling.PodGroupResourceClaimStatus)(unsafe.Pointer(&in.ResourceClaimStatuses))
|
||||
return nil
|
||||
}
|
||||
|
|
@ -449,7 +453,7 @@ func Convert_v1alpha2_PodGroupStatus_To_scheduling_PodGroupStatus(in *scheduling
|
|||
}
|
||||
|
||||
func autoConvert_scheduling_PodGroupStatus_To_v1alpha2_PodGroupStatus(in *scheduling.PodGroupStatus, out *schedulingv1alpha2.PodGroupStatus, s conversion.Scope) error {
|
||||
out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions))
|
||||
out.Conditions = *(*[]metav1.Condition)(unsafe.Pointer(&in.Conditions))
|
||||
out.ResourceClaimStatuses = *(*[]schedulingv1alpha2.PodGroupResourceClaimStatus)(unsafe.Pointer(&in.ResourceClaimStatuses))
|
||||
return nil
|
||||
}
|
||||
|
|
@ -469,6 +473,7 @@ func autoConvert_v1alpha2_PodGroupTemplate_To_scheduling_PodGroupTemplate(in *sc
|
|||
out.DisruptionMode = (*scheduling.DisruptionMode)(unsafe.Pointer(in.DisruptionMode))
|
||||
out.PriorityClassName = in.PriorityClassName
|
||||
out.Priority = (*int32)(unsafe.Pointer(in.Priority))
|
||||
out.PreemptionPolicy = (*core.PreemptionPolicy)(unsafe.Pointer(in.PreemptionPolicy))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -487,6 +492,7 @@ func autoConvert_scheduling_PodGroupTemplate_To_v1alpha2_PodGroupTemplate(in *sc
|
|||
out.DisruptionMode = (*schedulingv1alpha2.DisruptionMode)(unsafe.Pointer(in.DisruptionMode))
|
||||
out.PriorityClassName = in.PriorityClassName
|
||||
out.Priority = (*int32)(unsafe.Pointer(in.Priority))
|
||||
out.PreemptionPolicy = (*v1.PreemptionPolicy)(unsafe.Pointer(in.PreemptionPolicy))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ limitations under the License.
|
|||
package v1alpha2
|
||||
|
||||
import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
schedulingv1alpha2 "k8s.io/api/scheduling/v1alpha2"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
|
@ -40,6 +41,10 @@ func SetObjectDefaults_PodGroup(in *schedulingv1alpha2.PodGroup) {
|
|||
var ptrVar1 schedulingv1alpha2.DisruptionMode = "Pod"
|
||||
in.Spec.DisruptionMode = &ptrVar1
|
||||
}
|
||||
if in.Spec.PreemptionPolicy == nil {
|
||||
var ptrVar1 v1.PreemptionPolicy = "PreemptLowerPriority"
|
||||
in.Spec.PreemptionPolicy = &ptrVar1
|
||||
}
|
||||
}
|
||||
|
||||
func SetObjectDefaults_PodGroupList(in *schedulingv1alpha2.PodGroupList) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
context "context"
|
||||
fmt "fmt"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
schedulingv1alpha2 "k8s.io/api/scheduling/v1alpha2"
|
||||
equality "k8s.io/apimachinery/pkg/api/equality"
|
||||
operation "k8s.io/apimachinery/pkg/api/operation"
|
||||
|
|
@ -770,6 +771,47 @@ func Validate_PodGroupSpec(
|
|||
errs = append(errs, fn(fldPath.Child("priority"), obj.Priority, oldVal, oldObj != nil)...)
|
||||
}
|
||||
|
||||
{ // field schedulingv1alpha2.PodGroupSpec.PreemptionPolicy
|
||||
fn := func(
|
||||
fldPath *field.Path,
|
||||
obj, oldObj *v1.PreemptionPolicy,
|
||||
oldValueCorrelated bool) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if oldValueCorrelated && op.Type == operation.Update {
|
||||
if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// call field-attached validations
|
||||
earlyReturn := false
|
||||
if e := validate.IfOption(ctx, op, fldPath, obj, oldObj, "WorkloadAwarePreemption", false, validate.ForbiddenPointer).MarkShortCircuit(); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
earlyReturn = true
|
||||
}
|
||||
if e := validate.IfOption(ctx, op, fldPath, obj, oldObj, "WorkloadAwarePreemption", false, validate.OptionalPointer).MarkShortCircuit(); len(e) != 0 {
|
||||
earlyReturn = true
|
||||
}
|
||||
if e := validate.IfOption(ctx, op, fldPath, obj, oldObj, "WorkloadAwarePreemption", true, // optional fields with default values are effectively required
|
||||
validate.RequiredPointer).MarkShortCircuit(); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
earlyReturn = true
|
||||
}
|
||||
if e := validate.IfOption(ctx, op, fldPath, obj, oldObj, "WorkloadAwarePreemption", true, validate.Immutable).MarkShortCircuit(); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
earlyReturn = true
|
||||
}
|
||||
if earlyReturn {
|
||||
return // do not proceed
|
||||
}
|
||||
return
|
||||
}
|
||||
oldVal := safe.Field(oldObj,
|
||||
func(oldObj *schedulingv1alpha2.PodGroupSpec) *v1.PreemptionPolicy {
|
||||
return oldObj.PreemptionPolicy
|
||||
})
|
||||
errs = append(errs, fn(fldPath.Child("preemptionPolicy"), obj.PreemptionPolicy, oldVal, oldObj != nil)...)
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
|
|
@ -1089,6 +1131,41 @@ func Validate_PodGroupTemplate(
|
|||
errs = append(errs, fn(fldPath.Child("priority"), obj.Priority, oldVal, oldObj != nil)...)
|
||||
}
|
||||
|
||||
{ // field schedulingv1alpha2.PodGroupTemplate.PreemptionPolicy
|
||||
fn := func(
|
||||
fldPath *field.Path,
|
||||
obj, oldObj *v1.PreemptionPolicy,
|
||||
oldValueCorrelated bool) (errs field.ErrorList) {
|
||||
// don't revalidate unchanged data
|
||||
if oldValueCorrelated && op.Type == operation.Update {
|
||||
if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// call field-attached validations
|
||||
earlyReturn := false
|
||||
if e := validate.IfOption(ctx, op, fldPath, obj, oldObj, "WorkloadAwarePreemption", false, validate.ForbiddenPointer).MarkShortCircuit(); len(e) != 0 {
|
||||
errs = append(errs, e...)
|
||||
earlyReturn = true
|
||||
}
|
||||
if e := validate.IfOption(ctx, op, fldPath, obj, oldObj, "WorkloadAwarePreemption", false, validate.OptionalPointer).MarkShortCircuit(); len(e) != 0 {
|
||||
earlyReturn = true
|
||||
}
|
||||
if e := validate.IfOption(ctx, op, fldPath, obj, oldObj, "WorkloadAwarePreemption", true, validate.OptionalPointer).MarkShortCircuit(); len(e) != 0 {
|
||||
earlyReturn = true
|
||||
}
|
||||
if earlyReturn {
|
||||
return // do not proceed
|
||||
}
|
||||
return
|
||||
}
|
||||
oldVal := safe.Field(oldObj,
|
||||
func(oldObj *schedulingv1alpha2.PodGroupTemplate) *v1.PreemptionPolicy {
|
||||
return oldObj.PreemptionPolicy
|
||||
})
|
||||
errs = append(errs, fn(fldPath.Child("preemptionPolicy"), obj.PreemptionPolicy, oldVal, oldObj != nil)...)
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,11 @@ func ValidatePriorityClassUpdate(pc, oldPc *scheduling.PriorityClass) field.Erro
|
|||
|
||||
// ValidatePodGroup tests if all fields in a PodGroup are set correctly.
|
||||
func ValidatePodGroup(podGroup *scheduling.PodGroup) field.ErrorList {
|
||||
return apivalidation.ValidateObjectMeta(&podGroup.ObjectMeta, true, apivalidation.ValidatePodGroupName, field.NewPath("metadata"))
|
||||
allErrs := apivalidation.ValidateObjectMeta(&podGroup.ObjectMeta, true, apivalidation.ValidatePodGroupName, field.NewPath("metadata"))
|
||||
if podGroup.Spec.PreemptionPolicy != nil {
|
||||
allErrs = append(allErrs, apivalidation.ValidatePreemptionPolicy(podGroup.Spec.PreemptionPolicy, field.NewPath("spec", "preemptionPolicy"))...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidatePodGroupUpdate tests if an update to PodGroup is valid.
|
||||
|
|
@ -80,7 +84,15 @@ func ValidatePodGroupUpdate(podGroup, oldPodGroup *scheduling.PodGroup) field.Er
|
|||
|
||||
// ValidateWorkload tests if all fields in a Workload are set correctly.
|
||||
func ValidateWorkload(workload *scheduling.Workload) field.ErrorList {
|
||||
return apivalidation.ValidateObjectMeta(&workload.ObjectMeta, true, validateWorkloadName, field.NewPath("metadata"))
|
||||
allErrs := apivalidation.ValidateObjectMeta(&workload.ObjectMeta, true, validateWorkloadName, field.NewPath("metadata"))
|
||||
fldPath := field.NewPath("spec", "podGroupTemplates")
|
||||
for i, template := range workload.Spec.PodGroupTemplates {
|
||||
idxPath := fldPath.Index(i)
|
||||
if template.PreemptionPolicy != nil {
|
||||
allErrs = append(allErrs, apivalidation.ValidatePreemptionPolicy(template.PreemptionPolicy, idxPath.Child("preemptionPolicy"))...)
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateWorkloadUpdate tests if an update to Workload is valid.
|
||||
|
|
|
|||
|
|
@ -191,6 +191,15 @@ func TestValidateWorkload(t *testing.T) {
|
|||
"no scheduling constraints": mkWorkload(func(w *scheduling.Workload) {
|
||||
w.Spec.PodGroupTemplates[1].SchedulingConstraints = nil
|
||||
}),
|
||||
"default preemption policy (nil)": mkWorkload(), // preemption policy is unset (nil) by default
|
||||
"valid preemption policy (Never)": mkWorkload(func(w *scheduling.Workload) {
|
||||
preemptNever := core.PreemptNever
|
||||
w.Spec.PodGroupTemplates[0].PreemptionPolicy = &preemptNever
|
||||
}),
|
||||
"valid preemption policy (PreemptLowerPriority)": mkWorkload(func(w *scheduling.Workload) {
|
||||
preemptLowerPriority := core.PreemptLowerPriority
|
||||
w.Spec.PodGroupTemplates[0].PreemptionPolicy = &preemptLowerPriority
|
||||
}),
|
||||
}
|
||||
for name, workload := range successCases {
|
||||
errs := ValidateWorkload(workload)
|
||||
|
|
@ -251,6 +260,15 @@ func TestValidateWorkload(t *testing.T) {
|
|||
field.Invalid(field.NewPath("metadata", "namespace"), strings.Repeat("n", 64), "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')"),
|
||||
},
|
||||
},
|
||||
"invalid preemption policy": {
|
||||
workload: mkWorkload(func(w *scheduling.Workload) {
|
||||
invalidPolicy := core.PreemptionPolicy("Invalid")
|
||||
w.Spec.PodGroupTemplates[0].PreemptionPolicy = &invalidPolicy
|
||||
}),
|
||||
expectedErrs: field.ErrorList{
|
||||
field.NotSupported(field.NewPath("spec", "podGroupTemplates").Index(0).Child("preemptionPolicy"), "Invalid", []string{"PreemptLowerPriority", "Never"}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range failureCases {
|
||||
|
|
@ -363,6 +381,15 @@ func TestValidatePodGroup(t *testing.T) {
|
|||
"no scheduling constraints": mkPodGroup(func(pg *scheduling.PodGroup) {
|
||||
pg.Spec.SchedulingConstraints = nil
|
||||
}),
|
||||
"default preemption policy (nil)": mkPodGroup(), // preemption policy is unset (nil) by default
|
||||
"valid preemption policy (Never)": mkPodGroup(func(pg *scheduling.PodGroup) {
|
||||
preemptNever := core.PreemptNever
|
||||
pg.Spec.PreemptionPolicy = &preemptNever
|
||||
}),
|
||||
"valid preemption policy (PreemptLowerPriority)": mkPodGroup(func(pg *scheduling.PodGroup) {
|
||||
preemptLowerPriority := core.PreemptLowerPriority
|
||||
pg.Spec.PreemptionPolicy = &preemptLowerPriority
|
||||
}),
|
||||
}
|
||||
for name, podGroup := range successCases {
|
||||
errs := ValidatePodGroup(podGroup)
|
||||
|
|
@ -423,6 +450,15 @@ func TestValidatePodGroup(t *testing.T) {
|
|||
field.Invalid(field.NewPath("metadata", "namespace"), strings.Repeat("n", 64), "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')"),
|
||||
},
|
||||
},
|
||||
"invalid preemption policy": {
|
||||
podGroup: mkPodGroup(func(pg *scheduling.PodGroup) {
|
||||
invalidPolicy := core.PreemptionPolicy("Invalid")
|
||||
pg.Spec.PreemptionPolicy = &invalidPolicy
|
||||
}),
|
||||
expectedErrs: field.ErrorList{
|
||||
field.NotSupported(field.NewPath("spec", "preemptionPolicy"), "Invalid", []string{"PreemptLowerPriority", "Never"}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range failureCases {
|
||||
|
|
|
|||
10
pkg/apis/scheduling/zz_generated.deepcopy.go
generated
10
pkg/apis/scheduling/zz_generated.deepcopy.go
generated
|
|
@ -245,6 +245,11 @@ func (in *PodGroupSpec) DeepCopyInto(out *PodGroupSpec) {
|
|||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
if in.PreemptionPolicy != nil {
|
||||
in, out := &in.PreemptionPolicy, &out.PreemptionPolicy
|
||||
*out = new(core.PreemptionPolicy)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -314,6 +319,11 @@ func (in *PodGroupTemplate) DeepCopyInto(out *PodGroupTemplate) {
|
|||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
if in.PreemptionPolicy != nil {
|
||||
in, out := &in.PreemptionPolicy, &out.PreemptionPolicy
|
||||
*out = new(core.PreemptionPolicy)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
17
pkg/generated/openapi/zz_generated.openapi.go
generated
17
pkg/generated/openapi/zz_generated.openapi.go
generated
|
|
@ -54257,6 +54257,15 @@ func schema_k8sio_api_scheduling_v1alpha2_PodGroupSpec(ref common.ReferenceCallb
|
|||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"preemptionPolicy": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is immutable. This field is available only when the WorkloadAwarePreemption feature gate is enabled.\n\n\nPossible enum values:\n - `\"Never\"` means that pod never preempts other pods with lower priority.\n - `\"PreemptLowerPriority\"` means that pod can preempt other pods with lower priority.",
|
||||
Default: "PreemptLowerPriority",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Enum: []interface{}{"Never", "PreemptLowerPriority"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"schedulingPolicy"},
|
||||
},
|
||||
|
|
@ -54400,6 +54409,14 @@ func schema_k8sio_api_scheduling_v1alpha2_PodGroupTemplate(ref common.ReferenceC
|
|||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"preemptionPolicy": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is available only when the WorkloadAwarePreemption feature gate is enabled.\n\n\nPossible enum values:\n - `\"Never\"` means that pod never preempts other pods with lower priority.\n - `\"PreemptLowerPriority\"` means that pod can preempt other pods with lower priority.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Enum: []interface{}{"Never", "PreemptLowerPriority"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"name", "schedulingPolicy"},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -296,71 +296,71 @@ func TestSetDefaultsKubeletConfiguration(t *testing.T) {
|
|||
CacheUnauthorizedTTL: metav1.Duration{Duration: 30 * time.Second},
|
||||
},
|
||||
},
|
||||
RegistryPullQPS: ptr.To[int32](0),
|
||||
RegistryBurst: 10,
|
||||
EventRecordQPS: ptr.To[int32](0),
|
||||
EventBurst: 100,
|
||||
EnableDebuggingHandlers: ptr.To(false),
|
||||
HealthzPort: ptr.To[int32](0),
|
||||
HealthzBindAddress: "127.0.0.1",
|
||||
OOMScoreAdj: ptr.To[int32](0),
|
||||
ClusterDNS: []string{},
|
||||
StreamingConnectionIdleTimeout: metav1.Duration{Duration: 4 * time.Hour},
|
||||
NodeStatusUpdateFrequency: metav1.Duration{Duration: 10 * time.Second},
|
||||
NodeStatusReportFrequency: metav1.Duration{Duration: 5 * time.Minute},
|
||||
NodeLeaseDurationSeconds: 40,
|
||||
ContainerRuntimeEndpoint: "unix:///run/containerd/containerd.sock",
|
||||
ImageMinimumGCAge: metav1.Duration{Duration: 2 * time.Minute},
|
||||
ImageGCHighThresholdPercent: ptr.To[int32](0),
|
||||
ImageGCLowThresholdPercent: ptr.To[int32](0),
|
||||
ImagePullCredentialsVerificationPolicy: "NeverVerifyPreloadedImages",
|
||||
VolumeStatsAggPeriod: metav1.Duration{Duration: time.Minute},
|
||||
CgroupsPerQOS: ptr.To(false),
|
||||
CgroupDriver: "cgroupfs",
|
||||
CPUManagerPolicy: "none",
|
||||
CPUManagerPolicyOptions: map[string]string{},
|
||||
CPUManagerReconcilePeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||
MemoryManagerPolicy: v1beta1.NoneMemoryManagerPolicy,
|
||||
TopologyManagerPolicy: v1beta1.NoneTopologyManagerPolicy,
|
||||
TopologyManagerScope: v1beta1.ContainerTopologyManagerScope,
|
||||
QOSReserved: map[string]string{},
|
||||
RuntimeRequestTimeout: metav1.Duration{Duration: 2 * time.Minute},
|
||||
HairpinMode: v1beta1.PromiscuousBridge,
|
||||
MaxPods: 110,
|
||||
PodPidsLimit: ptr.To[int64](0),
|
||||
ResolverConfig: ptr.To(""),
|
||||
CPUCFSQuota: ptr.To(false),
|
||||
CPUCFSQuotaPeriod: &zeroDuration,
|
||||
NodeStatusMaxImages: ptr.To[int32](0),
|
||||
MaxOpenFiles: 1000000,
|
||||
ContentType: "application/vnd.kubernetes.protobuf",
|
||||
KubeAPIQPS: ptr.To[int32](0),
|
||||
KubeAPIBurst: 100,
|
||||
SerializeImagePulls: ptr.To(false),
|
||||
MaxParallelImagePulls: nil,
|
||||
EvictionHard: map[string]string{},
|
||||
EvictionSoft: map[string]string{},
|
||||
EvictionSoftGracePeriod: map[string]string{},
|
||||
EvictionPressureTransitionPeriod: metav1.Duration{Duration: 5 * time.Minute},
|
||||
EvictionMinimumReclaim: map[string]string{},
|
||||
MergeDefaultEvictionSettings: ptr.To(false),
|
||||
EnableControllerAttachDetach: ptr.To(false),
|
||||
MakeIPTablesUtilChains: ptr.To(false),
|
||||
IPTablesMasqueradeBit: ptr.To[int32](0),
|
||||
IPTablesDropBit: ptr.To[int32](0),
|
||||
FeatureGates: map[string]bool{},
|
||||
FailSwapOn: ptr.To(false),
|
||||
MemorySwap: v1beta1.MemorySwapConfiguration{SwapBehavior: ""},
|
||||
ContainerLogMaxSize: "10Mi",
|
||||
ContainerLogMaxFiles: ptr.To[int32](0),
|
||||
ContainerLogMaxWorkers: ptr.To[int32](1),
|
||||
ContainerLogMonitorInterval: &metav1.Duration{Duration: 10 * time.Second},
|
||||
RegistryPullQPS: ptr.To[int32](0),
|
||||
RegistryBurst: 10,
|
||||
EventRecordQPS: ptr.To[int32](0),
|
||||
EventBurst: 100,
|
||||
EnableDebuggingHandlers: ptr.To(false),
|
||||
HealthzPort: ptr.To[int32](0),
|
||||
HealthzBindAddress: "127.0.0.1",
|
||||
OOMScoreAdj: ptr.To[int32](0),
|
||||
ClusterDNS: []string{},
|
||||
StreamingConnectionIdleTimeout: metav1.Duration{Duration: 4 * time.Hour},
|
||||
NodeStatusUpdateFrequency: metav1.Duration{Duration: 10 * time.Second},
|
||||
NodeStatusReportFrequency: metav1.Duration{Duration: 5 * time.Minute},
|
||||
NodeLeaseDurationSeconds: 40,
|
||||
ContainerRuntimeEndpoint: "unix:///run/containerd/containerd.sock",
|
||||
ImageMinimumGCAge: metav1.Duration{Duration: 2 * time.Minute},
|
||||
ImageGCHighThresholdPercent: ptr.To[int32](0),
|
||||
ImageGCLowThresholdPercent: ptr.To[int32](0),
|
||||
ImagePullCredentialsVerificationPolicy: "NeverVerifyPreloadedImages",
|
||||
VolumeStatsAggPeriod: metav1.Duration{Duration: time.Minute},
|
||||
CgroupsPerQOS: ptr.To(false),
|
||||
CgroupDriver: "cgroupfs",
|
||||
CPUManagerPolicy: "none",
|
||||
CPUManagerPolicyOptions: map[string]string{},
|
||||
CPUManagerReconcilePeriod: metav1.Duration{Duration: 10 * time.Second},
|
||||
MemoryManagerPolicy: v1beta1.NoneMemoryManagerPolicy,
|
||||
TopologyManagerPolicy: v1beta1.NoneTopologyManagerPolicy,
|
||||
TopologyManagerScope: v1beta1.ContainerTopologyManagerScope,
|
||||
QOSReserved: map[string]string{},
|
||||
RuntimeRequestTimeout: metav1.Duration{Duration: 2 * time.Minute},
|
||||
HairpinMode: v1beta1.PromiscuousBridge,
|
||||
MaxPods: 110,
|
||||
PodPidsLimit: ptr.To[int64](0),
|
||||
ResolverConfig: ptr.To(""),
|
||||
CPUCFSQuota: ptr.To(false),
|
||||
CPUCFSQuotaPeriod: &zeroDuration,
|
||||
NodeStatusMaxImages: ptr.To[int32](0),
|
||||
MaxOpenFiles: 1000000,
|
||||
ContentType: "application/vnd.kubernetes.protobuf",
|
||||
KubeAPIQPS: ptr.To[int32](0),
|
||||
KubeAPIBurst: 100,
|
||||
SerializeImagePulls: ptr.To(false),
|
||||
MaxParallelImagePulls: nil,
|
||||
EvictionHard: map[string]string{},
|
||||
EvictionSoft: map[string]string{},
|
||||
EvictionSoftGracePeriod: map[string]string{},
|
||||
EvictionPressureTransitionPeriod: metav1.Duration{Duration: 5 * time.Minute},
|
||||
EvictionMinimumReclaim: map[string]string{},
|
||||
MergeDefaultEvictionSettings: ptr.To(false),
|
||||
EnableControllerAttachDetach: ptr.To(false),
|
||||
MakeIPTablesUtilChains: ptr.To(false),
|
||||
IPTablesMasqueradeBit: ptr.To[int32](0),
|
||||
IPTablesDropBit: ptr.To[int32](0),
|
||||
FeatureGates: map[string]bool{},
|
||||
FailSwapOn: ptr.To(false),
|
||||
MemorySwap: v1beta1.MemorySwapConfiguration{SwapBehavior: ""},
|
||||
ContainerLogMaxSize: "10Mi",
|
||||
ContainerLogMaxFiles: ptr.To[int32](0),
|
||||
ContainerLogMaxWorkers: ptr.To[int32](1),
|
||||
ContainerLogMonitorInterval: &metav1.Duration{Duration: 10 * time.Second},
|
||||
ConfigMapAndSecretChangeDetectionStrategy: v1beta1.WatchChangeDetectionStrategy,
|
||||
SystemReserved: map[string]string{},
|
||||
KubeReserved: map[string]string{},
|
||||
EnforceNodeAllocatable: []string{},
|
||||
AllowedUnsafeSysctls: []string{},
|
||||
VolumePluginDir: DefaultVolumePluginDir,
|
||||
SystemReserved: map[string]string{},
|
||||
KubeReserved: map[string]string{},
|
||||
EnforceNodeAllocatable: []string{},
|
||||
AllowedUnsafeSysctls: []string{},
|
||||
VolumePluginDir: DefaultVolumePluginDir,
|
||||
Logging: logsapi.LoggingConfiguration{
|
||||
Format: "text",
|
||||
FlushFrequency: logsapi.TimeOrMetaDuration{Duration: metav1.Duration{Duration: 5 * time.Second}, SerializeAsString: true},
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ func dropDisabledPodGroupSpecFields(podGroupSpec, oldPodGroupSpec *scheduling.Po
|
|||
dropDisabledDisruptionModeField(podGroupSpec, oldPodGroupSpec)
|
||||
dropDisabledPriorityClassNameField(podGroupSpec, oldPodGroupSpec)
|
||||
dropDisabledPriorityField(podGroupSpec, oldPodGroupSpec)
|
||||
dropDisabledPreemptionPolicyField(podGroupSpec, oldPodGroupSpec)
|
||||
}
|
||||
|
||||
func dropDisabledPodGroupStatusFields(newPodGroup, oldPodGroup *scheduling.PodGroup) {
|
||||
|
|
@ -244,6 +245,16 @@ func dropDisabledPriorityField(podGroupSpec, oldPodGroupSpec *scheduling.PodGrou
|
|||
podGroupSpec.Priority = nil
|
||||
}
|
||||
|
||||
// dropDisabledPreemptionPolicyField removes the PreemptionPolicy field unless it is
|
||||
// already used in the old PodGroup spec.
|
||||
func dropDisabledPreemptionPolicyField(podGroupSpec, oldPodGroupSpec *scheduling.PodGroupSpec) {
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.WorkloadAwarePreemption) || preemptionPolicyInUse(oldPodGroupSpec) {
|
||||
// No need to drop anything.
|
||||
return
|
||||
}
|
||||
podGroupSpec.PreemptionPolicy = nil
|
||||
}
|
||||
|
||||
func schedulingConstraintsInUse(podGroupSpec *scheduling.PodGroupSpec) bool {
|
||||
return podGroupSpec != nil && podGroupSpec.SchedulingConstraints != nil
|
||||
}
|
||||
|
|
@ -263,3 +274,7 @@ func priorityClassNameInUse(podGroupSpec *scheduling.PodGroupSpec) bool {
|
|||
func priorityInUse(podGroupSpec *scheduling.PodGroupSpec) bool {
|
||||
return podGroupSpec != nil && podGroupSpec.Priority != nil
|
||||
}
|
||||
|
||||
func preemptionPolicyInUse(podGroupSpec *scheduling.PodGroupSpec) bool {
|
||||
return podGroupSpec != nil && podGroupSpec.PreemptionPolicy != nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
"k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/scheduling"
|
||||
// Side-effect import: registers PodGroup with legacyscheme.Scheme so
|
||||
// the ConvertToVersion calls below resolve the type.
|
||||
|
|
@ -66,12 +67,27 @@ func podGroupWithSchedulingConstraints(keys ...string) *scheduling.PodGroup {
|
|||
return pg
|
||||
}
|
||||
|
||||
func podGroupWithDisruptionMode(mode scheduling.DisruptionMode) *scheduling.PodGroup {
|
||||
func basePodGroupWithWAP() *scheduling.PodGroup {
|
||||
pg := podGroup.DeepCopy()
|
||||
disruptionModePod := scheduling.DisruptionModePod
|
||||
preemptLowerPriority := core.PreemptLowerPriority
|
||||
pg.Spec.DisruptionMode = &disruptionModePod
|
||||
pg.Spec.PreemptionPolicy = &preemptLowerPriority
|
||||
return pg
|
||||
}
|
||||
|
||||
func podGroupWithDisruptionMode(mode scheduling.DisruptionMode) *scheduling.PodGroup {
|
||||
pg := basePodGroupWithWAP()
|
||||
pg.Spec.DisruptionMode = &mode
|
||||
return pg
|
||||
}
|
||||
|
||||
func podGroupWithPreemptionPolicy(policy core.PreemptionPolicy) *scheduling.PodGroup {
|
||||
pg := basePodGroupWithWAP()
|
||||
pg.Spec.PreemptionPolicy = &policy
|
||||
return pg
|
||||
}
|
||||
|
||||
var (
|
||||
fieldImmutableError = "field is immutable"
|
||||
minCountError = "must be greater than or equal to 1"
|
||||
|
|
@ -82,6 +98,7 @@ var (
|
|||
subdomainNameError = "lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters"
|
||||
forbiddenError = "Forbidden"
|
||||
supportedModesError = `supported values: "Pod", "PodGroup"`
|
||||
supportedPoliciesError = `supported values: "PreemptLowerPriority", "Never"`
|
||||
)
|
||||
|
||||
func TestStrategy(t *testing.T) {
|
||||
|
|
@ -258,6 +275,25 @@ func TestStrategyCreate(t *testing.T) {
|
|||
enableWorkloadAwarePreemption: true,
|
||||
expectValidationError: maximumError,
|
||||
},
|
||||
"workload aware preemption disabled - drop preemptionPolicy": {
|
||||
obj: podGroupWithPreemptionPolicy(core.PreemptNever),
|
||||
expectObj: podGroup,
|
||||
},
|
||||
"workload aware preemption enabled - preserve preemptionPolicy (Never)": {
|
||||
obj: podGroupWithPreemptionPolicy(core.PreemptNever),
|
||||
expectObj: podGroupWithPreemptionPolicy(core.PreemptNever),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"workload aware preemption enabled - preserve preemptionPolicy (PreemptLowerPriority)": {
|
||||
obj: podGroupWithPreemptionPolicy(core.PreemptLowerPriority),
|
||||
expectObj: podGroupWithPreemptionPolicy(core.PreemptLowerPriority),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"workload aware preemption enabled - invalid preemptionPolicy": {
|
||||
obj: podGroupWithPreemptionPolicy(core.PreemptionPolicy("Invalid")),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectValidationError: supportedPoliciesError,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
|
|
@ -448,6 +484,17 @@ func TestStrategyUpdate(t *testing.T) {
|
|||
enableWorkloadAwarePreemption: true,
|
||||
expectValidationError: fieldImmutableError,
|
||||
},
|
||||
"preemptionPolicy update, workload aware preemption disabled": {
|
||||
oldObj: podGroupWithPreemptionPolicy(core.PreemptNever),
|
||||
newObj: podGroupWithPreemptionPolicy(core.PreemptLowerPriority),
|
||||
expectValidationError: forbiddenError,
|
||||
},
|
||||
"preemptionPolicy update, workload aware preemption enabled": {
|
||||
oldObj: podGroupWithPreemptionPolicy(core.PreemptNever),
|
||||
newObj: podGroupWithPreemptionPolicy(core.PreemptLowerPriority),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectValidationError: fieldImmutableError,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ func dropDisabledPodGroupTemplatesFields(templates, oldTemplates []scheduling.Po
|
|||
dropDisabledDisruptionModeField(template, oldTemplate)
|
||||
dropDisabledPriorityClassNameField(template, oldTemplate)
|
||||
dropDisabledPriorityField(template, oldTemplate)
|
||||
dropDisabledPreemptionPolicyField(template, oldTemplate)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -181,6 +182,16 @@ func dropDisabledPriorityField(template, oldTemplate *scheduling.PodGroupTemplat
|
|||
template.Priority = nil
|
||||
}
|
||||
|
||||
// dropDisabledPreemptionPolicyField removes the PreemptionPolicy field from a template unless it is
|
||||
// already used in the old template.
|
||||
func dropDisabledPreemptionPolicyField(template, oldTemplate *scheduling.PodGroupTemplate) {
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.WorkloadAwarePreemption) || preemptionPolicyInUse(oldTemplate) {
|
||||
// No need to drop anything.
|
||||
return
|
||||
}
|
||||
template.PreemptionPolicy = nil
|
||||
}
|
||||
|
||||
func schedulingConstraintsInUse(pgt *scheduling.PodGroupTemplate) bool {
|
||||
return pgt != nil && pgt.SchedulingConstraints != nil
|
||||
}
|
||||
|
|
@ -200,3 +211,7 @@ func priorityClassNameInUse(pgt *scheduling.PodGroupTemplate) bool {
|
|||
func priorityInUse(pgt *scheduling.PodGroupTemplate) bool {
|
||||
return pgt != nil && pgt.Priority != nil
|
||||
}
|
||||
|
||||
func preemptionPolicyInUse(pgt *scheduling.PodGroupTemplate) bool {
|
||||
return pgt != nil && pgt.PreemptionPolicy != nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
"k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/scheduling"
|
||||
// Side-effect import: registers Workload with legacyscheme.Scheme so
|
||||
// the ConvertToVersion calls below resolve the type.
|
||||
|
|
@ -57,13 +58,16 @@ var (
|
|||
podDisruptionMode = scheduling.DisruptionModePod
|
||||
podGroupDisruptionMode = scheduling.DisruptionModePodGroup
|
||||
invalidDisruptionMode = scheduling.DisruptionMode("Invalid")
|
||||
preemptNever = core.PreemptNever
|
||||
preemptLowerPriority = core.PreemptLowerPriority
|
||||
|
||||
fieldImmutableError = "field is immutable"
|
||||
minCountError = "must be greater than or equal to 1"
|
||||
tooManyItemsError = "must have at most 1 item"
|
||||
requiredError = "Required value"
|
||||
subdomainNameError = "lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters"
|
||||
supportedModesError = `supported values: "Pod", "PodGroup"`
|
||||
fieldImmutableError = "field is immutable"
|
||||
minCountError = "must be greater than or equal to 1"
|
||||
tooManyItemsError = "must have at most 1 item"
|
||||
requiredError = "Required value"
|
||||
subdomainNameError = "lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters"
|
||||
supportedModesError = `supported values: "Pod", "PodGroup"`
|
||||
supportedPoliciesError = `supported values: "PreemptLowerPriority", "Never"`
|
||||
)
|
||||
|
||||
func TestWorkloadStrategy(t *testing.T) {
|
||||
|
|
@ -233,6 +237,50 @@ func TestStrategyCreate(t *testing.T) {
|
|||
enableWorkloadAwarePreemption: true,
|
||||
expectValidationError: subdomainNameError,
|
||||
},
|
||||
"workload aware preemption disabled - drop preemptionPolicy": {
|
||||
obj: func() *scheduling.Workload {
|
||||
w := workload.DeepCopy()
|
||||
w.Spec.PodGroupTemplates[0].PreemptionPolicy = &preemptNever
|
||||
return w
|
||||
}(),
|
||||
expectObj: workload,
|
||||
},
|
||||
"workload aware preemption enabled - preserve preemptionPolicy (Never)": {
|
||||
obj: func() *scheduling.Workload {
|
||||
w := workload.DeepCopy()
|
||||
w.Spec.PodGroupTemplates[0].PreemptionPolicy = &preemptNever
|
||||
return w
|
||||
}(),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectObj: func() *scheduling.Workload {
|
||||
w := workload.DeepCopy()
|
||||
w.Spec.PodGroupTemplates[0].PreemptionPolicy = &preemptNever
|
||||
return w
|
||||
}(),
|
||||
},
|
||||
"workload aware preemption enabled - preserve preemptionPolicy (PreemptLowerPriority)": {
|
||||
obj: func() *scheduling.Workload {
|
||||
w := workload.DeepCopy()
|
||||
w.Spec.PodGroupTemplates[0].PreemptionPolicy = &preemptLowerPriority
|
||||
return w
|
||||
}(),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectObj: func() *scheduling.Workload {
|
||||
w := workload.DeepCopy()
|
||||
w.Spec.PodGroupTemplates[0].PreemptionPolicy = &preemptLowerPriority
|
||||
return w
|
||||
}(),
|
||||
},
|
||||
"workload aware preemption enabled - invalid preemptionPolicy": {
|
||||
obj: func() *scheduling.Workload {
|
||||
w := workload.DeepCopy()
|
||||
invalidPolicy := core.PreemptionPolicy("Invalid")
|
||||
w.Spec.PodGroupTemplates[0].PreemptionPolicy = &invalidPolicy
|
||||
return w
|
||||
}(),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectValidationError: supportedPoliciesError,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
|
|
@ -530,6 +578,33 @@ func TestStrategyUpdate(t *testing.T) {
|
|||
enableWorkloadAwarePreemption: true,
|
||||
expectValidationError: fieldImmutableError,
|
||||
},
|
||||
"preemptionPolicy update, workload aware preemption disabled": {
|
||||
oldObj: func() *scheduling.Workload {
|
||||
w := workload.DeepCopy()
|
||||
w.Spec.PodGroupTemplates[0].PreemptionPolicy = &preemptNever
|
||||
return w
|
||||
}(),
|
||||
newObj: func() *scheduling.Workload {
|
||||
w := workload.DeepCopy()
|
||||
w.Spec.PodGroupTemplates[0].PreemptionPolicy = &preemptLowerPriority
|
||||
return w
|
||||
}(),
|
||||
expectValidationError: fieldImmutableError,
|
||||
},
|
||||
"preemptionPolicy update, workload aware preemption enabled": {
|
||||
oldObj: func() *scheduling.Workload {
|
||||
w := workload.DeepCopy()
|
||||
w.Spec.PodGroupTemplates[0].PreemptionPolicy = &preemptNever
|
||||
return w
|
||||
}(),
|
||||
newObj: func() *scheduling.Workload {
|
||||
w := workload.DeepCopy()
|
||||
w.Spec.PodGroupTemplates[0].PreemptionPolicy = &preemptLowerPriority
|
||||
return w
|
||||
}(),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectValidationError: fieldImmutableError,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
|
|
|
|||
|
|
@ -232,12 +232,12 @@ func NewFit(_ context.Context, plArgs runtime.Object, h fwk.Handle, fts feature.
|
|||
}
|
||||
|
||||
pl := &Fit{
|
||||
ignoredResources: sets.New(args.IgnoredResources...),
|
||||
ignoredResourceGroups: sets.New(args.IgnoredResourceGroups...),
|
||||
enableInPlacePodVerticalScaling: fts.EnableInPlacePodVerticalScaling,
|
||||
handle: h,
|
||||
enablePodLevelResources: fts.EnablePodLevelResources,
|
||||
enableDRAExtendedResource: fts.EnableDRAExtendedResource,
|
||||
ignoredResources: sets.New(args.IgnoredResources...),
|
||||
ignoredResourceGroups: sets.New(args.IgnoredResourceGroups...),
|
||||
enableInPlacePodVerticalScaling: fts.EnableInPlacePodVerticalScaling,
|
||||
handle: h,
|
||||
enablePodLevelResources: fts.EnablePodLevelResources,
|
||||
enableDRAExtendedResource: fts.EnableDRAExtendedResource,
|
||||
enableInPlacePodLevelResourcesVerticalScaling: fts.EnableInPlacePodLevelResourcesVerticalScaling,
|
||||
resourceAllocationScorer: scorer,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ func TestPodGroupEvaluator_SelectVictimsOnDomain(t *testing.T) {
|
|||
expectedStatus: fwk.NewStatus(fwk.Success),
|
||||
},
|
||||
{
|
||||
name: "PodGroup with PreemptNever does not perform preemption",
|
||||
name: "PodGroup with PreemptNever in a single pod is ignored and performs preemption",
|
||||
nodeNames: []string{"node1", "node2", "node3"},
|
||||
initPods: []*v1.Pod{
|
||||
st.MakePod().Name("p1").UID("v1").Node("node1").Priority(lowPriority).Obj(),
|
||||
|
|
@ -216,6 +216,28 @@ func TestPodGroupEvaluator_SelectVictimsOnDomain(t *testing.T) {
|
|||
st.MakePodGroup().Name("preemptor-pg").Priority(highPriority).Obj(),
|
||||
[]*v1.Pod{
|
||||
st.MakePod().Name("p-1").UID("p-1").Priority(highPriority).PreemptionPolicy(v1.PreemptNever).Obj(),
|
||||
},
|
||||
),
|
||||
blockingRules: []blockingRule{
|
||||
{nodeName: "node1", capacity: 1, blockingVictims: sets.New("p1")},
|
||||
{nodeName: "node2", capacity: 1, blockingVictims: sets.New("p2")},
|
||||
{nodeName: "node3", capacity: 1, blockingVictims: sets.New("p3")},
|
||||
},
|
||||
expectedPods: []string{"p1"},
|
||||
expectedStatus: fwk.NewStatus(fwk.Success),
|
||||
},
|
||||
{
|
||||
name: "PodGroup with PreemptNever does not perform preemption",
|
||||
nodeNames: []string{"node1", "node2", "node3"},
|
||||
initPods: []*v1.Pod{
|
||||
st.MakePod().Name("p1").UID("v1").Node("node1").Priority(lowPriority).Obj(),
|
||||
st.MakePod().Name("p2").UID("v2").Node("node2").Priority(lowPriority).PodGroupName("pg1").Obj(),
|
||||
st.MakePod().Name("p3").UID("v3").Node("node3").Priority(lowPriority).PodGroupName("pg2").Obj(),
|
||||
},
|
||||
preemptor: newPodGroupPreemptor(
|
||||
st.MakePodGroup().Name("preemptor-pg").Priority(highPriority).PreemptionPolicy(v1.PreemptNever).Obj(),
|
||||
[]*v1.Pod{
|
||||
st.MakePod().Name("p-1").UID("p-1").Priority(highPriority).Obj(),
|
||||
st.MakePod().Name("p-2").UID("p-2").Priority(highPriority).Obj(),
|
||||
},
|
||||
),
|
||||
|
|
@ -225,7 +247,47 @@ func TestPodGroupEvaluator_SelectVictimsOnDomain(t *testing.T) {
|
|||
{nodeName: "node3", capacity: 1, blockingVictims: sets.New("p3")},
|
||||
},
|
||||
expectedPods: []string{},
|
||||
expectedStatus: fwk.NewStatus(fwk.Unschedulable),
|
||||
expectedStatus: fwk.NewStatus(fwk.Unschedulable, "not eligible due to preemptionPolicy=Never."),
|
||||
},
|
||||
{
|
||||
name: "PodGroup with default preemption policy performs preemption",
|
||||
nodeNames: []string{"node1", "node2", "node3"},
|
||||
initPods: []*v1.Pod{
|
||||
st.MakePod().Name("p1").UID("v1").Node("node1").Priority(lowPriority).Obj(),
|
||||
st.MakePod().Name("p2").UID("v2").Node("node2").Priority(lowPriority).PodGroupName("pg1").Obj(),
|
||||
st.MakePod().Name("p3").UID("v3").Node("node3").Priority(lowPriority).PodGroupName("pg2").Obj(),
|
||||
},
|
||||
preemptor: newPodGroupPreemptor(
|
||||
st.MakePodGroup().Name("preemptor-pg").Priority(highPriority).Obj(), // PreemptionPolicy is nil (default)
|
||||
[]*v1.Pod{st.MakePod().Name("p-1").UID("p-1").Priority(highPriority).Obj()},
|
||||
),
|
||||
blockingRules: []blockingRule{
|
||||
{nodeName: "node1", capacity: 1, blockingVictims: sets.New("p1")},
|
||||
{nodeName: "node2", capacity: 1, blockingVictims: sets.New("p2")},
|
||||
{nodeName: "node3", capacity: 1, blockingVictims: sets.New("p3")},
|
||||
},
|
||||
expectedPods: []string{"p1"},
|
||||
expectedStatus: fwk.NewStatus(fwk.Success),
|
||||
},
|
||||
{
|
||||
name: "PodGroup with PreemptLowerPriority performs preemption",
|
||||
nodeNames: []string{"node1", "node2", "node3"},
|
||||
initPods: []*v1.Pod{
|
||||
st.MakePod().Name("p1").UID("v1").Node("node1").Priority(lowPriority).Obj(),
|
||||
st.MakePod().Name("p2").UID("v2").Node("node2").Priority(lowPriority).PodGroupName("pg1").Obj(),
|
||||
st.MakePod().Name("p3").UID("v3").Node("node3").Priority(lowPriority).PodGroupName("pg2").Obj(),
|
||||
},
|
||||
preemptor: newPodGroupPreemptor(
|
||||
st.MakePodGroup().Name("preemptor-pg").Priority(highPriority).PreemptionPolicy(v1.PreemptLowerPriority).Obj(),
|
||||
[]*v1.Pod{st.MakePod().Name("p-1").UID("p-1").Priority(highPriority).Obj()},
|
||||
),
|
||||
blockingRules: []blockingRule{
|
||||
{nodeName: "node1", capacity: 1, blockingVictims: sets.New("p1")},
|
||||
{nodeName: "node2", capacity: 1, blockingVictims: sets.New("p2")},
|
||||
{nodeName: "node3", capacity: 1, blockingVictims: sets.New("p3")},
|
||||
},
|
||||
expectedPods: []string{"p1"},
|
||||
expectedStatus: fwk.NewStatus(fwk.Success),
|
||||
},
|
||||
{
|
||||
name: "Preemptor group is not eligible if any member has nominated node with terminating pods",
|
||||
|
|
@ -432,7 +494,7 @@ func TestPodGroupEvaluator_SelectVictimsOnDomain(t *testing.T) {
|
|||
expectedStatus: fwk.NewStatus(fwk.Success),
|
||||
},
|
||||
{
|
||||
name: "PodGroup with PreemptNever does not perform preemption",
|
||||
name: "PodGroup with PreemptNever in a single pod is ignored and performs preemption with PodGroup victims",
|
||||
nodeNames: []string{"node1", "node2", "node3"},
|
||||
initPods: []*v1.Pod{
|
||||
st.MakePod().Name("p1").UID("v1").Node("node1").Priority(lowPriority).Obj(),
|
||||
|
|
@ -447,6 +509,32 @@ func TestPodGroupEvaluator_SelectVictimsOnDomain(t *testing.T) {
|
|||
st.MakePodGroup().Name("preemptor-pg").Priority(highPriority).Obj(),
|
||||
[]*v1.Pod{
|
||||
st.MakePod().Name("p-1").UID("p-1").Priority(highPriority).PreemptionPolicy(v1.PreemptNever).Obj(),
|
||||
},
|
||||
),
|
||||
blockingRules: []blockingRule{
|
||||
{nodeName: "node1", capacity: 1, blockingVictims: sets.New("p1")},
|
||||
{nodeName: "node2", capacity: 1, blockingVictims: sets.New("p2")},
|
||||
{nodeName: "node3", capacity: 1, blockingVictims: sets.New("p3")},
|
||||
},
|
||||
expectedPods: []string{"p1"},
|
||||
expectedStatus: fwk.NewStatus(fwk.Success),
|
||||
},
|
||||
{
|
||||
name: "PodGroup with PreemptNever does not perform preemption",
|
||||
nodeNames: []string{"node1", "node2", "node3"},
|
||||
initPods: []*v1.Pod{
|
||||
st.MakePod().Name("p1").UID("v1").Node("node1").Priority(lowPriority).Obj(),
|
||||
st.MakePod().Name("p2").UID("v2").Node("node2").Priority(lowPriority).PodGroupName("pg1").Obj(),
|
||||
st.MakePod().Name("p3").UID("v3").Node("node3").Priority(lowPriority).PodGroupName("pg2").Obj(),
|
||||
},
|
||||
initPodGroups: []*schedulingapi.PodGroup{
|
||||
st.MakePodGroup().Name("pg1").UID("pg1").DisruptionMode(schedulingapi.DisruptionModePod).Priority(lowPriority).Obj(),
|
||||
st.MakePodGroup().Name("pg2").UID("pg2").DisruptionMode(schedulingapi.DisruptionModePod).Priority(lowPriority).Obj(),
|
||||
},
|
||||
preemptor: newPodGroupPreemptor(
|
||||
st.MakePodGroup().Name("preemptor-pg").Priority(highPriority).PreemptionPolicy(v1.PreemptNever).Obj(),
|
||||
[]*v1.Pod{
|
||||
st.MakePod().Name("p-1").UID("p-1").Priority(highPriority).Obj(),
|
||||
st.MakePod().Name("p-2").UID("p-2").Priority(highPriority).Obj(),
|
||||
},
|
||||
),
|
||||
|
|
@ -456,7 +544,7 @@ func TestPodGroupEvaluator_SelectVictimsOnDomain(t *testing.T) {
|
|||
{nodeName: "node3", capacity: 1, blockingVictims: sets.New("p3")},
|
||||
},
|
||||
expectedPods: []string{},
|
||||
expectedStatus: fwk.NewStatus(fwk.Unschedulable),
|
||||
expectedStatus: fwk.NewStatus(fwk.Unschedulable, "not eligible due to preemptionPolicy=Never."),
|
||||
},
|
||||
{
|
||||
name: "PDB: Prefer lower priority pod for preemption, when preemption without pdb violation is not possible",
|
||||
|
|
|
|||
|
|
@ -42,10 +42,8 @@ type podGroupPreemptor struct {
|
|||
|
||||
func newPodGroupPreemptor(pg *schedulingapi.PodGroup, pods []*v1.Pod) *podGroupPreemptor {
|
||||
preemptionPolicy := v1.PreemptLowerPriority
|
||||
for _, pod := range pods {
|
||||
if p := pod.Spec.PreemptionPolicy; p != nil && *p == v1.PreemptNever {
|
||||
preemptionPolicy = *p
|
||||
}
|
||||
if pg != nil && pg.Spec.PreemptionPolicy != nil {
|
||||
preemptionPolicy = *pg.Spec.PreemptionPolicy
|
||||
}
|
||||
return &podGroupPreemptor{
|
||||
priority: util.PodGroupPriority(pg),
|
||||
|
|
|
|||
|
|
@ -1666,6 +1666,12 @@ func (wrapper *PodGroupWrapper) Priority(priority int32) *PodGroupWrapper {
|
|||
return wrapper
|
||||
}
|
||||
|
||||
// PreemptionPolicy sets the preemption policy of the inner PodGroup.
|
||||
func (wrapper *PodGroupWrapper) PreemptionPolicy(policy v1.PreemptionPolicy) *PodGroupWrapper {
|
||||
wrapper.PodGroup.Spec.PreemptionPolicy = &policy
|
||||
return wrapper
|
||||
}
|
||||
|
||||
// WorkloadWrapper wraps a Workload inside.
|
||||
type WorkloadWrapper struct{ schedulingapi.Workload }
|
||||
|
||||
|
|
@ -1730,3 +1736,9 @@ func (wrapper *PodGroupTemplateWrapper) BasicPolicy() *PodGroupTemplateWrapper {
|
|||
wrapper.SchedulingPolicy.Basic = &schedulingapi.BasicSchedulingPolicy{}
|
||||
return wrapper
|
||||
}
|
||||
|
||||
// PreemptionPolicy sets the preemption policy of the inner PodGroupTemplate.
|
||||
func (wrapper *PodGroupTemplateWrapper) PreemptionPolicy(policy v1.PreemptionPolicy) *PodGroupTemplateWrapper {
|
||||
wrapper.PodGroupTemplate.PreemptionPolicy = &policy
|
||||
return wrapper
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
|
||||
io "io"
|
||||
|
||||
k8s_io_api_core_v1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
math_bits "math/bits"
|
||||
|
|
@ -397,6 +398,13 @@ func (m *PodGroupSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.PreemptionPolicy != nil {
|
||||
i -= len(*m.PreemptionPolicy)
|
||||
copy(dAtA[i:], *m.PreemptionPolicy)
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(len(*m.PreemptionPolicy)))
|
||||
i--
|
||||
dAtA[i] = 0x42
|
||||
}
|
||||
if m.Priority != nil {
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(*m.Priority))
|
||||
i--
|
||||
|
|
@ -536,6 +544,13 @@ func (m *PodGroupTemplate) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.PreemptionPolicy != nil {
|
||||
i -= len(*m.PreemptionPolicy)
|
||||
copy(dAtA[i:], *m.PreemptionPolicy)
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(len(*m.PreemptionPolicy)))
|
||||
i--
|
||||
dAtA[i] = 0x42
|
||||
}
|
||||
if m.Priority != nil {
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(*m.Priority))
|
||||
i--
|
||||
|
|
@ -1029,6 +1044,10 @@ func (m *PodGroupSpec) Size() (n int) {
|
|||
if m.Priority != nil {
|
||||
n += 1 + sovGenerated(uint64(*m.Priority))
|
||||
}
|
||||
if m.PreemptionPolicy != nil {
|
||||
l = len(*m.PreemptionPolicy)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
|
|
@ -1082,6 +1101,10 @@ func (m *PodGroupTemplate) Size() (n int) {
|
|||
if m.Priority != nil {
|
||||
n += 1 + sovGenerated(uint64(*m.Priority))
|
||||
}
|
||||
if m.PreemptionPolicy != nil {
|
||||
l = len(*m.PreemptionPolicy)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
|
|
@ -1305,6 +1328,7 @@ func (this *PodGroupSpec) String() string {
|
|||
`DisruptionMode:` + valueToStringGenerated(this.DisruptionMode) + `,`,
|
||||
`PriorityClassName:` + fmt.Sprintf("%v", this.PriorityClassName) + `,`,
|
||||
`Priority:` + valueToStringGenerated(this.Priority) + `,`,
|
||||
`PreemptionPolicy:` + valueToStringGenerated(this.PreemptionPolicy) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
|
|
@ -1347,6 +1371,7 @@ func (this *PodGroupTemplate) String() string {
|
|||
`DisruptionMode:` + valueToStringGenerated(this.DisruptionMode) + `,`,
|
||||
`PriorityClassName:` + fmt.Sprintf("%v", this.PriorityClassName) + `,`,
|
||||
`Priority:` + valueToStringGenerated(this.Priority) + `,`,
|
||||
`PreemptionPolicy:` + valueToStringGenerated(this.PreemptionPolicy) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
|
|
@ -2552,6 +2577,39 @@ func (m *PodGroupSpec) Unmarshal(dAtA []byte) error {
|
|||
}
|
||||
}
|
||||
m.Priority = &v
|
||||
case 8:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field PreemptionPolicy", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
s := k8s_io_api_core_v1.PreemptionPolicy(dAtA[iNdEx:postIndex])
|
||||
m.PreemptionPolicy = &s
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(dAtA[iNdEx:])
|
||||
|
|
@ -2940,6 +2998,39 @@ func (m *PodGroupTemplate) Unmarshal(dAtA []byte) error {
|
|||
}
|
||||
}
|
||||
m.Priority = &v
|
||||
case 8:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field PreemptionPolicy", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
s := k8s_io_api_core_v1.PreemptionPolicy(dAtA[iNdEx:postIndex])
|
||||
m.PreemptionPolicy = &s
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(dAtA[iNdEx:])
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ syntax = "proto2";
|
|||
|
||||
package k8s.io.api.scheduling.v1alpha2;
|
||||
|
||||
import "k8s.io/api/core/v1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
|
||||
|
|
@ -289,6 +290,21 @@ message PodGroupSpec {
|
|||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:immutable
|
||||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:maximum=1000000000 # HighestUserDefinablePriority
|
||||
optional int32 priority = 7;
|
||||
|
||||
// PreemptionPolicy is the Policy for preempting pods with lower priority.
|
||||
// One of Never, PreemptLowerPriority.
|
||||
// Defaults to PreemptLowerPriority if unset.
|
||||
// This field is immutable.
|
||||
// This field is available only when the WorkloadAwarePreemption feature gate
|
||||
// is enabled.
|
||||
//
|
||||
// +featureGate=WorkloadAwarePreemption
|
||||
// +optional
|
||||
// +k8s:ifDisabled("WorkloadAwarePreemption")=+k8s:forbidden
|
||||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:optional
|
||||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:immutable
|
||||
// +default="PreemptLowerPriority"
|
||||
optional string preemptionPolicy = 8;
|
||||
}
|
||||
|
||||
// PodGroupStatus represents information about the status of a pod group.
|
||||
|
|
@ -417,6 +433,18 @@ message PodGroupTemplate {
|
|||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:optional
|
||||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:maximum=1000000000 # HighestUserDefinablePriority
|
||||
optional int32 priority = 7;
|
||||
|
||||
// PreemptionPolicy is the Policy for preempting pods with lower priority.
|
||||
// One of Never, PreemptLowerPriority.
|
||||
// Defaults to PreemptLowerPriority if unset.
|
||||
// This field is available only when the WorkloadAwarePreemption feature gate
|
||||
// is enabled.
|
||||
//
|
||||
// +featureGate=WorkloadAwarePreemption
|
||||
// +optional
|
||||
// +k8s:ifDisabled("WorkloadAwarePreemption")=+k8s:forbidden
|
||||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:optional
|
||||
optional string preemptionPolicy = 8;
|
||||
}
|
||||
|
||||
// PodGroupTemplateReference references a PodGroup template defined in some object (e.g. Workload).
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
package v1alpha2
|
||||
|
||||
import (
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
|
|
@ -201,6 +202,18 @@ type PodGroupTemplate struct {
|
|||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:optional
|
||||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:maximum=1000000000 # HighestUserDefinablePriority
|
||||
Priority *int32 `json:"priority,omitempty" protobuf:"varint,7,opt,name=priority"`
|
||||
|
||||
// PreemptionPolicy is the Policy for preempting pods with lower priority.
|
||||
// One of Never, PreemptLowerPriority.
|
||||
// Defaults to PreemptLowerPriority if unset.
|
||||
// This field is available only when the WorkloadAwarePreemption feature gate
|
||||
// is enabled.
|
||||
//
|
||||
// +featureGate=WorkloadAwarePreemption
|
||||
// +optional
|
||||
// +k8s:ifDisabled("WorkloadAwarePreemption")=+k8s:forbidden
|
||||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:optional
|
||||
PreemptionPolicy *apiv1.PreemptionPolicy `json:"preemptionPolicy,omitempty" protobuf:"bytes,8,opt,name=preemptionPolicy"`
|
||||
}
|
||||
|
||||
// PodGroupSchedulingPolicy defines the scheduling configuration for a PodGroup.
|
||||
|
|
@ -455,6 +468,21 @@ type PodGroupSpec struct {
|
|||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:immutable
|
||||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:maximum=1000000000 # HighestUserDefinablePriority
|
||||
Priority *int32 `json:"priority,omitempty" protobuf:"varint,7,opt,name=priority"`
|
||||
|
||||
// PreemptionPolicy is the Policy for preempting pods with lower priority.
|
||||
// One of Never, PreemptLowerPriority.
|
||||
// Defaults to PreemptLowerPriority if unset.
|
||||
// This field is immutable.
|
||||
// This field is available only when the WorkloadAwarePreemption feature gate
|
||||
// is enabled.
|
||||
//
|
||||
// +featureGate=WorkloadAwarePreemption
|
||||
// +optional
|
||||
// +k8s:ifDisabled("WorkloadAwarePreemption")=+k8s:forbidden
|
||||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:optional
|
||||
// +k8s:ifEnabled("WorkloadAwarePreemption")=+k8s:immutable
|
||||
// +default="PreemptLowerPriority"
|
||||
PreemptionPolicy *apiv1.PreemptionPolicy `json:"preemptionPolicy,omitempty" protobuf:"bytes,8,opt,name=preemptionPolicy"`
|
||||
}
|
||||
|
||||
// PodGroupStatus represents information about the status of a pod group.
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ var map_PodGroupSpec = map[string]string{
|
|||
"disruptionMode": "DisruptionMode defines the mode in which a given PodGroup can be disrupted. Controllers are expected to fill this field by copying it from a PodGroupTemplate. One of Pod, PodGroup. Defaults to Pod if unset. This field is immutable. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"priorityClassName": "PriorityClassName defines the priority that should be considered when scheduling this pod group. Controllers are expected to fill this field by copying it from a PodGroupTemplate. Otherwise, it is validated and resolved similarly to the PriorityClassName on PodGroupTemplate (i.e. if no priority class is specified, admission control can set this to the global default priority class if it exists. Otherwise, the pod group's priority will be zero). This field is immutable. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"priority": "Priority is the value of priority of this pod group. Various system components use this field to find the priority of the pod group. 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. This field is immutable. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"preemptionPolicy": "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is immutable. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
}
|
||||
|
||||
func (PodGroupSpec) SwaggerDoc() map[string]string {
|
||||
|
|
@ -139,6 +140,7 @@ var map_PodGroupTemplate = map[string]string{
|
|||
"disruptionMode": "DisruptionMode defines the mode in which a given PodGroup can be disrupted. One of Pod, PodGroup. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"priorityClassName": "PriorityClassName indicates the priority that should be considered when scheduling a pod group created from this template. If no priority class is specified, admission control can set this to the global default priority class if it exists. Otherwise, pod groups created from this template will have the priority set to zero. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"priority": "Priority is the value of priority of pod groups created from this template. Various system components use this field to find the priority of the pod group. 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. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
"preemptionPolicy": "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. This field is available only when the WorkloadAwarePreemption feature gate is enabled.",
|
||||
}
|
||||
|
||||
func (PodGroupTemplate) SwaggerDoc() map[string]string {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ limitations under the License.
|
|||
package v1alpha2
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
|
|
@ -244,6 +245,11 @@ func (in *PodGroupSpec) DeepCopyInto(out *PodGroupSpec) {
|
|||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
if in.PreemptionPolicy != nil {
|
||||
in, out := &in.PreemptionPolicy, &out.PreemptionPolicy
|
||||
*out = new(v1.PreemptionPolicy)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -262,7 +268,7 @@ func (in *PodGroupStatus) DeepCopyInto(out *PodGroupStatus) {
|
|||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
*out = make([]metav1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
|
|
@ -313,6 +319,11 @@ func (in *PodGroupTemplate) DeepCopyInto(out *PodGroupTemplate) {
|
|||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
if in.PreemptionPolicy != nil {
|
||||
in, out := &in.PreemptionPolicy, &out.PreemptionPolicy
|
||||
*out = new(v1.PreemptionPolicy)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,8 @@
|
|||
],
|
||||
"disruptionMode": "disruptionModeValue",
|
||||
"priorityClassName": "priorityClassNameValue",
|
||||
"priority": 7
|
||||
"priority": 7,
|
||||
"preemptionPolicy": "preemptionPolicyValue"
|
||||
},
|
||||
"status": {
|
||||
"conditions": [
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -38,6 +38,7 @@ spec:
|
|||
workload:
|
||||
podGroupTemplateName: podGroupTemplateNameValue
|
||||
workloadName: workloadNameValue
|
||||
preemptionPolicy: preemptionPolicyValue
|
||||
priority: 7
|
||||
priorityClassName: priorityClassNameValue
|
||||
resourceClaims:
|
||||
|
|
|
|||
|
|
@ -74,7 +74,8 @@
|
|||
],
|
||||
"disruptionMode": "disruptionModeValue",
|
||||
"priorityClassName": "priorityClassNameValue",
|
||||
"priority": 7
|
||||
"priority": 7,
|
||||
"preemptionPolicy": "preemptionPolicyValue"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -40,6 +40,7 @@ spec:
|
|||
podGroupTemplates:
|
||||
- disruptionMode: disruptionModeValue
|
||||
name: nameValue
|
||||
preemptionPolicy: preemptionPolicyValue
|
||||
priority: 7
|
||||
priorityClassName: priorityClassNameValue
|
||||
resourceClaims:
|
||||
|
|
|
|||
|
|
@ -14808,6 +14808,10 @@ var schemaYAML = typed.YAMLObject(`types:
|
|||
- name: podGroupTemplateRef
|
||||
type:
|
||||
namedType: io.k8s.api.scheduling.v1alpha2.PodGroupTemplateReference
|
||||
- name: preemptionPolicy
|
||||
type:
|
||||
scalar: string
|
||||
default: PreemptLowerPriority
|
||||
- name: priority
|
||||
type:
|
||||
scalar: numeric
|
||||
|
|
@ -14858,6 +14862,9 @@ var schemaYAML = typed.YAMLObject(`types:
|
|||
type:
|
||||
scalar: string
|
||||
default: ""
|
||||
- name: preemptionPolicy
|
||||
type:
|
||||
scalar: string
|
||||
- name: priority
|
||||
type:
|
||||
scalar: numeric
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ limitations under the License.
|
|||
package v1alpha2
|
||||
|
||||
import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
schedulingv1alpha2 "k8s.io/api/scheduling/v1alpha2"
|
||||
)
|
||||
|
||||
|
|
@ -75,6 +76,13 @@ type PodGroupSpecApplyConfiguration struct {
|
|||
// This field is available only when the WorkloadAwarePreemption feature gate
|
||||
// is enabled.
|
||||
Priority *int32 `json:"priority,omitempty"`
|
||||
// PreemptionPolicy is the Policy for preempting pods with lower priority.
|
||||
// One of Never, PreemptLowerPriority.
|
||||
// Defaults to PreemptLowerPriority if unset.
|
||||
// This field is immutable.
|
||||
// This field is available only when the WorkloadAwarePreemption feature gate
|
||||
// is enabled.
|
||||
PreemptionPolicy *v1.PreemptionPolicy `json:"preemptionPolicy,omitempty"`
|
||||
}
|
||||
|
||||
// PodGroupSpecApplyConfiguration constructs a declarative configuration of the PodGroupSpec type for use with
|
||||
|
|
@ -143,3 +151,11 @@ func (b *PodGroupSpecApplyConfiguration) WithPriority(value int32) *PodGroupSpec
|
|||
b.Priority = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithPreemptionPolicy sets the PreemptionPolicy field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the PreemptionPolicy field is set to the value of the last call.
|
||||
func (b *PodGroupSpecApplyConfiguration) WithPreemptionPolicy(value v1.PreemptionPolicy) *PodGroupSpecApplyConfiguration {
|
||||
b.PreemptionPolicy = &value
|
||||
return b
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ limitations under the License.
|
|||
package v1alpha2
|
||||
|
||||
import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
schedulingv1alpha2 "k8s.io/api/scheduling/v1alpha2"
|
||||
)
|
||||
|
||||
|
|
@ -66,6 +67,12 @@ type PodGroupTemplateApplyConfiguration struct {
|
|||
// This field is available only when the WorkloadAwarePreemption feature gate
|
||||
// is enabled.
|
||||
Priority *int32 `json:"priority,omitempty"`
|
||||
// PreemptionPolicy is the Policy for preempting pods with lower priority.
|
||||
// One of Never, PreemptLowerPriority.
|
||||
// Defaults to PreemptLowerPriority if unset.
|
||||
// This field is available only when the WorkloadAwarePreemption feature gate
|
||||
// is enabled.
|
||||
PreemptionPolicy *v1.PreemptionPolicy `json:"preemptionPolicy,omitempty"`
|
||||
}
|
||||
|
||||
// PodGroupTemplateApplyConfiguration constructs a declarative configuration of the PodGroupTemplate type for use with
|
||||
|
|
@ -134,3 +141,11 @@ func (b *PodGroupTemplateApplyConfiguration) WithPriority(value int32) *PodGroup
|
|||
b.Priority = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithPreemptionPolicy sets the PreemptionPolicy field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the PreemptionPolicy field is set to the value of the last call.
|
||||
func (b *PodGroupTemplateApplyConfiguration) WithPreemptionPolicy(value v1.PreemptionPolicy) *PodGroupTemplateApplyConfiguration {
|
||||
b.PreemptionPolicy = &value
|
||||
return b
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import (
|
|||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
"k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/scheduling"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
registry "k8s.io/kubernetes/pkg/registry/scheduling/podgroup"
|
||||
|
|
@ -172,7 +173,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Invalid(field.NewPath("spec", "schedulingConstraints", "topology").Index(0).Child("key"), nil, "").WithOrigin("format=k8s-label-key")},
|
||||
},
|
||||
"pod disruption mode, workload aware preemption enabled": {
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod)),
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod), setPreemptionPolicy(core.PreemptLowerPriority)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"pod disruption mode, workload aware preemption disabled": {
|
||||
|
|
@ -180,7 +181,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "disruptionMode"), "")},
|
||||
},
|
||||
"pod group disruption mode, workload aware preemption enabled": {
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePodGroup)),
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePodGroup), setPreemptionPolicy(core.PreemptLowerPriority)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"pod group disruption mode, workload aware preemption disabled": {
|
||||
|
|
@ -188,7 +189,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "disruptionMode"), "")},
|
||||
},
|
||||
"invalid disruption mode, workload aware preemption enabled": {
|
||||
input: mkValidPodGroup(setDisruptionMode("Invalid")),
|
||||
input: mkValidPodGroup(setDisruptionMode("Invalid"), setPreemptionPolicy(core.PreemptLowerPriority)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectedErrs: field.ErrorList{field.NotSupported(field.NewPath("spec", "disruptionMode"), "Invalid", sets.List(allowedDisruptionModes))},
|
||||
},
|
||||
|
|
@ -197,12 +198,12 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "disruptionMode"), "")},
|
||||
},
|
||||
"valid pod group without disruption mode, workload aware preemption enabled": {
|
||||
input: mkValidPodGroup(),
|
||||
input: mkValidPodGroup(setPreemptionPolicy(core.PreemptLowerPriority)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectedErrs: field.ErrorList{field.Required(field.NewPath("spec", "disruptionMode"), "")},
|
||||
},
|
||||
"valid priority class name, workload aware preemption enabled": {
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod), setPriorityClassName("high-priority")),
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod), setPreemptionPolicy(core.PreemptLowerPriority), setPriorityClassName("high-priority")),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"valid priority class name, workload aware preemption disabled": {
|
||||
|
|
@ -210,7 +211,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "priorityClassName"), "")},
|
||||
},
|
||||
"invalid priority class name, workload aware preemption enabled": {
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod), setPriorityClassName("high/priority")),
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod), setPreemptionPolicy(core.PreemptLowerPriority), setPriorityClassName("high/priority")),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectedErrs: field.ErrorList{
|
||||
field.Invalid(field.NewPath("spec", "priorityClassName"), nil, "").WithOrigin("format=k8s-long-name"),
|
||||
|
|
@ -221,7 +222,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "priorityClassName"), "")},
|
||||
},
|
||||
"valid priority, workload aware preemption enabled": {
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod), setPriority(1000)),
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod), setPreemptionPolicy(core.PreemptLowerPriority), setPriority(1000)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"valid priority, workload aware preemption disabled": {
|
||||
|
|
@ -229,7 +230,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "priority"), "")},
|
||||
},
|
||||
"valid negative priority, workload aware preemption enabled": {
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod), setPriority(-2147483648)),
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod), setPreemptionPolicy(core.PreemptLowerPriority), setPriority(-2147483648)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"valid negative priority, workload aware preemption disabled": {
|
||||
|
|
@ -237,7 +238,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "priority"), "")},
|
||||
},
|
||||
"too high priority, workload aware preemption enabled": {
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod), setPriority(scheduling.HighestUserDefinablePriority+1)),
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod), setPreemptionPolicy(core.PreemptLowerPriority), setPriority(scheduling.HighestUserDefinablePriority+1)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectedErrs: field.ErrorList{
|
||||
field.Invalid(field.NewPath("spec", "priority"), nil, "").WithOrigin("maximum"),
|
||||
|
|
@ -247,6 +248,19 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
input: mkValidPodGroup(setPriority(scheduling.HighestUserDefinablePriority + 1)),
|
||||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "priority"), "")},
|
||||
},
|
||||
"preemption policy, workload aware preemption disabled": {
|
||||
input: mkValidPodGroup(setPreemptionPolicy(core.PreemptNever)),
|
||||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "preemptionPolicy"), "")},
|
||||
},
|
||||
"valid preemption policy (Never), workload aware preemption enabled": {
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod), setPreemptionPolicy(core.PreemptNever)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"valid pod group without preemption policy, workload aware preemption enabled": {
|
||||
input: mkValidPodGroup(setDisruptionMode(scheduling.DisruptionModePod)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectedErrs: field.ErrorList{field.Required(field.NewPath("spec", "preemptionPolicy"), "")},
|
||||
},
|
||||
"ok resourceClaimName reference": {
|
||||
input: mkValidPodGroup(addResourceClaims(scheduling.PodGroupResourceClaim{Name: "claim", ResourceClaimName: new("resource-claim")})),
|
||||
},
|
||||
|
|
@ -559,6 +573,17 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) {
|
|||
updateObj: mkValidPodGroup(setResourceVersion("1"), setPriority(2000)),
|
||||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "priority"), "")},
|
||||
},
|
||||
"invalid update of preemption policy, workload aware preemption enabled": {
|
||||
oldObj: mkValidPodGroup(setResourceVersion("1"), setPreemptionPolicy(core.PreemptNever)),
|
||||
updateObj: mkValidPodGroup(setResourceVersion("1"), setPreemptionPolicy(core.PreemptLowerPriority)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectedErrs: field.ErrorList{field.Invalid(field.NewPath("spec", "preemptionPolicy"), nil, "").WithOrigin("immutable")},
|
||||
},
|
||||
"invalid update of preemption policy, workload aware preemption disabled": {
|
||||
oldObj: mkValidPodGroup(setResourceVersion("1"), setPreemptionPolicy(core.PreemptNever)),
|
||||
updateObj: mkValidPodGroup(setResourceVersion("1"), setPreemptionPolicy(core.PreemptLowerPriority)),
|
||||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "preemptionPolicy"), "")},
|
||||
},
|
||||
}
|
||||
for k, tc := range testCases {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
|
|
@ -869,3 +894,9 @@ func setPriority(priority int32) func(obj *scheduling.PodGroup) {
|
|||
obj.Spec.Priority = new(priority)
|
||||
}
|
||||
}
|
||||
|
||||
func setPreemptionPolicy(policy core.PreemptionPolicy) func(obj *scheduling.PodGroup) {
|
||||
return func(obj *scheduling.PodGroup) {
|
||||
obj.Spec.PreemptionPolicy = &policy
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,11 @@ func init() {
|
|||
{ErrorType: "FieldValueInvalid", Origin: "format=k8s-long-name"},
|
||||
{ErrorType: "FieldValueRequired"},
|
||||
},
|
||||
"spec.preemptionPolicy": {
|
||||
{ErrorType: "FieldValueForbidden"},
|
||||
{ErrorType: "FieldValueInvalid", Origin: "immutable"},
|
||||
{ErrorType: "FieldValueRequired"},
|
||||
},
|
||||
"spec.priority": {
|
||||
{ErrorType: "FieldValueForbidden"},
|
||||
{ErrorType: "FieldValueInvalid", Origin: "immutable"},
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
"k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/apis/scheduling"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
registry "k8s.io/kubernetes/pkg/registry/scheduling/workload"
|
||||
|
|
@ -203,7 +204,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Invalid(field.NewPath("spec", "podGroupTemplates").Index(0).Child("schedulingConstraints", "topology").Index(0).Child("key"), nil, "").WithOrigin("format=k8s-label-key")},
|
||||
},
|
||||
"pod disruption mode, workload aware preemption enabled": {
|
||||
input: mkValidWorkload(setDisruptionMode(0, podDisruptionMode)),
|
||||
input: mkValidWorkload(setDisruptionMode(0, podDisruptionMode), setPreemptionPolicy(0, core.PreemptLowerPriority)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"pod disruption mode, workload aware preemption disabled": {
|
||||
|
|
@ -211,7 +212,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "podGroupTemplates").Index(0).Child("disruptionMode"), "")},
|
||||
},
|
||||
"pod group disruption mode, workload aware preemption enabled": {
|
||||
input: mkValidWorkload(setDisruptionMode(0, podGroupDisruptionMode)),
|
||||
input: mkValidWorkload(setDisruptionMode(0, podGroupDisruptionMode), setPreemptionPolicy(0, core.PreemptLowerPriority)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"pod group disruption mode, workload aware preemption disabled": {
|
||||
|
|
@ -219,7 +220,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "podGroupTemplates").Index(0).Child("disruptionMode"), "")},
|
||||
},
|
||||
"invalid disruption mode, workload aware preemption enabled": {
|
||||
input: mkValidWorkload(setDisruptionMode(0, invalidDisruptionMode)),
|
||||
input: mkValidWorkload(setDisruptionMode(0, invalidDisruptionMode), setPreemptionPolicy(0, core.PreemptLowerPriority)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectedErrs: field.ErrorList{field.NotSupported(field.NewPath("spec", "podGroupTemplates").Index(0).Child("disruptionMode"), invalidDisruptionMode, sets.List(allowedDisruptionModes))},
|
||||
},
|
||||
|
|
@ -228,7 +229,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "podGroupTemplates").Index(0).Child("disruptionMode"), "")},
|
||||
},
|
||||
"valid priorityClassName, workload aware preemption enabled": {
|
||||
input: mkValidWorkload(setPriorityClassName(0, "high-priority")),
|
||||
input: mkValidWorkload(setDisruptionMode(0, podDisruptionMode), setPreemptionPolicy(0, core.PreemptLowerPriority), setPriorityClassName(0, "high-priority")),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"valid priorityClassName, workload aware preemption disabled": {
|
||||
|
|
@ -236,7 +237,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "podGroupTemplates").Index(0).Child("priorityClassName"), "")},
|
||||
},
|
||||
"invalid priorityClassName, workload aware preemption enabled": {
|
||||
input: mkValidWorkload(setPriorityClassName(0, "high/priority")),
|
||||
input: mkValidWorkload(setDisruptionMode(0, podDisruptionMode), setPreemptionPolicy(0, core.PreemptLowerPriority), setPriorityClassName(0, "high/priority")),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectedErrs: field.ErrorList{
|
||||
field.Invalid(field.NewPath("spec", "podGroupTemplates").Index(0).Child("priorityClassName"), nil, "").WithOrigin("format=k8s-long-name"),
|
||||
|
|
@ -248,7 +249,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
},
|
||||
|
||||
"valid priority, workload aware preemption enabled": {
|
||||
input: mkValidWorkload(setPriority(0, 1000)),
|
||||
input: mkValidWorkload(setDisruptionMode(0, podDisruptionMode), setPreemptionPolicy(0, core.PreemptLowerPriority), setPriority(0, 1000)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"valid priority, workload aware preemption disabled": {
|
||||
|
|
@ -256,7 +257,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "podGroupTemplates").Index(0).Child("priority"), "")},
|
||||
},
|
||||
"valid negative priority, workload aware preemption enabled": {
|
||||
input: mkValidWorkload(setPriority(0, -2147483648)),
|
||||
input: mkValidWorkload(setDisruptionMode(0, podDisruptionMode), setPreemptionPolicy(0, core.PreemptLowerPriority), setPriority(0, -2147483648)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"valid negative priority, workload aware preemption disabled": {
|
||||
|
|
@ -264,7 +265,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "podGroupTemplates").Index(0).Child("priority"), "")},
|
||||
},
|
||||
"too high priority, workload aware preemption enabled": {
|
||||
input: mkValidWorkload(setPriority(0, scheduling.HighestUserDefinablePriority+1)),
|
||||
input: mkValidWorkload(setDisruptionMode(0, podDisruptionMode), setPreemptionPolicy(0, core.PreemptLowerPriority), setPriority(0, scheduling.HighestUserDefinablePriority+1)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectedErrs: field.ErrorList{
|
||||
field.Invalid(field.NewPath("spec", "podGroupTemplates").Index(0).Child("priority"), nil, "").WithOrigin("maximum"),
|
||||
|
|
@ -274,6 +275,14 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) {
|
|||
input: mkValidWorkload(setPriority(0, scheduling.HighestUserDefinablePriority+1)),
|
||||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "podGroupTemplates").Index(0).Child("priority"), "")},
|
||||
},
|
||||
"preemption policy, workload aware preemption disabled": {
|
||||
input: mkValidWorkload(setPreemptionPolicy(0, core.PreemptNever)),
|
||||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec", "podGroupTemplates").Index(0).Child("preemptionPolicy"), "")},
|
||||
},
|
||||
"valid preemption policy (Never), workload aware preemption enabled": {
|
||||
input: mkValidWorkload(setDisruptionMode(0, podDisruptionMode), setPreemptionPolicy(0, core.PreemptNever)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
},
|
||||
"ok resourceClaimName reference": {
|
||||
input: mkValidWorkload(addResourceClaims(scheduling.PodGroupResourceClaim{Name: "claim", ResourceClaimName: new("resource-claim")})),
|
||||
},
|
||||
|
|
@ -602,6 +611,17 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) {
|
|||
updateObj: mkValidWorkload(setResourceVersion("1"), setPriority(0, 2000)),
|
||||
expectedErrs: field.ErrorList{field.Invalid(field.NewPath("spec", "podGroupTemplates"), nil, "").WithOrigin("immutable")},
|
||||
},
|
||||
"invalid update of preemption policy, workload aware preemption enabled": {
|
||||
oldObj: mkValidWorkload(setResourceVersion("1"), setPreemptionPolicy(0, core.PreemptNever)),
|
||||
updateObj: mkValidWorkload(setResourceVersion("1"), setPreemptionPolicy(0, core.PreemptLowerPriority)),
|
||||
enableWorkloadAwarePreemption: true,
|
||||
expectedErrs: field.ErrorList{field.Invalid(field.NewPath("spec", "podGroupTemplates"), nil, "").WithOrigin("immutable")},
|
||||
},
|
||||
"invalid update of preemption policy, workload aware preemption disabled": {
|
||||
oldObj: mkValidWorkload(setResourceVersion("1"), setPreemptionPolicy(0, core.PreemptNever)),
|
||||
updateObj: mkValidWorkload(setResourceVersion("1"), setPreemptionPolicy(0, core.PreemptLowerPriority)),
|
||||
expectedErrs: field.ErrorList{field.Invalid(field.NewPath("spec", "podGroupTemplates"), nil, "").WithOrigin("immutable")},
|
||||
},
|
||||
}
|
||||
for k, tc := range testCases {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
|
|
@ -782,3 +802,9 @@ func setPriority(pgIdx int, priority int32) func(obj *scheduling.Workload) {
|
|||
obj.Spec.PodGroupTemplates[pgIdx].Priority = new(priority)
|
||||
}
|
||||
}
|
||||
|
||||
func setPreemptionPolicy(pgIdx int, policy core.PreemptionPolicy) func(obj *scheduling.Workload) {
|
||||
return func(obj *scheduling.Workload) {
|
||||
obj.Spec.PodGroupTemplates[pgIdx].PreemptionPolicy = &policy
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ func init() {
|
|||
{ErrorType: "FieldValueInvalid", Origin: "format=k8s-short-name"},
|
||||
{ErrorType: "FieldValueRequired"},
|
||||
},
|
||||
"spec.podGroupTemplates[*].preemptionPolicy": {
|
||||
{ErrorType: "FieldValueForbidden"},
|
||||
},
|
||||
"spec.podGroupTemplates[*].priority": {
|
||||
{ErrorType: "FieldValueForbidden"},
|
||||
{ErrorType: "FieldValueInvalid", Origin: "maximum"},
|
||||
|
|
|
|||
|
|
@ -698,6 +698,29 @@ func TestPodGroupPreemption(t *testing.T) {
|
|||
expectedPreempted: []string{"vb"},
|
||||
expectedPodsPreemptedByWAP: 1,
|
||||
},
|
||||
{
|
||||
name: "PodGroup with PreemptNever preemption policy does not perform preemption",
|
||||
nodes: []*v1.Node{
|
||||
st.MakeNode().Name("node1").Capacity(map[v1.ResourceName]string{v1.ResourceCPU: "3", v1.ResourceMemory: "4Gi", v1.ResourcePods: "32"}).Obj(),
|
||||
},
|
||||
podGroups: []*schedulingapi.PodGroup{
|
||||
st.MakePodGroup().Name("pg1").Namespace("default").Priority(100).MinCount(3).PreemptionPolicy(v1.PreemptNever).Obj(),
|
||||
},
|
||||
initialPods: []*v1.Pod{
|
||||
st.MakePod().Name("low-1").Req(map[v1.ResourceName]string{v1.ResourceCPU: "1"}).Container("image").ZeroTerminationGracePeriod().Priority(10).Obj(),
|
||||
st.MakePod().Name("low-2").Req(map[v1.ResourceName]string{v1.ResourceCPU: "1"}).Container("image").ZeroTerminationGracePeriod().Priority(10).Obj(),
|
||||
st.MakePod().Name("low-3").Req(map[v1.ResourceName]string{v1.ResourceCPU: "1"}).Container("image").ZeroTerminationGracePeriod().Priority(10).Obj(),
|
||||
},
|
||||
preemptorPods: []*v1.Pod{
|
||||
st.MakePod().Name("high-1").Req(map[v1.ResourceName]string{v1.ResourceCPU: "1"}).Container("image").PodGroupName("pg1").ZeroTerminationGracePeriod().Priority(100).Obj(),
|
||||
st.MakePod().Name("high-2").Req(map[v1.ResourceName]string{v1.ResourceCPU: "1"}).Container("image").PodGroupName("pg1").ZeroTerminationGracePeriod().Priority(100).Obj(),
|
||||
st.MakePod().Name("high-3").Req(map[v1.ResourceName]string{v1.ResourceCPU: "1"}).Container("image").PodGroupName("pg1").ZeroTerminationGracePeriod().Priority(100).Obj(),
|
||||
},
|
||||
expectedScheduled: []string{"low-1", "low-2", "low-3"},
|
||||
expectedPreempted: []string{},
|
||||
expectedUnschedulable: []string{"high-1", "high-2", "high-3"},
|
||||
expectedPodsPreemptedByWAP: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
|||
Loading…
Reference in a new issue