@@ -6,6 +6,9 @@ const stateManager = require('./state');
6
6
// Import metrics history system
7
7
const metricsHistory = require ( './metricsHistory' ) ;
8
8
9
+ // Import diagnostic tool
10
+ const DiagnosticTool = require ( './diagnostics' ) ;
11
+
9
12
// --- BEGIN Configuration Loading using configLoader ---
10
13
const { loadConfiguration, ConfigurationError } = require ( './configLoader' ) ;
11
14
@@ -405,6 +408,159 @@ app.get('/api/charts', async (req, res) => {
405
408
}
406
409
} ) ;
407
410
411
+ // Simple diagnostic endpoint for troubleshooting
412
+ app . get ( '/api/diagnostics-simple' , async ( req , res ) => {
413
+ try {
414
+ // Delete from require cache to force reload
415
+ delete require . cache [ require . resolve ( './diagnostics-simple' ) ] ;
416
+ const SimpleDiagnosticTool = require ( './diagnostics-simple' ) ;
417
+ const tool = new SimpleDiagnosticTool ( stateManager , apiClients , pbsApiClients ) ;
418
+ const report = await tool . runDiagnostics ( ) ;
419
+ res . json ( report ) ;
420
+ } catch ( error ) {
421
+ console . error ( "Simple diagnostics error:" , error ) ;
422
+ res . status ( 500 ) . json ( { error : error . message } ) ;
423
+ }
424
+ } ) ;
425
+
426
+ // Direct state inspection endpoint
427
+ app . get ( '/api/diagnostics-state' , ( req , res ) => {
428
+ try {
429
+ const state = stateManager . getState ( ) ;
430
+ const summary = {
431
+ timestamp : new Date ( ) . toISOString ( ) ,
432
+ last_update : state . lastUpdate ,
433
+ update_age_seconds : state . lastUpdate ? Math . floor ( ( Date . now ( ) - new Date ( state . lastUpdate ) . getTime ( ) ) / 1000 ) : null ,
434
+ guests_count : state . guests ?. length || 0 ,
435
+ nodes_count : state . nodes ?. length || 0 ,
436
+ pbs_count : state . pbs ?. length || 0 ,
437
+ sample_guests : state . guests ?. slice ( 0 , 5 ) . map ( g => ( {
438
+ vmid : g . vmid ,
439
+ name : g . name ,
440
+ type : g . type ,
441
+ status : g . status
442
+ } ) ) || [ ] ,
443
+ sample_backups : [ ] ,
444
+ errors : state . errors || [ ]
445
+ } ;
446
+
447
+ // Get sample backups
448
+ if ( state . pbs && Array . isArray ( state . pbs ) ) {
449
+ state . pbs . forEach ( pbsInstance => {
450
+ if ( pbsInstance . datastores ) {
451
+ pbsInstance . datastores . forEach ( ds => {
452
+ if ( ds . snapshots && ds . snapshots . length > 0 ) {
453
+ ds . snapshots . slice ( 0 , 5 ) . forEach ( snap => {
454
+ summary . sample_backups . push ( {
455
+ store : ds . store ,
456
+ backup_id : snap [ 'backup-id' ] ,
457
+ backup_type : snap [ 'backup-type' ] ,
458
+ backup_time : new Date ( snap [ 'backup-time' ] * 1000 ) . toISOString ( )
459
+ } ) ;
460
+ } ) ;
461
+ }
462
+ } ) ;
463
+ }
464
+ } ) ;
465
+ }
466
+
467
+ res . json ( summary ) ;
468
+ } catch ( error ) {
469
+ console . error ( "State inspection error:" , error ) ;
470
+ res . status ( 500 ) . json ( { error : error . message } ) ;
471
+ }
472
+ } ) ;
473
+
474
+ // Quick diagnostic check endpoint
475
+ app . get ( '/api/diagnostics/check' , async ( req , res ) => {
476
+ try {
477
+ // Use cached result if available and recent
478
+ const cacheKey = 'diagnosticCheck' ;
479
+ const cached = global . diagnosticCache ?. [ cacheKey ] ;
480
+ if ( cached && ( Date . now ( ) - cached . timestamp ) < 60000 ) { // Cache for 1 minute
481
+ return res . json ( cached . result ) ;
482
+ }
483
+
484
+ // Run a quick check
485
+ delete require . cache [ require . resolve ( './diagnostics-fixed' ) ] ;
486
+ const DiagnosticToolFixed = require ( './diagnostics-fixed' ) ;
487
+ const diagnosticTool = new DiagnosticToolFixed ( stateManager , metricsHistory , apiClients , pbsApiClients ) ;
488
+ const report = await diagnosticTool . runDiagnostics ( ) ;
489
+
490
+ const hasIssues = report . recommendations &&
491
+ report . recommendations . some ( r => r . severity === 'critical' || r . severity === 'warning' ) ;
492
+
493
+ const result = {
494
+ hasIssues,
495
+ criticalCount : report . recommendations ?. filter ( r => r . severity === 'critical' ) . length || 0 ,
496
+ warningCount : report . recommendations ?. filter ( r => r . severity === 'warning' ) . length || 0
497
+ } ;
498
+
499
+ // Cache the result
500
+ if ( ! global . diagnosticCache ) global . diagnosticCache = { } ;
501
+ global . diagnosticCache [ cacheKey ] = { timestamp : Date . now ( ) , result } ;
502
+
503
+ res . json ( result ) ;
504
+ } catch ( error ) {
505
+ console . error ( "Error in diagnostic check:" , error ) ;
506
+ res . json ( { hasIssues : false } ) ; // Don't show icon on error
507
+ }
508
+ } ) ;
509
+
510
+ // Raw state endpoint - shows everything
511
+ app . get ( '/api/raw-state' , ( req , res ) => {
512
+ const state = stateManager . getState ( ) ;
513
+ const rawState = stateManager . state || { } ;
514
+ res . json ( {
515
+ lastUpdate : state . lastUpdate ,
516
+ statsLastUpdated : state . stats ?. lastUpdated ,
517
+ rawStateLastUpdated : rawState . stats ?. lastUpdated ,
518
+ guestsLength : state . guests ?. length ,
519
+ rawGuestsLength : rawState . guests ?. length ,
520
+ guestsType : Array . isArray ( state . guests ) ? 'array' : typeof state . guests ,
521
+ allKeys : Object . keys ( state ) ,
522
+ rawKeys : Object . keys ( rawState ) ,
523
+ serverUptime : process . uptime ( ) ,
524
+ // Sample guest to see structure
525
+ firstGuest : state . guests ?. [ 0 ] ,
526
+ rawFirstGuest : rawState . guests ?. [ 0 ]
527
+ } ) ;
528
+ } ) ;
529
+
530
+ // --- Diagnostic Endpoint ---
531
+ app . get ( '/api/diagnostics' , async ( req , res ) => {
532
+ try {
533
+ console . log ( 'Running diagnostics...' ) ;
534
+ // Force reload the diagnostic module to get latest changes
535
+ delete require . cache [ require . resolve ( './diagnostics-fixed' ) ] ;
536
+ const DiagnosticToolFixed = require ( './diagnostics-fixed' ) ;
537
+ const diagnosticTool = new DiagnosticToolFixed ( stateManager , metricsHistory , apiClients , pbsApiClients ) ;
538
+ const report = await diagnosticTool . runDiagnostics ( ) ;
539
+
540
+ // Format the report for easy reading
541
+ const formattedReport = {
542
+ ...report ,
543
+ summary : {
544
+ hasIssues : report . recommendations && report . recommendations . some ( r => r . severity === 'critical' ) ,
545
+ criticalIssues : report . recommendations ? report . recommendations . filter ( r => r . severity === 'critical' ) . length : 0 ,
546
+ warnings : report . recommendations ? report . recommendations . filter ( r => r . severity === 'warning' ) . length : 0 ,
547
+ info : report . recommendations ? report . recommendations . filter ( r => r . severity === 'info' ) . length : 0 ,
548
+ isTimingIssue : report . state && report . state . dataAge === null && report . state . serverUptime < 90
549
+ }
550
+ } ;
551
+
552
+ res . json ( formattedReport ) ;
553
+ } catch ( error ) {
554
+ console . error ( "Error running diagnostics:" , error ) ;
555
+ console . error ( "Stack trace:" , error . stack ) ;
556
+ res . status ( 500 ) . json ( {
557
+ error : "Failed to run diagnostics" ,
558
+ details : error . message ,
559
+ stack : error . stack
560
+ } ) ;
561
+ }
562
+ } ) ;
563
+
408
564
// --- WebSocket Setup ---
409
565
const io = new Server ( server , {
410
566
// Optional: Configure CORS for Socket.IO if needed, separate from Express CORS
0 commit comments