[coordinator] e2e tests: containerize and share deploy components#1975
Conversation
| @@ -3,6 +3,7 @@ | |||
| # | |||
| # Encoder deployment for multimodal disaggregation scenarios (E/PD, E/P/D). | |||
| # Includes a PVC for shared encoder embeddings cache. | |||
There was a problem hiding this comment.
can you remove this line? And rephrase the comments (we need PVC only for shared storage EC connector)
| - ../../../../components/vllm-encode/ | ||
| - ../../../../components/vllm-prefill/ | ||
| # vllm-decode is coordinator-local, not the shared deploy/components/vllm-decode: the | ||
| # router's decode carries a routing-sidecar proxying 8000->8200 for connector-based P/D |
There was a problem hiding this comment.
Why can't we reuse the shared deploy/components/vllm-decode? it is similar as the epd scenario without the sidecar
| @@ -1,23 +1,35 @@ | |||
| SHELL := /usr/bin/env bash | |||
|
|
|||
| # Image registry + dev-environment image tags (single source of truth). | |||
There was a problem hiding this comment.
should we return versions.mk?
There was a problem hiding this comment.
Checked, it's not actually shared here, the original pull_images.sh read versions.mk, but this repo's version (reused from the router) doesn't. So it'd only have one consumer, same as keeping it inline. Can restore it if you'd rather match upstream's layout for easier syncing.
|
CI tests do not include the coordinator |
|
We need to add rank-port topology (for DP) |
I will address it in a separate PR if thats OK. |
I added a new workflow for the coordinator. |
02cff23 to
d2bffe6
Compare
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com>
There was a problem hiding this comment.
Pull request overview
This PR refactors the coordinator end-to-end (e2e) testing and deployment-manifest layout to align with the main router’s infrastructure, reduce duplicated YAML, and improve test reliability/maintainability.
Changes:
- Containerizes
test-e2e-coordinatorto run fully inside the builder container (including Kind cluster lifecycle), matching the router e2e execution pattern. - Shares coordinator deploy components with the router where appropriate (CRDs + vLLM encode/prefill), while keeping coordinator-specific decode behavior via a local patch overlay.
- Improves coordinator e2e configurability and cleanup diagnostics (namespace/process helpers, render image/port parameters, suite-failure pod/log dumping) and removes unused Gateway API CRD installation from coordinator e2e.
Reviewed changes
Copilot reviewed 29 out of 30 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| test/utils/parallel.go | Adds shared helpers for per-process port/namespace calculations and Kind extraPortMappings generation. |
| test/e2e/e2e_suite_test.go | Refactors router e2e suite to use shared parallel helpers and centralizes default ports. |
| test/coordinator/e2e/coordinator/utils_test.go | Updates coordinator e2e helpers to use per-process namespace and adds suite-failure pod/log dumping. |
| test/coordinator/e2e/coordinator/setup_test.go | Uses per-process namespace consistently, removes unused Gateway API CRD install, and updates coordinator/render substitutions. |
| test/coordinator/e2e/coordinator/pools_check_test.go | Ensures pool checks operate within the per-process namespace. |
| test/coordinator/e2e/coordinator/e2e_suite_test.go | Adds coordinator e2e parallel-process plumbing, Kind port mappings, and suite-failure diagnostics; switches coordinator service away from NodePort usage in tests. |
| test/coordinator/e2e/coordinator/coordinator_test.go | Routes requests via the gateway helper and passes the resolved namespace into log verification. |
| test/coordinator/e2e/coordinator/configs_test.go | Parameterizes render service address by ${VLLM_RENDER_PORT}. |
| scripts/pull_images.sh | Adds a toggle to skip pulling the EPP image (useful when CI already loads artifacts). |
| README.coord.md | Adds a TOC and documents coordinator unit/e2e test workflows, env vars, and cluster preservation. |
| Makefile.coord.mk | Reworks coordinator build/test targets to run e2e inside the builder container with host networking + container socket wiring; updates image/tag handling. |
| Makefile | Excludes coordinator packages from the EPP unit-test package list. |
| deploy/coordinator/environments/dev/epd-pools/kustomization.yaml | Switches encode/prefill to shared components and documents why decode remains coordinator-local via patching. |
| deploy/coordinator/components/vllm-render/deployment.yaml | Parameterizes render image/port and removes unused container env vars. |
| deploy/coordinator/components/vllm-prefill/kustomization.yaml | Removes coordinator-local prefill kustomization (now shared). |
| deploy/coordinator/components/vllm-prefill/deployment.yaml | Removes duplicated coordinator-local prefill Deployment manifest. |
| deploy/coordinator/components/vllm-encode/kustomization.yaml | Removes coordinator-local encode kustomization (now shared). |
| deploy/coordinator/components/vllm-encode/deployment.yaml | Removes duplicated coordinator-local encode Deployment manifest. |
| deploy/coordinator/components/vllm-decode/patch-decode.yaml | Adds a patch overlay to remove the routing-sidecar and adapt decode ports for coordinator use. |
| deploy/coordinator/components/vllm-decode/kustomization.yaml | Converts decode to a shared-base + coordinator patch overlay. |
| deploy/coordinator/components/vllm-decode/deployment.yaml | Removes duplicated coordinator-local decode Deployment manifest. |
| deploy/coordinator/components/crds-gie/kustomization.yaml | Removes coordinator-local vendored GIE CRD kustomization (now referenced from shared components). |
| deploy/coordinator/components/crds-gie/gie.yaml | Removes coordinator-local vendored GIE CRD bundle. |
| deploy/coordinator/components/crds-gateway-api/kustomization.yaml | Removes coordinator-local vendored Gateway API CRD kustomization (no longer installed by coordinator e2e). |
| deploy/coordinator/components/coordinator/deployment.yaml | Changes coordinator Service from NodePort to ClusterIP for the coordinator component. |
| deploy/components/vllm-prefill/kustomization.yaml | Updates component header comment to note coordinator reuse. |
| deploy/components/vllm-encode/kustomization.yaml | Clarifies the PVC inclusion rationale in comments. |
| .github/workflows/ci-pr-checks.yaml | Excludes coordinator-only paths from the main PR checks workflow filter. |
| .github/workflows/ci-coordinator.yaml | Adds a dedicated CI workflow to run coordinator unit + e2e tests when coordinator-relevant paths change. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Revital Sur <eres@il.ibm.com>
| // ProcessPort returns the NodePort for the current Ginkgo parallel process for | ||
| // a service whose first process uses basePort. When tests run in parallel, | ||
| // each process gets its own NodePort of the form basePort + processPortOffset | ||
| // * (the process number minus one), so process one gets exactly basePort. |
There was a problem hiding this comment.
The file has zero unit tests
There was a problem hiding this comment.
No other file in test/utils/ has a unit test file. The unit test target (make test-unit) explicitly excludes the test/ subtree, so any *_test.go added here would not be picked up by it.
The functions that call ginkgo.GinkgoParallelProcess() (ProcessPort, Namespace) also can't be meaningfully tested outside a running Ginkgo suite. The pure helpers could have tests, but they'd need a separate make target to run.
| modelName = env.GetEnvString("MODEL_NAME", "Qwen/Qwen3-VL-2B-Instruct", ginkgo.GinkgoLogr) | ||
|
|
||
| nsName = env.GetEnvString("NAMESPACE", "default", ginkgo.GinkgoLogr) | ||
| numProcesses = env.GetEnvInt("E2E_NUM_PROCS", 1, ginkgo.GinkgoLogr) |
There was a problem hiding this comment.
E2E_NUM_PROCS is never set by any workflow, and neither run script passes -ginkgo.procs/-p to go test. So numProcesses is always 1 in every CI run — the baseName-N / port+100*idx branches have never run, before or after this PR. This PR generalizes that already-dormant router code into a shared package and hands the coordinator suite the identical, still-unexercised capability. Pre-existing pattern, not introduced by this PR, but worth flagging since the PR explicitly reframes it as new "parallel test infrastructure" — infrastructure that's currently only proven at n=1.
Probably it is a part of #1976
grep -r E2E_NUM_PROCS *
test/coordinator/e2e/coordinator/e2e_suite_test.go:92: numProcesses = env.GetEnvInt("E2E_NUM_PROCS", 1, ginkgo.GinkgoLogr)
test/utils/parallel.go:71:// E2E_NUM_PROCS environment variable) matches the actual number of Ginkgo
test/utils/parallel.go:76: ginkgo.Fail(fmt.Sprintf("The value of the environment variable `E2E_NUM_PROCS` (%d) is not equal to the number of ginkgo processes being run (%d)",
test/e2e/e2e_suite_test.go:87: numProcesses = env.GetEnvInt("E2E_NUM_PROCS", 1, ginkgo.GinkgoLogr)
There was a problem hiding this comment.
Right, as far as I know @shmuelk is planning to have a follow up PR.
|
Signed-off-by: Revital Sur <eres@il.ibm.com>
elevran
left a comment
There was a problem hiding this comment.
Containerization and component-sharing are well-scoped - thanks.
See inline comments on the new copy of dumpPodsAndLogs/dumpContainerLogs.
| // dumpPodsAndLogs prints pod statuses and container logs for the given namespace | ||
| // to the Ginkgo writer. Call this before cleanup to ensure the information is | ||
| // available when CI tests fail. | ||
| func dumpPodsAndLogs(nsName string) { |
There was a problem hiding this comment.
This introducs a duplication of dumpPodsAndLogs and the helper below from test/e2e/utils_test.go:487, which he PR otherwise works to eliminate.
Moving both helpers into test/utils (alongside parallel.go) keeps the dedupe theme consistent across the diff. Note that the router's copy has slightly richer signatures (previous bool, explicit context) but the minimum useful shared shape is func DumpPodsAndLogs(nsName string) matching this version.
| }) | ||
| stream, err := req.Stream(testConfig.Context) | ||
| if err != nil { | ||
| ginkgo.GinkgoWriter.Printf("(failed to fetch logs: %v)\n", err) |
There was a problem hiding this comment.
nit:
when GetLogs/Stream fails (often because cleanup races and the pod is gone), the dump prints (failed to fetch logs: %v) without the pod/container context. Wrap with the pod/container names so an operator scanning a failure dump can tell which container failed. Same suggestion applies to the existing router copy in test/e2e/utils_test.go:586.
Signed-off-by: Revital Sur <eres@il.ibm.com>
| objects = append(objects, testutils.CreateObjsFromYaml(testConfig, docs, nsName)...) | ||
|
|
||
| podsInDeploymentsReady(objects) | ||
| if k8sContext != "" { |
There was a problem hiding this comment.
why do we remove this?
There was a problem hiding this comment.
This was the direct-NodePort path (the port-forward plus a second /readyz poll against coordinatorBaseURL()). Nothing exercises it anymore, all traffic goes through the Envoy gateway, so it was dead code. Readiness is still covered: podsInDeploymentsReady confirms the pod is up, and the gateway /readyz poll still guards against Envoy's STRICT_DNS resolution lagging the per-test Service. Removed coordinatorBaseURL/getCoordinatorPort too since they had no other callers.
| // DumpPodsAndLogs prints pod statuses and container logs for the given namespace | ||
| // to the Ginkgo writer. Call this before cleanup to ensure the information is | ||
| // available when CI tests fail. | ||
| func DumpPodsAndLogs(cfg *TestConfig, nsName string) { |
There was a problem hiding this comment.
do you need UT for this?
There was a problem hiding this comment.
Not sure about that. This is best-effort diagnostic output that runs on E2E failure, it has no return value, swallows all errors, and only affects how readable CI logs are, never a test result. It's exercised by the E2E suites themselves. Nothing else in test/utils (context, network, parallel, server, ...) is unit-tested either, so adding a UT just here would be inconsistent. A UT would mostly end up asserting on formatted column output, which is brittle and low-value. Happy to add one if you'd still like coverage, e.g. a fake.NewSimpleClientset case, but I'd lean against it.
|
|
||
| ``` | ||
| Client -> Coordinator -> Inference Gateway -> EPP -> vLLM Workers | ||
| Client -> Inference Gateway -> Coordinator -> Inference Gateway -> EPP -> vLLM Workers |
There was a problem hiding this comment.
I think the diagram would be clearer if we used a single double-ended arrow between the Inference Gateway and the Coordinator, rather than writing it out as Inference Gateway -> Coordinator -> Inference Gateway which is quite confusing.
Signed-off-by: Revital Sur <eres@il.ibm.com>
Signed-off-by: Revital Sur <eres@il.ibm.com> # Conflicts: # test/coordinator/e2e/coordinator/e2e_suite_test.go
Signed-off-by: Revital Sur <eres@il.ibm.com>
elevran
left a comment
There was a problem hiding this comment.
@revit13 please open a follow up issue and PR to determine if and what shared build and CICD code can be leveraged. I have concerns about the additional variables and targets that might be duplicated across GH actions and Makefiles.
| @@ -0,0 +1,106 @@ | |||
| name: CI - Coordinator Test | |||
There was a problem hiding this comment.
should CI for coordinator share the existing CICD files instead of dedicated actions?
Just wonder how much is duplicated and whether the can be combined instead of introducing new actions and merge gates.
| - .github/actions/docker-build-and-push/action.yml | ||
| - .github/actions/e2e-runner-setup/action.yml | ||
| - .github/workflows/ci-pr-checks.yaml | ||
| - '!Dockerfile.coordinator' |
There was a problem hiding this comment.
are these consistent with the previous items? None contain ! prefixes.
| @@ -1,23 +1,35 @@ | |||
| SHELL := /usr/bin/env bash | |||
There was a problem hiding this comment.
can you please confirm the need for maintaining a coordinator makefile vs inlining targets into existing makefiles?
What type of PR is this?
/kind test
What this PR does / why we need it:
Reworks how the coordinator's e2e tests run and removes duplication between the coordinator's deploy manifests and the main router's, fixing several bugs found along the way.
Containerize test-e2e-coordinator: the target now runs the whole suite (including kind create cluster) inside the builder container via docker run, matching the main router's test-e2e-run pattern, instead of executing directly on the host.
Share deploy components with the router: crds-gateway-api, crds-gie, vllm-encode, and vllm-prefill now reference the router's shared deploy/components/* instead of coordinator-local vendored/duplicated copies. vllm-decode intentionally stays coordinator-local (the router's decode carries a routing-sidecar the coordinator's pipeline doesn't use) with a comment explaining why.
Drop the unused Gateway API CRD install from the coordinator e2e suite — the coordinator never creates a Gateway/HTTPRoute object (it routes on an EPP-Phase header via a hand-rolled Envoy config), so only GIE CRDs are installed now.
Parameterize vllm-render: port and image are now ${VLLM_RENDER_PORT}/${VLLM_RENDER_IMAGE} (previously hardcoded 8082 and reusing ${VLLM_IMAGE}), and dropped unused PORT/POD_NAME/POD_NAMESPACE env vars from the container.
Bug fixes:
--force-dummy-tokenizer was being passed twice to the encode/prefill/decode simulator containers (baked into the base manifest and re-added by the simulator overlay patch).
Relative paths in the coordinator's Go e2e test package were off by one directory level, so kustomize/manifest lookups resolved to the wrong location.
image-build-epp called a script that doesn't exist (scripts/build-epp-image.sh); it now falls through to the existing generic image-build-% pattern.
Docs: README.coord.md gains a Table of Contents, documents test-e2e-coordinator, E2E_KEEP_CLUSTER_ON_FAILURE, accessing the kind cluster's kubeconfig after a preserved failure, and the full e2e environment-variable table.
Depends on #1601 — once that merges, further cleanup can be applied here (e.g. sharing the vllm-render component with the router too, the same way vllm-encode/vllm-prefill already are)
Which issue(s) this PR fixes:
#1877
Release note (write
NONEif no user-facing change):