Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changes/unreleased/fixed-20260728-212512.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kind: Fixed
body: |-
Allow creating PodGroups with an explicit minMember of 0
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ spec:
description: |-
MinMember defines the minimal number of members to run the PodGroup;
if there are not enough resources to start all required members, the scheduler will not start anyone.
A value of 0 means no gang requirement: all pods are scheduled elastically (e.g. scale-to-zero workloads).
format: int32
minimum: 1
minimum: 0
type: integer
parallelism:
description: The number of pods which will try to run at any instant.
Expand Down
3 changes: 2 additions & 1 deletion pkg/apis/scheduling/v2alpha2/podgroup_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ import (
type PodGroupSpec struct {
// MinMember defines the minimal number of members to run the PodGroup;
// if there are not enough resources to start all required members, the scheduler will not start anyone.
// +kubebuilder:validation:Minimum=1
// A value of 0 means no gang requirement: all pods are scheduled elastically (e.g. scale-to-zero workloads).
// +kubebuilder:validation:Minimum=0
MinMember int32 `json:"minMember,omitempty" protobuf:"bytes,1,opt,name=minMember"`

// Queue defines the queue to allocate resource for PodGroup; if queue does not exist,
Expand Down
16 changes: 13 additions & 3 deletions pkg/podgrouper/podgrouper/plugins/knative/knative_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package knative

import (
"strconv"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -113,6 +112,17 @@ func TestGetPodGroupMetadata(t *testing.T) {
}

func TestGetPodGroupMetadata_MinScale(t *testing.T) {
for minScale, expectedMinAvailable := range map[string]int32{
"3": 3,
"0": 0, // scale-to-zero: no gang requirement
} {
t.Run("min-scale="+minScale, func(t *testing.T) {
testGetPodGroupMetadataMinScale(t, minScale, expectedMinAvailable)
})
}
}

func testGetPodGroupMetadataMinScale(t *testing.T, minScale string, expectedMinAvailable int32) {
service := &unstructured.Unstructured{
Object: map[string]interface{}{
"kind": "Service",
Expand Down Expand Up @@ -156,7 +166,7 @@ func TestGetPodGroupMetadata_MinScale(t *testing.T) {
Namespace: "test_namespace",
UID: "2",
Annotations: map[string]string{
"autoscaling.knative.dev/min-scale": "3",
"autoscaling.knative.dev/min-scale": minScale,
},
},
Spec: knative.RevisionSpec{},
Expand Down Expand Up @@ -197,7 +207,7 @@ func TestGetPodGroupMetadata_MinScale(t *testing.T) {
assert.Equal(t, "pg-revision-2", metadata.Name)
assert.Equal(t, constants.InferencePriorityClass, metadata.PriorityClassName)
assert.Equal(t, "test_queue", metadata.Queue)
assert.Equal(t, "3", strconv.Itoa(int(metadata.MinAvailable)))
assert.Equal(t, expectedMinAvailable, metadata.MinAvailable)
}

func TestGetPodGroupMetadataBackwardsCompatibility(t *testing.T) {
Expand Down
32 changes: 32 additions & 0 deletions pkg/scheduler/api/podgroup_info/job_info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/utils/ptr"

enginev2alpha2 "github.com/kai-scheduler/KAI-scheduler/pkg/apis/scheduling/v2alpha2"
commonconstants "github.com/kai-scheduler/KAI-scheduler/pkg/common/constants"
"github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/common_info"
"github.com/kai-scheduler/KAI-scheduler/pkg/scheduler/api/pod_info"
Expand Down Expand Up @@ -132,6 +133,37 @@ func TestAddTaskInfo(t *testing.T) {
}
}

func TestSetPodGroupMinMember(t *testing.T) {
tests := []struct {
name string
minMember int32
expectedMinAvail int32
}{
// int32 cannot distinguish unset from explicit 0; both default to a gang of 1
{"zero or unset minMember defaults to 1", 0, 1},
{"positive minMember is honored", 3, 3},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
info := NewPodGroupInfo("group-1")
info.SetPodGroup(&enginev2alpha2.PodGroup{
ObjectMeta: metav1.ObjectMeta{
Name: "group-1",
Namespace: "ns-1",
},
Spec: enginev2alpha2.PodGroupSpec{
Queue: "queue-1",
MinMember: test.minMember,
},
})

if got := info.PodSets[DefaultSubGroup].GetMinAvailable(); got != test.expectedMinAvail {
t.Errorf("expected minAvailable %d, got %d", test.expectedMinAvail, got)
}
})
}
}

func TestDeleteTaskInfo(t *testing.T) {
// case1
case01_uid := common_info.PodGroupID("owner1")
Expand Down
26 changes: 26 additions & 0 deletions test/e2e/suites/integrations/third_party/knative/knative_specs.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,32 @@ func DescribeKnativeSpecs() bool {
Expect(podGroups.Items[0].Spec.MinMember).To(Equal(int32(1)),
"Expected minmember of podgroup to be 1")
})

It("knative service with scale-to-zero - minscale 0", func(ctx context.Context) {
namespace := queue.GetConnectedNamespaceToQueue(testCtx.Queues[0])
serviceName := "knative-service-" + utils.GenerateRandomK8sName(10)

knativeService := GetKnativeServiceObject(serviceName, namespace, testCtx.Queues[0].Name)

knativeService.Spec.ConfigurationSpec.Template.Annotations[minScaleAnnotation] = "0"

Expect(testCtx.ControllerClient.Create(ctx, knativeService)).To(Succeed())
defer func() {
Expect(testCtx.ControllerClient.Delete(ctx, knativeService)).To(Succeed())
}()

// Knative still creates the initial pod on deployment even with min-scale 0
pods := GetServicePods(ctx, testCtx, serviceName, namespace, 1)

wait.ForPodsScheduled(ctx, testCtx.ControllerClient, namespace, pods)

var podGroups v2alpha2.PodGroupList
Expect(testCtx.ControllerClient.List(ctx, &podGroups, client.InNamespace(namespace))).To(Succeed())
Expect(len(podGroups.Items)).To(Equal(1),
"Expected one podgroup for the revision")
Expect(podGroups.Items[0].Spec.MinMember).To(Equal(int32(0)),
"Expected minmember of podgroup to be 0")
})
})
})
}
Expand Down
Loading