Skip to content

Commit 4e2ee29

Browse files
szedan-rhrootfsJaredforReal
authored
fix: Grafana monitoring page iframe embedding and dynamic cluster configuration (#642)
Fixes multiple Grafana integration issues in the dashboard: 405 login errors, localhost redirects, iframe reload loops, and hardcoded cluster URLs. Changes: - dashboard/backend/router/router.go: Enhanced login routing to detect Grafana requests via Content-Type/Referer headers - dashboard/frontend/src/pages/MonitoringPage.tsx: Removed two-step load causing redirect loops, direct dashboard loading via goto endpoint - deploy/openshift/observability/grafana/deployment.yaml: Added proper server config with dynamic route URL placeholder - deploy/openshift/deploy-to-openshift.sh: Dynamic route URL substitution for cluster-agnostic deployments Signed-off-by: Senan Zedan <[email protected]> Co-authored-by: Huamin Chen <[email protected]> Co-authored-by: Jared <[email protected]>
1 parent 99b6184 commit 4e2ee29

File tree

6 files changed

+225
-34
lines changed

6 files changed

+225
-34
lines changed

dashboard/backend/router/router.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,25 @@ func Setup(cfg *config.Config) *http.ServeMux {
201201
if middleware.HandleCORSPreflight(w, r) {
202202
return
203203
}
204-
log.Printf("Proxying Chat UI login: %s %s", r.Method, r.URL.Path)
204+
// Check if this is a Grafana login request by:
205+
// 1. Query parameter redirectTo with "goto" (GET requests)
206+
// 2. Referer header containing "/embedded/grafana" or "/monitoring"
207+
// 3. Content-Type: application/json (Grafana uses JSON for login POST)
208+
redirectTo := r.URL.Query().Get("redirectTo")
209+
referer := r.Header.Get("Referer")
210+
contentType := r.Header.Get("Content-Type")
211+
212+
isGrafanaRequest := (redirectTo != "" && strings.Contains(redirectTo, "goto")) ||
213+
strings.Contains(referer, "/embedded/grafana") ||
214+
strings.Contains(referer, "/monitoring") ||
215+
strings.Contains(contentType, "application/json")
216+
217+
if isGrafanaRequest && grafanaStaticProxy != nil {
218+
log.Printf("Proxying Grafana login: %s %s (redirectTo=%s, referer=%s, contentType=%s)", r.Method, r.URL.Path, redirectTo, referer, contentType)
219+
grafanaStaticProxy.ServeHTTP(w, r)
220+
return
221+
}
222+
log.Printf("Proxying Chat UI login: %s %s (contentType=%s)", r.Method, r.URL.Path, contentType)
205223
chatUIProxy.ServeHTTP(w, r)
206224
})
207225
mux.HandleFunc("/logout", func(w http.ResponseWriter, r *http.Request) {

dashboard/frontend/src/pages/MonitoringPage.tsx

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -31,38 +31,15 @@ const MonitoringPage: React.FC = () => {
3131
return () => observer.disconnect()
3232
}, [theme])
3333

34-
// Build initial Grafana URL - load the root path first
35-
const buildInitialGrafanaUrl = () => {
36-
// Start with Grafana root path
37-
const url = `/embedded/grafana/?orgId=1&theme=${theme}`
38-
console.log('Initial Grafana URL:', url)
39-
return url
40-
}
41-
42-
// Build dashboard URL using goto endpoint - this is what Grafana uses internally
43-
const buildDashboardUrl = () => {
44-
// Use Grafana's goto endpoint to navigate by UID
45-
// This mimics the internal navigation when clicking Home
34+
// Build Grafana dashboard URL directly
35+
const buildGrafanaUrl = () => {
36+
// Load the dashboard directly using the goto endpoint
37+
// This is the cleanest approach and avoids redirect loops
4638
const url = `/embedded/grafana/goto/llm-router-metrics?orgId=1&theme=${theme}&refresh=30s`
47-
console.log('Dashboard goto URL:', url)
39+
console.log('Grafana URL:', url)
4840
return url
4941
}
5042

51-
// Add effect to handle automatic redirect to dashboard
52-
useEffect(() => {
53-
// After initial page load, wait a bit then redirect to dashboard using goto
54-
const timer = setTimeout(() => {
55-
if (iframeRef.current) {
56-
console.log('Redirecting to dashboard using goto...')
57-
// Use goto endpoint to navigate to dashboard (mimics clicking Home)
58-
iframeRef.current.src = buildDashboardUrl()
59-
}
60-
setLoading(false)
61-
}, 100) // Wait 0.1 seconds after initial load
62-
63-
return () => clearTimeout(timer)
64-
}, [theme])
65-
6643

6744

6845
const handleIframeLoad = () => {
@@ -95,7 +72,7 @@ const MonitoringPage: React.FC = () => {
9572
<iframe
9673
ref={iframeRef}
9774
key={`grafana-${theme}`}
98-
src={buildInitialGrafanaUrl()}
75+
src={buildGrafanaUrl()}
9976
className={styles.iframe}
10077
title="Grafana Dashboard"
10178
allowFullScreen

deploy/openshift/dashboard/dashboard-deployment.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ data:
1212
TARGET_ROUTER_METRICS_URL: "http://semantic-router:9190/metrics"
1313
TARGET_OPENWEBUI_URL: "http://openwebui:3000"
1414
TARGET_CHATUI_URL: "http://chatui:3000"
15-
TARGET_JAEGER_URL: "http://jaeger:16686"
1615
ROUTER_CONFIG_PATH: "/app/config/config.yaml"
1716

1817
---

deploy/openshift/deploy-to-openshift.sh

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ success "Dynamic config generated with IPs: Model-A=$MODEL_A_IP, Model-B=$MODEL_
204204
log "Creating ConfigMaps with dynamic IPs..."
205205
oc create configmap semantic-router-config \
206206
--from-file=config.yaml="$TEMP_CONFIG" \
207+
--from-file=tools_db.json="$SCRIPT_DIR/tools_db.json" \
207208
-n "$NAMESPACE" --dry-run=client -o yaml | oc apply -f -
208209

209210
oc create configmap envoy-config \
@@ -346,10 +347,51 @@ EOF
346347
oc apply -f "$SCRIPT_DIR/openwebui/route.yaml" -n "$NAMESPACE"
347348
success "OpenWebUI deployed"
348349

349-
# Deploy Grafana
350+
# Deploy Grafana with dynamic route URL
350351
log "Deploying Grafana..."
351-
oc apply -f "$SCRIPT_DIR/observability/grafana/" -n "$NAMESPACE"
352-
success "Grafana deployed"
352+
353+
# First apply Grafana resources to create the route
354+
oc apply -f "$SCRIPT_DIR/observability/grafana/pvc.yaml" -n "$NAMESPACE" 2>/dev/null || true
355+
oc apply -f "$SCRIPT_DIR/observability/grafana/service.yaml" -n "$NAMESPACE" 2>/dev/null || true
356+
oc apply -f "$SCRIPT_DIR/observability/grafana/route.yaml" -n "$NAMESPACE" 2>/dev/null || true
357+
oc apply -f "$SCRIPT_DIR/observability/grafana/configmaps.yaml" -n "$NAMESPACE" 2>/dev/null || true
358+
359+
# Wait for route to be created and get its URL
360+
log "Waiting for Grafana route to be created..."
361+
for i in {1..30}; do
362+
GRAFANA_ROUTE_URL=$(oc get route grafana -n "$NAMESPACE" -o jsonpath='{.spec.host}' 2>/dev/null || echo "")
363+
364+
if [[ -n "$GRAFANA_ROUTE_URL" ]]; then
365+
GRAFANA_ROUTE_URL="https://$GRAFANA_ROUTE_URL"
366+
success "Grafana route URL: $GRAFANA_ROUTE_URL"
367+
break
368+
fi
369+
370+
if [[ $i -eq 30 ]]; then
371+
error "Timeout waiting for Grafana route"
372+
exit 1
373+
fi
374+
375+
sleep 2
376+
done
377+
378+
# Generate Grafana deployment with dynamic route URL
379+
log "Generating Grafana deployment with dynamic route URL..."
380+
TEMP_GRAFANA_DEPLOYMENT="/tmp/grafana-deployment-dynamic.yaml"
381+
sed "s|DYNAMIC_GRAFANA_ROUTE_URL|$GRAFANA_ROUTE_URL|g" \
382+
"$SCRIPT_DIR/observability/grafana/deployment.yaml" > "$TEMP_GRAFANA_DEPLOYMENT"
383+
384+
# Verify the URL was substituted
385+
if ! grep -q "$GRAFANA_ROUTE_URL" "$TEMP_GRAFANA_DEPLOYMENT"; then
386+
error "Grafana route URL substitution failed!"
387+
exit 1
388+
fi
389+
390+
# Apply Grafana deployment with dynamic URL
391+
oc apply -f "$TEMP_GRAFANA_DEPLOYMENT" -n "$NAMESPACE"
392+
rm -f "$TEMP_GRAFANA_DEPLOYMENT"
393+
394+
success "Grafana deployed with dynamic route URL: $GRAFANA_ROUTE_URL"
353395

354396
# Deploy Prometheus
355397
log "Deploying Prometheus..."

deploy/openshift/observability/grafana/deployment.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@ spec:
4848
value: ""
4949
- name: GF_PATHS_PROVISIONING
5050
value: /etc/grafana/provisioning
51+
- name: GF_SERVER_SERVE_FROM_SUB_PATH
52+
value: "true"
53+
- name: GF_SERVER_ROOT_URL
54+
value: "DYNAMIC_GRAFANA_ROUTE_URL"
55+
- name: GF_SERVER_PROTOCOL
56+
value: "http"
57+
- name: GF_SECURITY_ALLOW_EMBEDDING
58+
value: "true"
59+
- name: GF_AUTH_ANONYMOUS_ENABLED
60+
value: "true"
61+
- name: GF_AUTH_ANONYMOUS_ORG_ROLE
62+
value: "Viewer"
5163
volumeMounts:
5264
- name: storage
5365
mountPath: /var/lib/grafana

deploy/openshift/tools_db.json

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
[
2+
{
3+
"tool": {
4+
"type": "function",
5+
"function": {
6+
"name": "get_weather",
7+
"description": "Get current weather information for a location",
8+
"parameters": {
9+
"type": "object",
10+
"properties": {
11+
"location": {
12+
"type": "string",
13+
"description": "The city and state, e.g. San Francisco, CA"
14+
},
15+
"unit": {
16+
"type": "string",
17+
"enum": ["celsius", "fahrenheit"],
18+
"description": "Temperature unit"
19+
}
20+
},
21+
"required": ["location"]
22+
}
23+
}
24+
},
25+
"description": "Get current weather information, temperature, conditions, forecast for any location, city, or place. Check weather today, now, current conditions, temperature, rain, sun, cloudy, hot, cold, storm, snow",
26+
"category": "weather",
27+
"tags": ["weather", "temperature", "forecast", "climate"]
28+
},
29+
{
30+
"tool": {
31+
"type": "function",
32+
"function": {
33+
"name": "search_web",
34+
"description": "Search the web for information",
35+
"parameters": {
36+
"type": "object",
37+
"properties": {
38+
"query": {
39+
"type": "string",
40+
"description": "The search query"
41+
},
42+
"num_results": {
43+
"type": "integer",
44+
"description": "Number of results to return",
45+
"default": 5
46+
}
47+
},
48+
"required": ["query"]
49+
}
50+
}
51+
},
52+
"description": "Search the internet, web search, find information online, browse web content, lookup, research, google, find answers, discover, investigate",
53+
"category": "search",
54+
"tags": ["search", "web", "internet", "information", "browse"]
55+
},
56+
{
57+
"tool": {
58+
"type": "function",
59+
"function": {
60+
"name": "calculate",
61+
"description": "Perform mathematical calculations",
62+
"parameters": {
63+
"type": "object",
64+
"properties": {
65+
"expression": {
66+
"type": "string",
67+
"description": "Mathematical expression to evaluate"
68+
}
69+
},
70+
"required": ["expression"]
71+
}
72+
}
73+
},
74+
"description": "Calculate mathematical expressions, solve math problems, arithmetic operations, compute numbers, addition, subtraction, multiplication, division, equations, formula",
75+
"category": "math",
76+
"tags": ["math", "calculation", "arithmetic", "compute", "numbers"]
77+
},
78+
{
79+
"tool": {
80+
"type": "function",
81+
"function": {
82+
"name": "send_email",
83+
"description": "Send an email message",
84+
"parameters": {
85+
"type": "object",
86+
"properties": {
87+
"to": {
88+
"type": "string",
89+
"description": "Recipient email address"
90+
},
91+
"subject": {
92+
"type": "string",
93+
"description": "Email subject"
94+
},
95+
"body": {
96+
"type": "string",
97+
"description": "Email body content"
98+
}
99+
},
100+
"required": ["to", "subject", "body"]
101+
}
102+
}
103+
},
104+
"description": "Send email messages, email communication, contact people via email, mail, message, correspondence, notify, inform",
105+
"category": "communication",
106+
"tags": ["email", "send", "communication", "message", "contact"]
107+
},
108+
{
109+
"tool": {
110+
"type": "function",
111+
"function": {
112+
"name": "create_calendar_event",
113+
"description": "Create a new calendar event or appointment",
114+
"parameters": {
115+
"type": "object",
116+
"properties": {
117+
"title": {
118+
"type": "string",
119+
"description": "Event title"
120+
},
121+
"date": {
122+
"type": "string",
123+
"description": "Event date in YYYY-MM-DD format"
124+
},
125+
"time": {
126+
"type": "string",
127+
"description": "Event time in HH:MM format"
128+
},
129+
"duration": {
130+
"type": "integer",
131+
"description": "Duration in minutes"
132+
}
133+
},
134+
"required": ["title", "date", "time"]
135+
}
136+
}
137+
},
138+
"description": "Schedule meetings, create calendar events, set appointments, manage calendar, book time, plan meeting, organize schedule, reminder, agenda",
139+
"category": "productivity",
140+
"tags": ["calendar", "event", "meeting", "appointment", "schedule"]
141+
}
142+
]
143+

0 commit comments

Comments
 (0)