Skip to content

Commit 5918deb

Browse files
authored
Merge pull request #84 from shmuelk/dev-rebase-2025-04-29
Dev rebase 2025 04 29
2 parents c6adfc3 + 962db85 commit 5918deb

File tree

9 files changed

+178
-108
lines changed

9 files changed

+178
-108
lines changed

go.mod

+7-7
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ require (
1717
go.uber.org/zap v1.27.0
1818
google.golang.org/grpc v1.71.1
1919
google.golang.org/protobuf v1.36.6
20-
k8s.io/api v0.32.3
21-
k8s.io/apiextensions-apiserver v0.32.3
22-
k8s.io/apimachinery v0.32.3
23-
k8s.io/client-go v0.32.3
24-
k8s.io/code-generator v0.32.3
25-
k8s.io/component-base v0.32.3
20+
k8s.io/api v0.32.4
21+
k8s.io/apiextensions-apiserver v0.32.4
22+
k8s.io/apimachinery v0.32.4
23+
k8s.io/client-go v0.32.4
24+
k8s.io/code-generator v0.32.4
25+
k8s.io/component-base v0.32.4
2626
k8s.io/utils v0.0.0-20241210054802-24370beab758
2727
sigs.k8s.io/controller-runtime v0.20.4
2828
sigs.k8s.io/structured-merge-diff/v4 v4.7.0
@@ -123,7 +123,7 @@ require (
123123
gopkg.in/inf.v0 v0.9.1 // indirect
124124
gopkg.in/yaml.v2 v2.4.0 // indirect
125125
gopkg.in/yaml.v3 v3.0.1 // indirect
126-
k8s.io/apiserver v0.32.3 // indirect
126+
k8s.io/apiserver v0.32.4 // indirect
127127
k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 // indirect
128128
k8s.io/klog/v2 v2.130.1 // indirect
129129
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect

go.sum

+14-14
Original file line numberDiff line numberDiff line change
@@ -302,20 +302,20 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
302302
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
303303
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
304304
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
305-
k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls=
306-
k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k=
307-
k8s.io/apiextensions-apiserver v0.32.3 h1:4D8vy+9GWerlErCwVIbcQjsWunF9SUGNu7O7hiQTyPY=
308-
k8s.io/apiextensions-apiserver v0.32.3/go.mod h1:8YwcvVRMVzw0r1Stc7XfGAzB/SIVLunqApySV5V7Dss=
309-
k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U=
310-
k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
311-
k8s.io/apiserver v0.32.3 h1:kOw2KBuHOA+wetX1MkmrxgBr648ksz653j26ESuWNY8=
312-
k8s.io/apiserver v0.32.3/go.mod h1:q1x9B8E/WzShF49wh3ADOh6muSfpmFL0I2t+TG0Zdgc=
313-
k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU=
314-
k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY=
315-
k8s.io/code-generator v0.32.3 h1:31p2TVzC9+hVdSkAFruAk3JY+iSfzrJ83Qij1yZutyw=
316-
k8s.io/code-generator v0.32.3/go.mod h1:+mbiYID5NLsBuqxjQTygKM/DAdKpAjvBzrJd64NU1G8=
317-
k8s.io/component-base v0.32.3 h1:98WJvvMs3QZ2LYHBzvltFSeJjEx7t5+8s71P7M74u8k=
318-
k8s.io/component-base v0.32.3/go.mod h1:LWi9cR+yPAv7cu2X9rZanTiFKB2kHA+JjmhkKjCZRpI=
305+
k8s.io/api v0.32.4 h1:kw8Y/G8E7EpNy7gjB8gJZl3KJkNz8HM2YHrZPtAZsF4=
306+
k8s.io/api v0.32.4/go.mod h1:5MYFvLvweRhyKylM3Es/6uh/5hGp0dg82vP34KifX4g=
307+
k8s.io/apiextensions-apiserver v0.32.4 h1:IA+CoR63UDOijR/vEpow6wQnX4V6iVpzazJBskHrpHE=
308+
k8s.io/apiextensions-apiserver v0.32.4/go.mod h1:Y06XO/b92H8ymOdG1HlA1submf7gIhbEDc3RjriqZOs=
309+
k8s.io/apimachinery v0.32.4 h1:8EEksaxA7nd7xWJkkwLDN4SvWS5ot9g6Z/VZb3ju25I=
310+
k8s.io/apimachinery v0.32.4/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
311+
k8s.io/apiserver v0.32.4 h1:Yf7sd/y+GOQKH1Qf6wUeayZrYXe2SKZ17Bcq7VQM5HQ=
312+
k8s.io/apiserver v0.32.4/go.mod h1:JFUMNtE2M5yqLZpIsgCb06SkVSW1YcxW1oyLSTfjXR8=
313+
k8s.io/client-go v0.32.4 h1:zaGJS7xoYOYumoWIFXlcVrsiYioRPrXGO7dBfVC5R6M=
314+
k8s.io/client-go v0.32.4/go.mod h1:k0jftcyYnEtwlFW92xC7MTtFv5BNcZBr+zn9jPlT9Ic=
315+
k8s.io/code-generator v0.32.4 h1:d4dm/43RD6xhPBX22JgJw9JUpwTKzVR6tAxJD7pz83o=
316+
k8s.io/code-generator v0.32.4/go.mod h1:R0bKdIg1smtvsKvj9q7SxTeKq5X9ko6PuICCGt4yqxg=
317+
k8s.io/component-base v0.32.4 h1:HuF+2JVLbFS5GODLIfPCb1Td6b+G2HszJoArcWOSr5I=
318+
k8s.io/component-base v0.32.4/go.mod h1:10KloJEYw1keU/Xmjfy9TKJqUq7J2mYdiD1VDXoco4o=
319319
k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 h1:si3PfKm8dDYxgfbeA6orqrtLkvvIeH8UqffFJDl0bz4=
320320
k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU=
321321
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=

pkg/epp/scheduling/plugins/picker/max-score.go

-55
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package picker
2+
3+
import (
4+
"fmt"
5+
6+
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/plugins"
7+
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/types"
8+
logutil "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/util/logging"
9+
)
10+
11+
var _ plugins.Picker = &MaxScorePicker{}
12+
13+
func NewMaxScorePicker() plugins.Picker {
14+
return &MaxScorePicker{
15+
random: &RandomPicker{},
16+
}
17+
}
18+
19+
// MaxScorePicker picks the pod with the maximum score from the list of candidates.
20+
type MaxScorePicker struct {
21+
random *RandomPicker
22+
}
23+
24+
// Name returns the name of the picker.
25+
func (p *MaxScorePicker) Name() string {
26+
return "max_score"
27+
}
28+
29+
// Pick selects the pod with the maximum score from the list of candidates.
30+
func (p *MaxScorePicker) Pick(ctx *types.SchedulingContext, scoredPods []*types.ScoredPod) *types.Result {
31+
ctx.Logger.V(logutil.DEBUG).Info(fmt.Sprintf("Selecting a pod with the max score from %d candidates: %+v", len(scoredPods), scoredPods))
32+
33+
highestScorePods := []*types.ScoredPod{}
34+
maxScore := -1.0 // pods min score is 0, putting value lower than 0 in order to find at least one pod as highest
35+
for _, pod := range scoredPods {
36+
if pod.Score > maxScore {
37+
maxScore = pod.Score
38+
highestScorePods = []*types.ScoredPod{pod}
39+
} else if pod.Score == maxScore {
40+
highestScorePods = append(highestScorePods, pod)
41+
}
42+
}
43+
44+
if len(highestScorePods) > 1 {
45+
return p.random.Pick(ctx, highestScorePods) // pick randomly from the highest score pods
46+
}
47+
48+
return &types.Result{TargetPod: highestScorePods[0]}
49+
}

pkg/epp/scheduling/plugins/picker/random_picker.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ var _ plugins.Picker = &RandomPicker{}
3030
// RandomPicker picks a random pod from the list of candidates.
3131
type RandomPicker struct{}
3232

33-
func (rp *RandomPicker) Name() string {
33+
func (p *RandomPicker) Name() string {
3434
return "random"
3535
}
3636

37-
func (rp *RandomPicker) Pick(ctx *types.SchedulingContext, scoredPods []*types.ScoredPod) *types.Result {
37+
func (p *RandomPicker) Pick(ctx *types.SchedulingContext, scoredPods []*types.ScoredPod) *types.Result {
3838
ctx.Logger.V(logutil.DEBUG).Info(fmt.Sprintf("Selecting a random pod from %d candidates: %+v", len(scoredPods), scoredPods))
3939
i := rand.Intn(len(scoredPods))
40-
return &types.Result{TargetPod: scoredPods[i].Pod}
40+
return &types.Result{TargetPod: scoredPods[i]}
4141
}

pkg/epp/scheduling/scheduler_test.go

+26-21
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,19 @@ func TestSchedule(t *testing.T) {
9393
},
9494
},
9595
wantRes: &types.Result{
96-
TargetPod: &types.PodMetrics{
97-
Pod: &backendmetrics.Pod{NamespacedName: k8stypes.NamespacedName{Name: "pod2"}},
98-
Metrics: &backendmetrics.Metrics{
99-
WaitingQueueSize: 3,
100-
KVCacheUsagePercent: 0.1,
101-
MaxActiveModels: 2,
102-
ActiveModels: map[string]int{
103-
"foo": 1,
104-
"critical": 1,
96+
TargetPod: &types.ScoredPod{
97+
Pod: &types.PodMetrics{
98+
Pod: &backendmetrics.Pod{NamespacedName: k8stypes.NamespacedName{Name: "pod2"}},
99+
Metrics: &backendmetrics.Metrics{
100+
WaitingQueueSize: 3,
101+
KVCacheUsagePercent: 0.1,
102+
MaxActiveModels: 2,
103+
ActiveModels: map[string]int{
104+
"foo": 1,
105+
"critical": 1,
106+
},
107+
WaitingModels: map[string]int{},
105108
},
106-
WaitingModels: map[string]int{},
107109
},
108110
},
109111
MutatedHeaders: make(map[string]string),
@@ -155,17 +157,19 @@ func TestSchedule(t *testing.T) {
155157
},
156158
},
157159
wantRes: &types.Result{
158-
TargetPod: &types.PodMetrics{
159-
Pod: &backendmetrics.Pod{NamespacedName: k8stypes.NamespacedName{Name: "pod1"}},
160-
Metrics: &backendmetrics.Metrics{
161-
WaitingQueueSize: 0,
162-
KVCacheUsagePercent: 0.2,
163-
MaxActiveModels: 2,
164-
ActiveModels: map[string]int{
165-
"foo": 1,
166-
"bar": 1,
160+
TargetPod: &types.ScoredPod{
161+
Pod: &types.PodMetrics{
162+
Pod: &backendmetrics.Pod{NamespacedName: k8stypes.NamespacedName{Name: "pod1"}},
163+
Metrics: &backendmetrics.Metrics{
164+
WaitingQueueSize: 0,
165+
KVCacheUsagePercent: 0.2,
166+
MaxActiveModels: 2,
167+
ActiveModels: map[string]int{
168+
"foo": 1,
169+
"bar": 1,
170+
},
171+
WaitingModels: map[string]int{},
167172
},
168-
WaitingModels: map[string]int{},
169173
},
170174
},
171175
MutatedHeaders: make(map[string]string),
@@ -525,6 +529,7 @@ func (tp *TestPlugin) Filter(ctx *types.SchedulingContext, pods []types.Pod) []t
525529
tp.ReceivedRequestHeaders[key] = value
526530
}
527531
return findPods(ctx, tp.FilterRes...)
532+
528533
}
529534

530535
func (tp *TestPlugin) Score(ctx *types.SchedulingContext, pods []types.Pod) map[types.Pod]float64 {
@@ -574,7 +579,7 @@ func findPods(ctx *types.SchedulingContext, names ...k8stypes.NamespacedName) []
574579
func getPodScore(scoredPods []*types.ScoredPod, selectedPod types.Pod) float64 {
575580
finalScore := 0.0
576581
for _, scoredPod := range scoredPods {
577-
if scoredPod.Pod.GetPod().NamespacedName.String() == selectedPod.GetPod().NamespacedName.String() {
582+
if scoredPod.GetPod().NamespacedName.String() == selectedPod.GetPod().NamespacedName.String() {
578583
finalScore = scoredPod.Score
579584
break
580585
}

pkg/epp/scheduling/types/types.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ type Pod interface {
4949
}
5050

5151
type ScoredPod struct {
52-
Pod Pod
52+
Pod
5353
Score float64
5454
}
5555

pkg/epp/util/env/env.go

+17-7
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,25 @@ import (
55
"strconv"
66

77
"github.com/go-logr/logr"
8-
logutil "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/util/logging"
98
)
109

1110
// getEnvFloat gets a float64 from an environment variable with a default value
1211
func GetEnvFloat(key string, defaultVal float64, logger logr.Logger) float64 {
1312
val, exists := os.LookupEnv(key)
1413
if !exists {
15-
logger.V(logutil.VERBOSE).Info("Environment variable not set, using default value",
14+
logger.Info("Environment variable not set, using default value",
1615
"key", key, "defaultValue", defaultVal)
1716
return defaultVal
1817
}
1918

2019
floatVal, err := strconv.ParseFloat(val, 64)
2120
if err != nil {
22-
logger.V(logutil.VERBOSE).Info("Failed to parse environment variable as float, using default value",
21+
logger.Info("Failed to parse environment variable as float, using default value",
2322
"key", key, "value", val, "error", err, "defaultValue", defaultVal)
2423
return defaultVal
2524
}
2625

27-
logger.V(logutil.VERBOSE).Info("Successfully loaded environment variable",
26+
logger.Info("Successfully loaded environment variable",
2827
"key", key, "value", floatVal)
2928
return floatVal
3029
}
@@ -33,19 +32,30 @@ func GetEnvFloat(key string, defaultVal float64, logger logr.Logger) float64 {
3332
func GetEnvInt(key string, defaultVal int, logger logr.Logger) int {
3433
val, exists := os.LookupEnv(key)
3534
if !exists {
36-
logger.V(logutil.VERBOSE).Info("Environment variable not set, using default value",
35+
logger.Info("Environment variable not set, using default value",
3736
"key", key, "defaultValue", defaultVal)
3837
return defaultVal
3938
}
4039

4140
intVal, err := strconv.Atoi(val)
4241
if err != nil {
43-
logger.V(logutil.VERBOSE).Info("Failed to parse environment variable as int, using default value",
42+
logger.Info("Failed to parse environment variable as int, using default value",
4443
"key", key, "value", val, "error", err, "defaultValue", defaultVal)
4544
return defaultVal
4645
}
4746

48-
logger.V(logutil.VERBOSE).Info("Successfully loaded environment variable",
47+
logger.Info("Successfully loaded environment variable",
4948
"key", key, "value", intVal)
5049
return intVal
5150
}
51+
52+
// GetEnvString gets a string from an environment variable with a default value
53+
func GetEnvString(key string, defaultVal string, logger logr.Logger) string {
54+
val, exists := os.LookupEnv(key)
55+
if !exists {
56+
logger.Info("Environment variable not set, using default value",
57+
"key", key, "defaultValue", defaultVal)
58+
return defaultVal
59+
}
60+
return val
61+
}

pkg/epp/util/env/env_test.go

+61
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,64 @@ func TestGetEnvInt(t *testing.T) {
142142
})
143143
}
144144
}
145+
146+
func TestGetEnvString(t *testing.T) {
147+
logger := testr.New(t)
148+
149+
tests := []struct {
150+
name string
151+
key string
152+
value string
153+
defaultVal string
154+
expected string
155+
setup func()
156+
teardown func()
157+
}{
158+
{
159+
name: "env variable exists and is valid",
160+
key: "TEST_STR",
161+
value: "123",
162+
defaultVal: "default",
163+
expected: "123",
164+
setup: func() {
165+
os.Setenv("TEST_STR", "123")
166+
},
167+
teardown: func() {
168+
os.Unsetenv("TEST_STR")
169+
},
170+
},
171+
{
172+
name: "env variable does not exist",
173+
key: "TEST_STR_MISSING",
174+
defaultVal: "default",
175+
expected: "default",
176+
setup: func() {},
177+
teardown: func() {},
178+
},
179+
{
180+
name: "env variable is empty string",
181+
key: "TEST_STR_EMPTY",
182+
value: "",
183+
defaultVal: "default",
184+
expected: "",
185+
setup: func() {
186+
os.Setenv("TEST_STR_EMPTY", "")
187+
},
188+
teardown: func() {
189+
os.Unsetenv("TEST_STR_EMPTY")
190+
},
191+
},
192+
}
193+
194+
for _, tc := range tests {
195+
t.Run(tc.name, func(t *testing.T) {
196+
tc.setup()
197+
defer tc.teardown()
198+
199+
result := GetEnvString(tc.key, tc.defaultVal, logger.V(logutil.VERBOSE))
200+
if result != tc.expected {
201+
t.Errorf("GetEnvString(%s, %s) = %s, expected %s", tc.key, tc.defaultVal, result, tc.expected)
202+
}
203+
})
204+
}
205+
}

0 commit comments

Comments
 (0)