Skip to content

Commit 5ae7594

Browse files
committed
feat: implement decision-based routing with plugin architecture
Signed-off-by: bitliu <[email protected]>
1 parent 51cefd8 commit 5ae7594

File tree

13 files changed

+1478
-445
lines changed

13 files changed

+1478
-445
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
name: Integration Test [Dynamic Config]
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
push:
8+
branches:
9+
- main
10+
workflow_dispatch: # Allow manual triggering
11+
12+
jobs:
13+
integration-test:
14+
runs-on: ubuntu-latest
15+
timeout-minutes: 60
16+
17+
steps:
18+
- name: Check out the repo
19+
uses: actions/checkout@v4
20+
21+
- name: Set up Go
22+
uses: actions/setup-go@v5
23+
with:
24+
go-version: '1.24'
25+
26+
- name: Set up Rust
27+
uses: actions-rust-lang/setup-rust-toolchain@v1
28+
with:
29+
toolchain: 1.90
30+
31+
- name: Install system dependencies
32+
run: |
33+
sudo apt-get update
34+
sudo apt-get install -y \
35+
make \
36+
curl \
37+
build-essential \
38+
pkg-config
39+
40+
- name: Install Kind
41+
run: |
42+
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.22.0/kind-linux-amd64
43+
chmod +x ./kind
44+
sudo mv ./kind /usr/local/bin/kind
45+
46+
- name: Install kubectl
47+
run: |
48+
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
49+
chmod +x kubectl
50+
sudo mv kubectl /usr/local/bin/kubectl
51+
52+
- name: Install Helm
53+
run: |
54+
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
55+
56+
- name: Download E2E test dependencies
57+
run: |
58+
cd e2e && go mod download
59+
60+
- name: Build E2E test binary
61+
run: |
62+
make build-e2e
63+
64+
- name: Run Dynamic Config E2E tests
65+
id: e2e-test
66+
run: |
67+
set +e # Don't exit on error, we want to capture the result
68+
make e2e-test E2E_PROFILE=dynamic-config E2E_VERBOSE=true E2E_KEEP_CLUSTER=false
69+
TEST_EXIT_CODE=$?
70+
echo "test_exit_code=${TEST_EXIT_CODE}" >> $GITHUB_OUTPUT
71+
exit ${TEST_EXIT_CODE}
72+
73+
- name: Upload test reports
74+
if: always()
75+
uses: actions/upload-artifact@v4
76+
with:
77+
name: test-reports-dynamic-config
78+
path: |
79+
test-report.json
80+
test-report.md
81+
semantic-router-logs.txt
82+
retention-days: 30
83+
84+
- name: Create test summary from report
85+
if: always()
86+
run: |
87+
if [ -f "test-report.md" ]; then
88+
echo "=== Reading test report from test-report.md ==="
89+
cat test-report.md >> $GITHUB_STEP_SUMMARY
90+
91+
# Add semantic-router logs section if available
92+
if [ -f "semantic-router-logs.txt" ]; then
93+
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
94+
95+
---
96+
97+
### 📝 Semantic Router Logs
98+
99+
<details>
100+
<summary>Click to view semantic-router logs</summary>
101+
102+
```
103+
EOF
104+
# Add first 500 lines of logs to summary (to avoid exceeding GitHub limits)
105+
head -n 500 semantic-router-logs.txt >> $GITHUB_STEP_SUMMARY
106+
107+
# Check if there are more lines
108+
TOTAL_LINES=$(wc -l < semantic-router-logs.txt)
109+
if [ "$TOTAL_LINES" -gt 500 ]; then
110+
cat >> $GITHUB_STEP_SUMMARY << EOF
111+
112+
... (showing first 500 lines of $TOTAL_LINES total lines)
113+
114+
📦 Full logs are available in the workflow artifacts: semantic-router-logs.txt
115+
EOF
116+
fi
117+
118+
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
119+
```
120+
121+
</details>
122+
EOF
123+
fi
124+
125+
# Add additional context
126+
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
127+
128+
---
129+
130+
### 📚 Additional Resources
131+
132+
- **Trigger:** ${{ github.event_name }}
133+
- **Branch:** `${{ github.ref_name }}`
134+
- **Commit:** `${{ github.sha }}`
135+
- **Workflow Run:** [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
136+
- [E2E Test Framework Documentation](https://github.com/${{ github.repository }}/tree/main/e2e)
137+
- [Dynamic Config Profile](https://github.com/${{ github.repository }}/tree/main/e2e/profiles/dynamic-config)
138+
139+
### 📦 Artifacts
140+
141+
- **test-report.json** - Detailed test results in JSON format
142+
- **test-report.md** - Human-readable test report
143+
- **semantic-router-logs.txt** - Complete semantic-router pod logs
144+
- All artifacts are retained for 30 days
145+
146+
### 🔧 Dynamic Config Profile
147+
148+
This test validates the Kubernetes CRD-based dynamic configuration feature:
149+
- IntelligentPool CRD for model configuration
150+
- IntelligentRoute CRD for routing decisions
151+
- Controller-runtime based reconciliation
152+
- Automatic configuration updates on CRD changes
153+
EOF
154+
else
155+
echo "⚠️ Test report file not found!" >> $GITHUB_STEP_SUMMARY
156+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{{- if .Values.rbac.create -}}
2+
apiVersion: rbac.authorization.k8s.io/v1
3+
kind: ClusterRole
4+
metadata:
5+
name: {{ include "semantic-router.fullname" . }}
6+
labels:
7+
{{- include "semantic-router.labels" . | nindent 4 }}
8+
rules:
9+
# Permissions for IntelligentPool CRD
10+
- apiGroups:
11+
- vllm.ai
12+
resources:
13+
- intelligentpools
14+
verbs:
15+
- get
16+
- list
17+
- watch
18+
- apiGroups:
19+
- vllm.ai
20+
resources:
21+
- intelligentpools/status
22+
verbs:
23+
- get
24+
# Permissions for IntelligentRoute CRD
25+
- apiGroups:
26+
- vllm.ai
27+
resources:
28+
- intelligentroutes
29+
verbs:
30+
- get
31+
- list
32+
- watch
33+
- apiGroups:
34+
- vllm.ai
35+
resources:
36+
- intelligentroutes/status
37+
verbs:
38+
- get
39+
{{- end }}
40+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{{- if .Values.rbac.create -}}
2+
apiVersion: rbac.authorization.k8s.io/v1
3+
kind: ClusterRoleBinding
4+
metadata:
5+
name: {{ include "semantic-router.fullname" . }}
6+
labels:
7+
{{- include "semantic-router.labels" . | nindent 4 }}
8+
roleRef:
9+
apiGroup: rbac.authorization.k8s.io
10+
kind: ClusterRole
11+
name: {{ include "semantic-router.fullname" . }}
12+
subjects:
13+
- kind: ServiceAccount
14+
name: {{ include "semantic-router.serviceAccountName" . }}
15+
namespace: {{ include "semantic-router.namespace" . }}
16+
{{- end }}
17+

deploy/helm/semantic-router/values.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ serviceAccount:
4242
# -- The name of the service account to use
4343
name: ""
4444

45+
# RBAC configuration
46+
rbac:
47+
# -- Create RBAC resources (ClusterRole and ClusterRoleBinding)
48+
create: true
49+
4550
# Pod annotations
4651
podAnnotations: {}
4752

e2e/cmd/e2e/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/vllm-project/semantic-router/e2e/pkg/banner"
1111
"github.com/vllm-project/semantic-router/e2e/pkg/framework"
1212
aigateway "github.com/vllm-project/semantic-router/e2e/profiles/ai-gateway"
13+
dynamicconfig "github.com/vllm-project/semantic-router/e2e/profiles/dynamic-config"
1314

1415
// Import profiles to register test cases
1516
_ "github.com/vllm-project/semantic-router/e2e/profiles/ai-gateway"
@@ -96,6 +97,8 @@ func getProfile(name string) (framework.Profile, error) {
9697
switch name {
9798
case "ai-gateway":
9899
return aigateway.NewProfile(), nil
100+
case "dynamic-config":
101+
return dynamicconfig.NewProfile(), nil
99102
// Add more profiles here as they are implemented
100103
// case "istio":
101104
// return istio.NewProfile(), nil
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
apiVersion: vllm.ai/v1alpha1
2+
kind: IntelligentPool
3+
metadata:
4+
name: ai-gateway-pool
5+
namespace: default
6+
spec:
7+
defaultModel: "base-model"
8+
models:
9+
- name: "base-model"
10+
reasoningFamily: "qwen3"
11+
piiPolicy:
12+
allowByDefault: false
13+
loras:
14+
- name: "science-expert"
15+
description: "Specialized for science domains: biology, chemistry, physics, health, engineering"
16+
- name: "social-expert"
17+
description: "Optimized for social sciences: business, economics"
18+
- name: "math-expert"
19+
description: "Fine-tuned for mathematics and quantitative reasoning"
20+
- name: "law-expert"
21+
description: "Specialized for legal questions and law-related topics"
22+
- name: "humanities-expert"
23+
description: "Optimized for humanities: psychology, history, philosophy"
24+
- name: "general-expert"
25+
description: "General-purpose adapter for diverse topics"
26+

0 commit comments

Comments
 (0)