Skip to content

Commit 8c51cf2

Browse files
committed
Adding more debug info for debug providers
1 parent 10e14a2 commit 8c51cf2

2 files changed

Lines changed: 262 additions & 6 deletions

File tree

server/routes/status.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,40 @@ router.get('/status/providers', (req: Request, res: Response) => {
218218
}
219219
})
220220

221+
/**
222+
* POST /status/providers/:providerName/retry
223+
* Manually retry initialization for a failed provider
224+
*/
225+
router.post('/status/providers/:providerName/retry', async (req: Request, res: Response) => {
226+
try {
227+
const { providerName } = req.params
228+
console.log(`Status: Retrying provider: ${providerName}`)
229+
230+
const success = await providerManager.retryProvider(providerName)
231+
232+
if (success) {
233+
const status = providerManager.getProviderStatus(providerName)
234+
res.json({
235+
success: true,
236+
message: `Provider ${providerName} successfully initialized`,
237+
status
238+
})
239+
} else {
240+
res.status(400).json({
241+
success: false,
242+
message: `Failed to initialize provider ${providerName}`,
243+
error: 'Initialization failed'
244+
})
245+
}
246+
} catch (error) {
247+
console.error('Status: Error retrying provider:', error)
248+
res.status(500).json({
249+
success: false,
250+
error: error instanceof Error ? error.message : 'Unknown error'
251+
})
252+
}
253+
})
254+
221255
/**
222256
* GET /status/oidc-debug
223257
* Get detailed OIDC discovery information for debugging

src/views/ProvidersStatusView.vue

Lines changed: 228 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,43 @@
117117
<label>Last Checked:</label>
118118
<span>{{ formatDate(provider.lastChecked) }}</span>
119119
</div>
120-
<div v-if="provider.error" class="provider-detail error-detail">
121-
<label>Error:</label>
122-
<span class="error-message">{{ provider.error }}</span>
120+
121+
<!-- Enhanced Error Display -->
122+
<div v-if="provider.error" class="error-section">
123+
<div class="error-header">
124+
<el-icon class="error-icon"><WarningFilled /></el-icon>
125+
<span class="error-category">{{ getErrorCategory(provider.error) }}</span>
126+
</div>
127+
<div class="error-message">
128+
<strong>Error:</strong> {{ getFormattedError(provider.error) }}
129+
</div>
130+
131+
<!-- Troubleshooting Hints -->
132+
<div class="troubleshooting-hints">
133+
<div class="hint-title">
134+
<el-icon><InfoFilled /></el-icon>
135+
<strong>Troubleshooting:</strong>
136+
</div>
137+
<ul class="hint-list">
138+
<li v-for="(hint, index) in getTroubleshootingHints(provider.error)" :key="index">
139+
{{ hint }}
140+
</li>
141+
</ul>
142+
</div>
143+
144+
<!-- Retry Button -->
145+
<div class="retry-section">
146+
<el-button
147+
type="primary"
148+
size="small"
149+
:loading="retryingProviders.has(provider.name)"
150+
@click="retryProvider(provider.name)"
151+
>
152+
<el-icon><Refresh /></el-icon>
153+
{{ retryingProviders.has(provider.name) ? 'Retrying...' : 'Retry Now' }}
154+
</el-button>
155+
<span class="retry-hint">Manual retry to reinitialize this provider</span>
156+
</div>
123157
</div>
124158
</div>
125159
</el-card>
@@ -164,7 +198,7 @@
164198
<script setup lang="ts">
165199
import { ref, onMounted } from 'vue'
166200
import { ElMessage } from 'element-plus'
167-
import { Refresh, InfoFilled } from '@element-plus/icons-vue'
201+
import { Refresh, InfoFilled, WarningFilled } from '@element-plus/icons-vue'
168202
169203
interface ProviderStatus {
170204
name: string
@@ -195,6 +229,7 @@ const loading = ref(true)
195229
const error = ref<string | null>(null)
196230
const status = ref<StatusResponse | null>(null)
197231
const activeCollapse = ref<string[]>(['obpOidc', 'keycloak', 'google', 'github', 'custom'])
232+
const retryingProviders = ref<Set<string>>(new Set())
198233
199234
const fetchStatus = async () => {
200235
loading.value = true
@@ -220,6 +255,113 @@ const refreshStatus = async () => {
220255
ElMessage.success('Provider status refreshed')
221256
}
222257
258+
const retryProvider = async (providerName: string) => {
259+
retryingProviders.value.add(providerName)
260+
261+
try {
262+
const response = await fetch(`/api/status/providers/${providerName}/retry`, {
263+
method: 'POST'
264+
})
265+
266+
const result = await response.json()
267+
268+
if (response.ok && result.success) {
269+
ElMessage.success(`Provider ${providerName} successfully initialized!`)
270+
await fetchStatus() // Refresh the status
271+
} else {
272+
ElMessage.error(result.message || `Failed to retry provider ${providerName}`)
273+
}
274+
} catch (err) {
275+
ElMessage.error(`Error retrying provider: ${err instanceof Error ? err.message : 'Unknown error'}`)
276+
} finally {
277+
retryingProviders.value.delete(providerName)
278+
}
279+
}
280+
281+
const getErrorCategory = (errorMsg: string): string => {
282+
if (!errorMsg) return 'Unknown Error'
283+
284+
const msg = errorMsg.toLowerCase()
285+
286+
if (msg.includes('http 4') || msg.includes('http 5')) {
287+
return 'HTTP Error'
288+
} else if (msg.includes('timeout') || msg.includes('network') || msg.includes('fetch')) {
289+
return 'Network Error'
290+
} else if (msg.includes('not configured') || msg.includes('no well-known')) {
291+
return 'Configuration Error'
292+
} else if (msg.includes('failed to initialize')) {
293+
return 'Initialization Error'
294+
} else if (msg.includes('invalid') || msg.includes('parse')) {
295+
return 'Validation Error'
296+
}
297+
298+
return 'General Error'
299+
}
300+
301+
const getFormattedError = (errorMsg: string): string => {
302+
if (!errorMsg) return 'Unknown error occurred'
303+
304+
// Make common errors more user-friendly
305+
const msg = errorMsg.toLowerCase()
306+
307+
if (msg.includes('http 404')) {
308+
return 'Provider endpoint not found (HTTP 404). The OIDC configuration endpoint is not accessible.'
309+
} else if (msg.includes('http 401') || msg.includes('http 403')) {
310+
return 'Access denied (HTTP 401/403). Authentication or authorization required.'
311+
} else if (msg.includes('http 500') || msg.includes('http 502') || msg.includes('http 503')) {
312+
return 'Provider server error (HTTP 5xx). The identity provider is experiencing issues.'
313+
} else if (msg.includes('timeout')) {
314+
return 'Connection timeout. The provider is not responding in a timely manner.'
315+
} else if (msg.includes('network')) {
316+
return 'Network connectivity issue. Cannot reach the provider server.'
317+
} else if (msg.includes('no well-known url configured')) {
318+
return 'Missing well-known URL. The provider configuration is incomplete.'
319+
} else if (msg.includes('failed to initialize')) {
320+
return 'Initialization failed. Could not create OAuth2 client for this provider.'
321+
}
322+
323+
return errorMsg
324+
}
325+
326+
const getTroubleshootingHints = (errorMsg: string): string[] => {
327+
if (!errorMsg) return ['Check server logs for more details']
328+
329+
const msg = errorMsg.toLowerCase()
330+
const hints: string[] = []
331+
332+
if (msg.includes('http 404')) {
333+
hints.push('Verify the provider\'s well-known URL is correct in the OBP API configuration')
334+
hints.push('Check that the identity provider is properly deployed and accessible')
335+
hints.push('Ensure the OIDC discovery endpoint exists at /.well-known/openid-configuration')
336+
} else if (msg.includes('http 401') || msg.includes('http 403')) {
337+
hints.push('Check if the provider requires authentication for the discovery endpoint')
338+
hints.push('Verify API credentials and permissions')
339+
} else if (msg.includes('http 5')) {
340+
hints.push('The identity provider may be down or restarting')
341+
hints.push('Check the provider\'s status page or logs')
342+
hints.push('Try again in a few minutes')
343+
} else if (msg.includes('timeout') || msg.includes('network')) {
344+
hints.push('Verify network connectivity between API Explorer and the identity provider')
345+
hints.push('Check firewall rules and DNS resolution')
346+
hints.push('Ensure the provider URL is accessible from the server')
347+
hints.push('Try accessing the well-known URL manually from the server')
348+
} else if (msg.includes('no well-known') || msg.includes('not configured')) {
349+
hints.push('Check environment variables for this provider')
350+
hints.push('Verify the provider is configured in the OBP API')
351+
hints.push('Review the SETUP_MULTI_PROVIDER.md documentation')
352+
} else if (msg.includes('failed to initialize')) {
353+
hints.push('Check the provider\'s OIDC configuration is valid')
354+
hints.push('Verify client ID and client secret are correct')
355+
hints.push('Review server logs for detailed error messages')
356+
} else {
357+
hints.push('Check server logs for detailed error information')
358+
hints.push('Verify the provider configuration in environment variables')
359+
hints.push('Visit the OIDC Debug page for more details')
360+
}
361+
362+
return hints
363+
}
364+
223365
const getProviderDisplayName = (key: string): string => {
224366
const names: { [key: string]: string } = {
225367
'obp-oidc': 'OBP-OIDC',
@@ -412,11 +554,91 @@ h2 {
412554
align-items: flex-start;
413555
}
414556
557+
/* Enhanced Error Section */
558+
.error-section {
559+
background: #fef0f0;
560+
padding: 16px;
561+
border-radius: 6px;
562+
border-left: 4px solid #f56c6c;
563+
margin-top: 12px;
564+
}
565+
566+
.error-header {
567+
display: flex;
568+
align-items: center;
569+
gap: 8px;
570+
margin-bottom: 12px;
571+
}
572+
573+
.error-icon {
574+
color: #f56c6c;
575+
font-size: 18px;
576+
}
577+
578+
.error-category {
579+
font-weight: 600;
580+
color: #f56c6c;
581+
font-size: 14px;
582+
text-transform: uppercase;
583+
letter-spacing: 0.5px;
584+
}
585+
415586
.error-message {
587+
background: #fff;
588+
padding: 10px 12px;
589+
border-radius: 4px;
590+
border: 1px solid #fbc4c4;
591+
margin-bottom: 12px;
592+
font-size: 13px;
593+
line-height: 1.6;
594+
color: #303133;
595+
}
596+
597+
.error-message strong {
416598
color: #f56c6c;
417-
font-family: 'Courier New', monospace;
599+
}
600+
601+
.troubleshooting-hints {
602+
background: #fff;
603+
padding: 12px;
604+
border-radius: 4px;
605+
border: 1px solid #e4e7ed;
606+
margin-bottom: 12px;
607+
}
608+
609+
.hint-title {
610+
display: flex;
611+
align-items: center;
612+
gap: 6px;
613+
margin-bottom: 8px;
614+
color: #409eff;
615+
font-size: 13px;
616+
}
617+
618+
.hint-list {
619+
margin: 0;
620+
padding-left: 20px;
621+
color: #606266;
622+
font-size: 13px;
623+
line-height: 1.8;
624+
}
625+
626+
.hint-list li {
627+
margin-bottom: 4px;
628+
}
629+
630+
.retry-section {
631+
display: flex;
632+
align-items: center;
633+
gap: 12px;
634+
padding-top: 8px;
635+
border-top: 1px solid #fbc4c4;
636+
}
637+
638+
.retry-hint {
418639
font-size: 12px;
419-
word-break: break-all;
640+
color: #909399;
641+
font-style: italic;
420642
}
421643
422644
/* Environment Config */

0 commit comments

Comments
 (0)