Skip to content

Commit 33e108a

Browse files
committed
Add Stable-Service fix
Signed-off-by: Revital Sur <eres@il.ibm.com>
1 parent 1d115d7 commit 33e108a

3 files changed

Lines changed: 50 additions & 13 deletions

File tree

test/coordinator/e2e/coordinator/coordinator_test.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,7 @@ import (
3131
testutils "github.com/llm-d/llm-d-router/test/utils"
3232
)
3333

34-
// requestTimeout is intentionally long (applies to all specs, text-only and
35-
// multimodal) so the request completes even on the intermittent slow/black-holed
36-
// path, letting the end-of-spec coordinator log dump show whether and when the
37-
// request actually reached the coordinator.
38-
const requestTimeout = 600 * time.Second
34+
const requestTimeout = 60 * time.Second
3935

4036
// testImageURL and testImageURL2 are publicly accessible images used to
4137
// exercise multimodal requests that trigger the encode stage.

test/coordinator/e2e/coordinator/e2e_suite_test.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,10 @@ var (
9797

9898
readyTimeout = env.GetEnvDuration("READY_TIMEOUT", defaultReadyTimeout, ginkgo.GinkgoLogr)
9999

100-
portForwardSessions []*gexec.Session
101-
rendererObjects []string
102-
createdNameSpace bool
100+
portForwardSessions []*gexec.Session
101+
rendererObjects []string
102+
stableServiceObjects []string
103+
createdNameSpace bool
103104
)
104105

105106
func TestCoordinatorE2E(t *testing.T) {
@@ -131,6 +132,10 @@ var _ = ginkgo.BeforeSuite(func() {
131132
}
132133

133134
rendererObjects = createRenderer()
135+
136+
// Coordinator and EPP Services are created once and kept stable across specs
137+
// so Envoy's STRICT_DNS clusters never have to re-resolve a rotated ClusterIP.
138+
stableServiceObjects = createStableServices()
134139
})
135140

136141
var _ = ginkgo.ReportAfterSuite("cleanup", func(report ginkgo.Report) {
@@ -148,6 +153,9 @@ var _ = ginkgo.ReportAfterSuite("cleanup", func(report ginkgo.Report) {
148153
if len(rendererObjects) > 0 {
149154
testutils.DeleteObjects(testConfig, rendererObjects, nsName)
150155
}
156+
if len(stableServiceObjects) > 0 {
157+
testutils.DeleteObjects(testConfig, stableServiceObjects, nsName)
158+
}
151159
for _, session := range portForwardSessions {
152160
session.Terminate()
153161
}

test/coordinator/e2e/coordinator/setup_test.go

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ func createEndPointPicker(phase, config string) []string {
9696

9797
objects := make([]string, 1, 8)
9898
objects[0] = "ConfigMap/" + cmName
99-
objects = append(objects, applyManifest(manifest, eppSubstitutions())...)
99+
// The Service is created once by createStableServices; recreate only the
100+
// rest (ServiceAccount, RoleBinding, Deployment) per spec.
101+
objects = append(objects, applyManifest(manifest, eppSubstitutions(), "Service")...)
100102
podsInDeploymentsReady(objects)
101103
return objects
102104
}
@@ -177,7 +179,9 @@ func createCoordinator(config string) []string {
177179
objects[0] = "ConfigMap/llm-d-coordinator-config"
178180

179181
docs := e2eutil.RunKustomize(coordinatorComponentDir)
180-
docs = e2eutil.FilterKinds(docs, "ConfigMap")
182+
// The Service is created once by createStableServices so its ClusterIP is
183+
// stable across specs; recreate only the Deployment (and SA) per spec.
184+
docs = e2eutil.FilterKinds(docs, "ConfigMap", "Service")
181185
docs = e2eutil.SubstituteMany(docs, coordinatorSubstitutions())
182186
docs = e2eutil.RemoveEmptyArgs(docs)
183187
objects = append(objects, testutils.CreateObjsFromYaml(testConfig, docs, nsName)...)
@@ -188,8 +192,11 @@ func createCoordinator(config string) []string {
188192
}
189193

190194
// waitForCoordinatorReady polls /readyz through Envoy until it returns 200,
191-
// catching Envoy's STRICT_DNS resolution lagging behind the per-test Service
192-
// (podsInDeploymentsReady already confirms the coordinator pod itself is ready).
195+
// confirming the freshly recreated coordinator pod is reachable through the
196+
// gateway before the test sends its request. The gateway Service is stable
197+
// across specs (see createStableServices), so this waits for the new pod to
198+
// appear behind it, not for Envoy to re-resolve a rotated ClusterIP.
199+
// (podsInDeploymentsReady already confirms the coordinator pod itself is ready.)
193200
func waitForCoordinatorReady() {
194201
ginkgo.By("Waiting for coordinator to be reachable via gateway")
195202
gomega.Eventually(func() bool {
@@ -222,13 +229,39 @@ func createEPPConfigMap(name, content string) {
222229
}
223230
}
224231

225-
func applyManifest(path string, subs map[string]string) []string {
232+
func applyManifest(path string, subs map[string]string, excludeKinds ...string) []string {
226233
docs := testutils.ReadYaml(path)
227234
docs = e2eutil.SubstituteMany(docs, subs)
228235
docs = e2eutil.RemoveEmptyArgs(docs)
236+
if len(excludeKinds) > 0 {
237+
docs = e2eutil.FilterKinds(docs, excludeKinds...)
238+
}
229239
return testutils.CreateObjsFromYaml(testConfig, docs, getNamespace())
230240
}
231241

242+
// createStableServices creates the coordinator and per-phase EPP Services once,
243+
// up front, and returns their ids for suite teardown. Envoy fronts these via
244+
// STRICT_DNS clusters and outlives the per-spec workload; recreating the
245+
// Services each spec would rotate their ClusterIPs and force Envoy to
246+
// re-resolve, so only the Deployments behind them churn per spec. Mirrors the
247+
// non-coordinator e2e, which creates the EPP Services once in its per-container
248+
// setup and recreates only the Deployment per test.
249+
func createStableServices() []string {
250+
var objects []string
251+
252+
docs := e2eutil.RunKustomize(coordinatorComponentDir)
253+
docs = e2eutil.FilterKinds(docs, "ConfigMap", "Deployment", "ServiceAccount")
254+
docs = e2eutil.SubstituteMany(docs, coordinatorSubstitutions())
255+
docs = e2eutil.RemoveEmptyArgs(docs)
256+
objects = append(objects, testutils.CreateObjsFromYaml(testConfig, docs, getNamespace())...)
257+
258+
for _, manifest := range []string{encodeEPPManifest, prefillEPPManifest, decodeEPPManifest} {
259+
objects = append(objects,
260+
applyManifest(manifest, eppSubstitutions(), "ServiceAccount", "RoleBinding", "Deployment")...)
261+
}
262+
return objects
263+
}
264+
232265
func eppSubstitutions() map[string]string {
233266
return map[string]string{
234267
"${EPP_NAME}": eppName,

0 commit comments

Comments
 (0)