ExecuteSSHCommandStdoutOnly executes a command and returns only stdout, filtering out ld.so.preload errors from stderr This prevents stderr pollution from breaking output parsing when /etc/ld.so.preload references a missing binary
(client *SSHClient, command string)
| 502 | // ExecuteSSHCommandStdoutOnly executes a command and returns only stdout, filtering out ld.so.preload errors from stderr |
| 503 | // This prevents stderr pollution from breaking output parsing when /etc/ld.so.preload references a missing binary |
| 504 | func ExecuteSSHCommandStdoutOnly(client *SSHClient, command string) (string, error) { |
| 505 | if client == nil || client.client == nil { |
| 506 | return "", fmt.Errorf("SSH client is not connected") |
| 507 | } |
| 508 | |
| 509 | session, err := client.client.NewSession() |
| 510 | if err != nil { |
| 511 | return "", fmt.Errorf("failed to create session: %w", err) |
| 512 | } |
| 513 | defer session.Close() |
| 514 | |
| 515 | stdout, err := session.StdoutPipe() |
| 516 | if err != nil { |
| 517 | return "", fmt.Errorf("failed to get stdout pipe: %w", err) |
| 518 | } |
| 519 | |
| 520 | stderr, err := session.StderrPipe() |
| 521 | if err != nil { |
| 522 | return "", fmt.Errorf("failed to get stderr pipe: %w", err) |
| 523 | } |
| 524 | |
| 525 | if err := session.Start(command); err != nil { |
| 526 | return "", fmt.Errorf("failed to start command: %w", err) |
| 527 | } |
| 528 | |
| 529 | // Read stdout and stderr concurrently |
| 530 | var stdoutData, stderrData []byte |
| 531 | var stderrErr error |
| 532 | done := make(chan bool, 2) |
| 533 | |
| 534 | go func() { |
| 535 | var err error |
| 536 | stdoutData, err = io.ReadAll(stdout) |
| 537 | if err != nil { |
| 538 | // Log but don't fail - stderr filtering will handle errors |
| 539 | } |
| 540 | done <- true |
| 541 | }() |
| 542 | |
| 543 | go func() { |
| 544 | stderrData, stderrErr = io.ReadAll(stderr) |
| 545 | done <- true |
| 546 | }() |
| 547 | |
| 548 | // Wait for both reads to complete |
| 549 | <-done |
| 550 | <-done |
| 551 | |
| 552 | // Wait for command to finish |
| 553 | cmdErr := session.Wait() |
| 554 | |
| 555 | // Filter out ld.so.preload errors from stderr (these are benign when binary is missing) |
| 556 | stderrStr := string(stderrData) |
| 557 | if stderrErr == nil && stderrStr != "" { |
| 558 | // Check if stderr contains only ignorable Thunder-specific errors |
| 559 | stderrLines := strings.Split(strings.TrimSpace(stderrStr), "\n") |
| 560 | hasNonIgnorableErrors := false |
| 561 | for _, line := range stderrLines { |