@@ -1405,6 +1405,67 @@ func ValidateNodeProblemDetector(ctx context.Context, s *Scenario) {
14051405 execScriptOnVMForScenarioValidateExitCode (ctx , s , strings .Join (command , "\n " ), 0 , "Node Problem Detector (NPD) service validation failed" )
14061406}
14071407
1408+ func ValidateNodeExporter (ctx context.Context , s * Scenario ) {
1409+ s .T .Helper ()
1410+
1411+ skipFile := "/etc/node-exporter.d/skip_vhd_node_exporter"
1412+ serviceName := "node-exporter.service"
1413+
1414+ // Check if node-exporter is installed on this VHD by looking for the skip sentinel file.
1415+ // The skip file is only present on VHDs that have node-exporter installed (Ubuntu, Mariner, Azure Linux).
1416+ // Flatcar, OSGuard, and older VHDs do not have node-exporter installed and will not have the skip file.
1417+ if ! fileExist (ctx , s , skipFile ) {
1418+ s .T .Logf ("Skipping node-exporter validation: sentinel file %s not found (VHD does not have node-exporter installed)" , skipFile )
1419+ return
1420+ }
1421+
1422+ s .T .Logf ("skip_vhd_node_exporter sentinel file found, validating node-exporter installation" )
1423+
1424+ // Validate service is running
1425+ ValidateSystemdUnitIsRunning (ctx , s , serviceName )
1426+ ValidateSystemdUnitIsNotFailed (ctx , s , serviceName )
1427+
1428+ // Validate service is enabled
1429+ execScriptOnVMForScenarioValidateExitCode (ctx , s , fmt .Sprintf ("systemctl is-enabled %s" , serviceName ), 0 , fmt .Sprintf ("%s should be enabled" , serviceName ))
1430+
1431+ // Validate binary exists and is executable
1432+ // The binary is installed at /usr/bin and symlinked to /opt/bin for consistency with other binaries (kubelet, etc.)
1433+ ValidateFileExists (ctx , s , "/usr/bin/node-exporter" )
1434+ ValidateFileExists (ctx , s , "/opt/bin/node-exporter" )
1435+ ValidateFileExists (ctx , s , "/opt/bin/node-exporter-startup.sh" )
1436+
1437+ // Validate configuration files exist
1438+ ValidateFileExists (ctx , s , skipFile )
1439+ ValidateFileExists (ctx , s , "/etc/node-exporter.d/web-config.yml" )
1440+
1441+ // Validate that node-exporter is listening on port 19100
1442+ // We verify the port is open using ss/netstat rather than making a full mTLS request,
1443+ // since the e2e test environment may not have the correct client certs set up.
1444+ // The mTLS configuration is validated by checking that the web-config.yml exists
1445+ // and contains the expected TLS settings.
1446+ s .T .Logf ("Validating node-exporter is listening on port 19100" )
1447+ command := []string {
1448+ "set -ex" ,
1449+ "NODE_IP=$(hostname -I | awk '{print $1}')" ,
1450+ // Verify node-exporter is listening on port 19100
1451+ "ss -tlnp | grep -q ':19100' || netstat -tlnp | grep -q ':19100'" ,
1452+ }
1453+ execScriptOnVMForScenarioValidateExitCode (ctx , s , strings .Join (command , "\n " ), 0 , "node-exporter should be listening on port 19100" )
1454+
1455+ // Verify the web-config.yml has proper TLS configuration
1456+ s .T .Logf ("Validating node-exporter TLS configuration" )
1457+ tlsCommand := []string {
1458+ "set -ex" ,
1459+ // Verify web-config.yml contains TLS settings
1460+ "grep -q 'tls_server_config' /etc/node-exporter.d/web-config.yml" ,
1461+ "grep -q 'client_auth_type' /etc/node-exporter.d/web-config.yml" ,
1462+ "grep -q 'client_ca_file' /etc/node-exporter.d/web-config.yml" ,
1463+ }
1464+ execScriptOnVMForScenarioValidateExitCode (ctx , s , strings .Join (tlsCommand , "\n " ), 0 , "node-exporter TLS config should be properly configured" )
1465+
1466+ s .T .Logf ("node-exporter validation passed" )
1467+ }
1468+
14081469func ValidateNPDFilesystemCorruption (ctx context.Context , s * Scenario ) {
14091470 command := []string {
14101471 "set -ex" ,
0 commit comments