diff --git a/pkg/detector/detector.go b/pkg/detector/detector.go index 4f4a59f76..49fe5bdd9 100644 --- a/pkg/detector/detector.go +++ b/pkg/detector/detector.go @@ -477,6 +477,7 @@ func (d *ResourceDetector) ApplyPolicy(object *unstructured.Unstructured, object bindingCopy.Spec.Failover = binding.Spec.Failover bindingCopy.Spec.ConflictResolution = binding.Spec.ConflictResolution bindingCopy.Spec.PreserveResourcesOnDeletion = binding.Spec.PreserveResourcesOnDeletion + bindingCopy.Spec.SchedulePriority = binding.Spec.SchedulePriority if binding.Spec.Suspension != nil { if bindingCopy.Spec.Suspension == nil { bindingCopy.Spec.Suspension = &workv1alpha2.Suspension{} @@ -571,6 +572,7 @@ func (d *ResourceDetector) ApplyClusterPolicy(object *unstructured.Unstructured, bindingCopy.Spec.Failover = binding.Spec.Failover bindingCopy.Spec.ConflictResolution = binding.Spec.ConflictResolution bindingCopy.Spec.PreserveResourcesOnDeletion = binding.Spec.PreserveResourcesOnDeletion + bindingCopy.Spec.SchedulePriority = binding.Spec.SchedulePriority if binding.Spec.Suspension != nil { if bindingCopy.Spec.Suspension == nil { bindingCopy.Spec.Suspension = &workv1alpha2.Suspension{} @@ -767,6 +769,32 @@ func (d *ResourceDetector) BuildResourceBinding(object *unstructured.Unstructure propagationBinding.Spec.ReplicaRequirements = replicaRequirements } + if features.FeatureGate.Enabled(features.PriorityBasedScheduling) && policySpec.SchedulePriority != nil { + var bindingSchedulePriority *workv1alpha2.SchedulePriority + priorityClassName := policySpec.SchedulePriority.PriorityClassName + + switch policySpec.SchedulePriority.PriorityClassSource { + case policyv1alpha1.KubePriorityClass: + kubePriorityClass, err := helper.GetPriorityClassByName(context.TODO(), d.Client, policySpec.SchedulePriority.PriorityClassName) + if err != nil { + klog.Errorf("Failed to get Kube PriorityClass(%s): %v", priorityClassName, err) + return nil, err + } + bindingSchedulePriority = &workv1alpha2.SchedulePriority{ + Priority: kubePriorityClass.Value, + // TODO add preemptionpolicy + //PreemptionPolicy: kubePriorityClass.PreemptionPolicy, + } + case policyv1alpha1.PodPriorityClass: + return nil, fmt.Errorf("priority class source is PodPriorityClass, but PodPriorityClass is not supported yet") + case policyv1alpha1.FederatedPriorityClass: + return nil, fmt.Errorf("priority class source is FederatedPriorityClass, but FederatedPriorityClass is not supported yet") + default: + return nil, fmt.Errorf("unsupported priority class source") + } + propagationBinding.Spec.SchedulePriority = bindingSchedulePriority + } + return propagationBinding, nil } diff --git a/pkg/util/helper/priorityclass.go b/pkg/util/helper/priorityclass.go new file mode 100644 index 000000000..0982b8d6c --- /dev/null +++ b/pkg/util/helper/priorityclass.go @@ -0,0 +1,37 @@ +/* +Copyright 2025 The Karmada Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package helper + +import ( + "context" + + schedulingv1 "k8s.io/api/scheduling/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// GetPriorityClassByName gets the k8s priority class by name. +// +// It returns the priorityClass and an error. +func GetPriorityClassByName(ctx context.Context, c client.Client, name string) (*schedulingv1.PriorityClass, error) { + priorityClass := &schedulingv1.PriorityClass{} + + if err := c.Get(ctx, client.ObjectKey{Name: name}, priorityClass); err != nil { + return nil, err + } + + return priorityClass, nil +} diff --git a/pkg/util/helper/priorityclass_test.go b/pkg/util/helper/priorityclass_test.go new file mode 100644 index 000000000..f56f0181d --- /dev/null +++ b/pkg/util/helper/priorityclass_test.go @@ -0,0 +1,58 @@ +/* +Copyright 2025 The Karmada Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package helper + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + schedulingv1 "k8s.io/api/scheduling/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +func TestGetPriorityClassByName(t *testing.T) { + ctx := context.Background() + + // Create mock PriorityClasses + priorityClass1 := &schedulingv1.PriorityClass{ + ObjectMeta: metav1.ObjectMeta{Name: "high-priority"}, + Value: 1000, + } + + // Create a fake client with the objects + scheme := runtime.NewScheme() + err := corev1.AddToScheme(scheme) + assert.NoError(t, err) + err = schedulingv1.AddToScheme(scheme) + assert.NoError(t, err) + fakeClient := clientfake.NewClientBuilder().WithScheme(scheme).WithObjects(priorityClass1).Build() + + // Test case 1: Fetch by name + pc, err := GetPriorityClassByName(ctx, fakeClient, "high-priority") + assert.NoError(t, err) + assert.NotNil(t, pc) + assert.Equal(t, int32(1000), pc.Value) + + // Test case 2: Error when named class does not exist + pc, err = GetPriorityClassByName(ctx, fakeClient, "nonexistent") + assert.Error(t, err) + assert.Nil(t, pc) +}