Skip to content

Commit 5ec9f43

Browse files
szedan-rhclaude
andauthored
Fix OpenShift Dashboard Playground OpenWebUI Connection (#634)
* fix(dashboard): add OpenShift hostname detection for OpenWebUI playground Apply PlaygroundPage.tsx patch to detect OpenShift route hostnames and automatically construct the correct OpenWebUI URL for the playground iframe. This fixes the 'localhost refused to connect' error when accessing the playground through the dashboard on OpenShift deployments. Changes: - Update PlaygroundPage.tsx to detect OpenShift hostname patterns - Dynamically construct OpenWebUI route URL based on dashboard hostname - Add BuildConfig for building custom dashboard in OpenShift - Fallback to /embedded/openwebui/ for local development Signed-off-by: szedan <[email protected]> * feat: enhance OpenShift deployment with one-click observability stack This commit improves the OpenShift deployment workflow by implementing a streamlined, fully automated deployment process with comprehensive observability support. Key changes: **Dashboard Build Support:** - Add dashboard/Dockerfile for OpenShift binary builds - Multi-stage build: Node.js frontend + Go backend - Enables building dashboard from local source without Docker daemon - Includes PlaygroundPage fix for dynamic OpenWebUI URL detection **Deployment Script Enhancements:** - Add --no-observability flag for minimal core-only deployments - Implement full observability stack deployment (Dashboard, OpenWebUI, Grafana, Prometheus) - Add inline OpenWebUI PVC creation (fixes missing PVC issue) - Improve deployment feedback with component-specific success messages - Add help flag with usage documentation **Cleanup Script Improvements:** - Add comprehensive observability resource cleanup - Include dashboard-custom buildconfig and imagestream cleanup - Update resource lists to match new deployment structure **Cross-Cluster Portability:** - Remove hardcoded hostname from openwebui/route.yaml - Enable automatic route hostname generation per cluster - Improve cluster portability for multi-cluster deployments **Documentation Cleanup:** - Remove outdated README files (dashboard, openwebui, observability) - Remove deprecated build-custom-dashboard.sh script - Remove obsolete PlaygroundPage.tsx.patch file - Update main README.md with one-click deployment instructions - Add binary build workflow documentation **Testing:** - End-to-end deployment verified on OpenShift 4.x - Cleanup and redeploy tested successfully - All pods running and routes accessible Fixes: Dashboard playground "localhost refused to connect" error Related: PlaygroundPage now uses dynamic hostname detection 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> Signed-off-by: szedan <[email protected]> * fix: add blank lines around lists in OpenShift README for markdown linting (MD032) Resolves markdown linting errors by adding blank lines before list sections at lines 254, 261, and 268 in deploy/openshift/README.md as required by markdownlint MD032 rule. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> Signed-off-by: szedan <[email protected]> * fix(openshift): make vLLM endpoint IPs dynamic and lower classification threshold This commit addresses two critical issues for OpenShift deployment portability and query handling: **Dynamic vLLM Endpoint Configuration:** - Replace hardcoded ClusterIPs with dynamic placeholders (DYNAMIC_MODEL_A_IP, DYNAMIC_MODEL_B_IP) - Update deploy script to substitute placeholders with actual discovered ClusterIPs - Remove fallback logic that relied on old hardcoded IPs - Improve error handling when IP substitution fails - Makes deployments truly portable across different OpenShift clusters **Classification Threshold Adjustment:** - Lower category classifier threshold from 0.6 to 0.45 - Allows simple queries like "what is cat?" (confidence ~0.45) to be classified - Previously, queries below 0.6 threshold resulted in empty category and routing failures - Add default_model configuration for fallback routing **Files Changed:** - deploy/openshift/config-openshift.yaml: Replace hardcoded IPs with DYNAMIC_* placeholders, lower threshold, add default_model - deploy/openshift/deploy-to-openshift.sh: Simplify sed patterns for IP replacement, improve error handling **Testing:** - Verified dynamic IP discovery during deployment - Tested queries successfully routed to vLLM backends - All pre-commit hooks passing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> Signed-off-by: szedan <[email protected]> * feat(openshift): enable GPU for vLLM models and lower classification threshold Changes: - Enable CUDA GPU for both vLLM model deployments (Model-A and Model-B) - Changed --device from "cpu" to "cuda" - Added nvidia.com/gpu: 1 resource requests and limits - Lower category classification threshold from 0.45 to 0.35 - Fixes issue where queries like "what is physics?" (confidence 0.3581) were failing classification - Empty category results in no model routing, causing request failures - New threshold allows more queries to be successfully classified and routed Tested on OpenShift cluster: - Both models successfully loading on CUDA - Classification now working for previously failing queries 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> Signed-off-by: szedan <[email protected]> --------- Signed-off-by: szedan <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent f193a19 commit 5ec9f43

File tree

13 files changed

+356
-767
lines changed

13 files changed

+356
-767
lines changed

dashboard/Dockerfile

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Build frontend
2+
FROM node:18-alpine AS frontend-builder
3+
WORKDIR /app/frontend
4+
COPY frontend/package*.json ./
5+
RUN npm ci
6+
COPY frontend/ ./
7+
RUN npm run build
8+
9+
# Build backend
10+
FROM golang:1.21-alpine AS backend-builder
11+
WORKDIR /app/backend
12+
COPY backend/go.* ./
13+
RUN go mod download
14+
COPY backend/ ./
15+
RUN CGO_ENABLED=0 GOOS=linux go build -o dashboard-server .
16+
17+
# Final image
18+
FROM alpine:3.18
19+
RUN apk add --no-cache ca-certificates
20+
WORKDIR /app
21+
COPY --from=backend-builder /app/backend/dashboard-server .
22+
COPY --from=frontend-builder /app/frontend/dist ./frontend
23+
ENV DASHBOARD_STATIC_DIR=./frontend
24+
EXPOSE 8700
25+
CMD ["./dashboard-server"]

dashboard/frontend/src/pages/PlaygroundPage.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@ import React, { useState, useEffect } from 'react'
22
import styles from './PlaygroundPage.module.css'
33

44
const PlaygroundPage: React.FC = () => {
5-
const [openWebUIUrl] = useState('http://localhost:3001')
5+
// Detect OpenWebUI URL based on current hostname
6+
// Assumes openwebui and dashboard have matching hostname patterns
7+
const getOpenWebUIUrl = () => {
8+
const hostname = window.location.hostname
9+
const openwebuiHost = hostname.replace('dashboard', 'openwebui')
10+
return `${window.location.protocol}//${openwebuiHost}`
11+
}
12+
13+
const [openWebUIUrl] = useState(getOpenWebUIUrl())
614
const [currentUrl, setCurrentUrl] = useState('')
715

816
// Auto-load on mount

deploy/openshift/README.md

Lines changed: 153 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,54 @@ This directory contains OpenShift-specific deployment manifests for the vLLM Sem
99
- OpenShift cluster access
1010
- `oc` CLI tool configured and logged in
1111
- Cluster admin privileges (or permissions to create namespaces and routes)
12+
- Local source code (for dashboard build)
1213

13-
### Automated Deployment (Recommended)
14+
### One-Click Full Deployment (Recommended)
1415

15-
The deployment script automatically handles everything including dynamic IP configuration:
16+
Deploy the complete stack including semantic-router, vLLM models, and all observability components:
1617

1718
```bash
1819
cd deploy/openshift
1920
./deploy-to-openshift.sh
2021
```
2122

22-
This script will:
23+
This script will deploy:
24+
25+
**Core Components:**
2326

2427
- ✅ Build the llm-katan image from Dockerfile
2528
- ✅ Create namespace and PVCs
26-
- ✅ Deploy vLLM model services (model-a and model-b)
29+
- ✅ Deploy vLLM model services (Model-A and Model-B)
2730
- ✅ Auto-discover Kubernetes service ClusterIPs
2831
- ✅ Generate configuration with actual IPs (portable across clusters)
29-
- ✅ Deploy semantic-router with Envoy proxy
32+
- ✅ Deploy semantic-router with Envoy proxy sidecar
3033
- ✅ Create OpenShift routes for external access
3134

35+
**Observability Stack:**
36+
37+
- ✅ Dashboard (built from local source with PlaygroundPage fix)
38+
- ✅ OpenWebUI playground for testing models
39+
- ✅ Grafana for metrics visualization
40+
- ✅ Prometheus for metrics collection
41+
42+
### Minimal Deployment (Core Only)
43+
44+
If you only want the core semantic-router and vLLM models without observability:
45+
46+
```bash
47+
cd deploy/openshift
48+
./deploy-to-openshift.sh --no-observability
49+
```
50+
51+
This deploys only the core components without Dashboard, OpenWebUI, Grafana, and Prometheus.
52+
53+
### Command Line Options
54+
55+
| Flag | Description |
56+
|------|-------------|
57+
| `--no-observability` | Skip deploying Dashboard, OpenWebUI, Grafana, and Prometheus |
58+
| `--help`, `-h` | Show help message |
59+
3260
### Manual Deployment (Advanced)
3361

3462
If you prefer manual deployment or need to customize:
@@ -53,23 +81,67 @@ If you prefer manual deployment or need to customize:
5381

5482
4. **Note:** You'll need to manually configure ClusterIPs in `config-openshift.yaml`
5583

84+
## How Dashboard Build Works
85+
86+
The deployment script uses OpenShift's **binary build** approach for the dashboard:
87+
88+
1. Creates a BuildConfig with Docker strategy
89+
2. Uploads the local `dashboard/` directory as build source
90+
3. Builds the image inside OpenShift (no local Docker required)
91+
4. Pushes to OpenShift internal registry
92+
5. Deploys using the built image
93+
94+
### Why Binary Build?
95+
96+
- ✅ No local Docker daemon required
97+
- ✅ Works on any machine with `oc` CLI
98+
- ✅ Builds with your local code changes (including PlaygroundPage fix)
99+
- ✅ Automatically integrated with OpenShift registry
100+
- ✅ Works across different OpenShift clusters
101+
102+
### Updating Dashboard
103+
104+
If you make changes to the dashboard code, rebuild and redeploy:
105+
106+
```bash
107+
# Rebuild dashboard image from local source
108+
cd dashboard
109+
oc start-build dashboard-custom --from-dir=. --follow -n vllm-semantic-router-system
110+
111+
# Restart deployment to use new image
112+
oc rollout restart deployment/dashboard -n vllm-semantic-router-system
113+
```
114+
56115
## Accessing Services
57116

58-
After deployment, the services will be accessible via OpenShift Routes:
117+
After deployment, the script will display URLs for all services. Routes are automatically generated with cluster-appropriate hostnames.
59118

60119
### Get Route URLs
61120

62121
```bash
63-
# Classification API (HTTP REST)
122+
# Core Services
64123
oc get route semantic-router-api -n vllm-semantic-router-system -o jsonpath='{.spec.host}'
65-
66-
# gRPC API
67124
oc get route semantic-router-grpc -n vllm-semantic-router-system -o jsonpath='{.spec.host}'
68-
69-
# Metrics
70125
oc get route semantic-router-metrics -n vllm-semantic-router-system -o jsonpath='{.spec.host}'
126+
127+
# Observability (if deployed)
128+
oc get route dashboard -n vllm-semantic-router-system -o jsonpath='{.spec.host}'
129+
oc get route openwebui -n vllm-semantic-router-system -o jsonpath='{.spec.host}'
130+
oc get route grafana -n vllm-semantic-router-system -o jsonpath='{.spec.host}'
131+
oc get route prometheus -n vllm-semantic-router-system -o jsonpath='{.spec.host}'
132+
```
133+
134+
### Dashboard Playground
135+
136+
Access the OpenWebUI playground through the dashboard:
137+
138+
```bash
139+
DASHBOARD_URL=$(oc get route dashboard -n vllm-semantic-router-system -o jsonpath='{.spec.host}')
140+
echo "Playground: https://$DASHBOARD_URL/playground"
71141
```
72142

143+
The playground automatically detects the OpenWebUI URL by replacing `dashboard` with `openwebui` in the hostname - no configuration needed!
144+
73145
### Example Usage
74146

75147
```bash
@@ -133,20 +205,82 @@ curl https://$METRICS_ROUTE/metrics
133205

134206
## Cleanup
135207

136-
Remove all resources:
208+
### Quick Cleanup
209+
210+
Remove the entire namespace and all resources (recommended):
137211

138212
```bash
139-
oc delete -k deploy/openshift/
213+
cd deploy/openshift
214+
./cleanup-openshift.sh
140215
```
141216

142-
Or remove individual components:
217+
If not already logged in to OpenShift:
143218

144219
```bash
145-
oc delete -f deploy/openshift/routes.yaml
146-
oc delete -f deploy/openshift/service.yaml
147-
oc delete -f deploy/openshift/deployment.yaml
148-
oc delete -f deploy/openshift/pvc.yaml
149-
oc delete -f deploy/openshift/namespace.yaml
220+
oc login <your-cluster-url>
221+
./cleanup-openshift.sh
222+
```
223+
224+
### Cleanup Options
225+
226+
The cleanup script supports different cleanup levels:
227+
228+
| Level | What Gets Deleted | What's Preserved |
229+
|-------|------------------|------------------|
230+
| `deployment` | Deployments, services, routes, configmaps, buildconfigs | Namespace, PVCs |
231+
| `namespace` (default) | Entire namespace and all resources | Nothing |
232+
| `all` | Namespace + cluster-wide resources | Nothing |
233+
234+
**Examples:**
235+
236+
```bash
237+
# Remove everything (default)
238+
./cleanup-openshift.sh
239+
240+
# Keep namespace and PVCs, remove only deployments
241+
./cleanup-openshift.sh --level deployment
242+
243+
# Dry run to see what would be deleted
244+
./cleanup-openshift.sh --dry-run
245+
246+
# Force cleanup without confirmation
247+
./cleanup-openshift.sh --force
248+
```
249+
250+
### What Gets Cleaned Up
251+
252+
The cleanup script removes:
253+
254+
**Core Components:**
255+
256+
- semantic-router deployment
257+
- vLLM model deployments (Model-A, Model-B)
258+
- All services and routes
259+
- ConfigMaps (router config, envoy config)
260+
- BuildConfigs and ImageStreams (llm-katan, dashboard-custom)
261+
262+
**Observability Stack:**
263+
264+
- Dashboard deployment
265+
- OpenWebUI deployment
266+
- Grafana deployment
267+
- Prometheus deployment
268+
- All related services, routes, and configmaps
269+
270+
**Storage (namespace level only):**
271+
272+
- PVCs for models and cache
273+
274+
### Manual Cleanup
275+
276+
If you prefer manual cleanup:
277+
278+
```bash
279+
# Delete entire namespace (removes everything)
280+
oc delete namespace vllm-semantic-router-system
281+
282+
# Or delete specific components
283+
oc delete deployment,service,route,configmap,buildconfig,imagestream --all -n vllm-semantic-router-system
150284
```
151285

152286
## Troubleshooting

deploy/openshift/cleanup-openshift.sh

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ OPTIONS:
6161
-h, --help Show this help message
6262
6363
CLEANUP LEVELS:
64-
deployment - Remove deployment, services, routes, configmap (keep namespace and PVC)
65-
namespace - Remove entire namespace and all resources (default)
64+
deployment - Remove deployments, services, routes, configmaps, buildconfigs (keep namespace and PVCs)
65+
Includes: semantic-router, vLLM models, dashboard, OpenWebUI, Grafana, Prometheus
66+
namespace - Remove entire namespace and all resources including PVCs (default)
6667
all - Remove namespace and any cluster-wide resources
6768
6869
EXAMPLES:
@@ -254,6 +255,18 @@ show_current_resources() {
254255
echo "=== ConfigMaps ==="
255256
oc get configmaps -n "$NAMESPACE" 2>/dev/null || echo "No configmaps found"
256257

258+
echo ""
259+
echo "=== BuildConfigs ==="
260+
oc get buildconfig -n "$NAMESPACE" 2>/dev/null || echo "No buildconfigs found"
261+
262+
echo ""
263+
echo "=== ImageStreams ==="
264+
oc get imagestream -n "$NAMESPACE" 2>/dev/null || echo "No imagestreams found"
265+
266+
echo ""
267+
echo "=== Deployments ==="
268+
oc get deployments -n "$NAMESPACE" 2>/dev/null || echo "No deployments found"
269+
257270
echo ""
258271
}
259272

@@ -270,10 +283,12 @@ confirm_cleanup() {
270283

271284
case "$CLEANUP_LEVEL" in
272285
"deployment")
273-
log "WARN" "Will delete: deployment, services, routes, configmaps (keeping namespace and PVCs)"
286+
log "WARN" "Will delete: deployments, services, routes, configmaps, buildconfigs (keeping namespace and PVCs)"
287+
log "WARN" "Components: semantic-router, vLLM models, dashboard, OpenWebUI, Grafana, Prometheus"
274288
;;
275289
"namespace")
276290
log "WARN" "Will delete: entire namespace and all resources including PVCs"
291+
log "WARN" "This removes ALL components: core + observability stack"
277292
;;
278293
"all")
279294
log "WARN" "Will delete: namespace and any cluster-wide resources"
@@ -304,13 +319,43 @@ cleanup_deployment() {
304319

305320
# Delete specific resources but keep namespace and PVCs
306321
local resources=(
322+
# Core semantic-router resources
307323
"deployment/semantic-router"
324+
"deployment/vllm-model-a"
325+
"deployment/vllm-model-b"
308326
"service/semantic-router"
309327
"service/semantic-router-metrics"
328+
"service/vllm-model-a"
329+
"service/vllm-model-b"
310330
"route/semantic-router-api"
311331
"route/semantic-router-grpc"
312332
"route/semantic-router-metrics"
333+
"route/envoy-http"
334+
"route/envoy-admin"
313335
"configmap/semantic-router-config"
336+
"configmap/envoy-config"
337+
"buildconfig/llm-katan"
338+
"imagestream/llm-katan"
339+
"imagestream/python"
340+
341+
# Observability resources
342+
"deployment/dashboard"
343+
"deployment/openwebui"
344+
"deployment/grafana"
345+
"deployment/prometheus"
346+
"service/dashboard"
347+
"service/openwebui"
348+
"service/grafana"
349+
"service/prometheus"
350+
"route/dashboard"
351+
"route/openwebui"
352+
"route/grafana"
353+
"route/prometheus"
354+
"configmap/dashboard-config"
355+
"configmap/grafana-config"
356+
"configmap/prometheus-config"
357+
"buildconfig/dashboard-custom"
358+
"imagestream/dashboard-custom"
314359
)
315360

316361
for resource in "${resources[@]}"; do

deploy/openshift/config-openshift.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ prompt_guard:
3232
# This makes deployment portable across different OpenShift clusters
3333
vllm_endpoints:
3434
- name: "model-a-endpoint"
35-
address: "172.30.64.134" # PLACEHOLDER - will be replaced with actual ClusterIP
35+
address: "DYNAMIC_MODEL_A_IP" # model-a-ip - will be replaced with actual ClusterIP
3636
port: 8000
3737
weight: 1
3838
- name: "model-b-endpoint"
39-
address: "172.30.116.177" # PLACEHOLDER - will be replaced with actual ClusterIP
39+
address: "DYNAMIC_MODEL_B_IP" # model-b-ip - will be replaced with actual ClusterIP
4040
port: 8001
4141
weight: 1
4242

@@ -59,7 +59,7 @@ classifier:
5959
category_model:
6060
model_id: "models/category_classifier_modernbert-base_model"
6161
use_modernbert: true
62-
threshold: 0.6
62+
threshold: 0.35 # Lowered from 0.45 to handle queries like "what is physics?" (confidence 0.3581)
6363
use_cpu: true
6464
category_mapping_path: "models/category_classifier_modernbert-base_model/category_mapping.json"
6565
pii_model:

0 commit comments

Comments
 (0)