@@ -2,6 +2,7 @@ package ssh
22
33import (
44 "fmt"
5+ "io"
56 "log"
67 "net"
78 "os"
@@ -21,6 +22,13 @@ type HostManager interface {
2122 Apply () error
2223}
2324
25+ // CommandResult represents the result of running a command via SSH
26+ type CommandResult struct {
27+ Stdout string
28+ Stderr string
29+ ExitCode int
30+ }
31+
2432type SSHHostManager struct {
2533 ExporterHost * v1alpha1.ExporterHost `json:"exporterHost,omitempty"`
2634 sshClient * ssh.Client
@@ -54,10 +62,88 @@ func NewSSHHostManager(exporterHost *v1alpha1.ExporterHost) (HostManager, error)
5462}
5563
5664func (m * SSHHostManager ) Status () (string , error ) {
57- if m .ExporterHost .Spec .Management .SSH .Host == "" {
58- return "" , fmt .Errorf ("SSH host is not configured for exporter %s" , m .ExporterHost .Name )
65+ result , err := m .runCommand ("ls -la" )
66+ if err != nil {
67+ return "" , fmt .Errorf ("failed to run status command for %q: %w" , m .ExporterHost .Name , err )
5968 }
60- return "Not implemented yet" , nil
69+
70+ // For now, return a simple status based on exit code
71+ if result .ExitCode == 0 {
72+ return "ok" , nil
73+ }
74+ return fmt .Sprintf ("error (exit code: %d)" , result .ExitCode ), nil
75+ }
76+
77+ // runCommand executes a command on the remote host and returns the result
78+ func (m * SSHHostManager ) runCommand (command string ) (* CommandResult , error ) {
79+ if m .sshClient == nil {
80+ return nil , fmt .Errorf ("sshClient is not initialized" )
81+ }
82+ session , err := m .sshClient .NewSession ()
83+ if err != nil {
84+ return nil , fmt .Errorf ("failed to create SSH session for %q: %w" , m .ExporterHost .Name , err )
85+ }
86+ defer func () {
87+ if closeErr := session .Close (); closeErr != nil {
88+ log .Printf ("Failed to close SSH session for %q: %v" , m .ExporterHost .Name , closeErr )
89+ }
90+ }()
91+
92+ stdout , err := session .StdoutPipe ()
93+ if err != nil {
94+ return nil , fmt .Errorf ("failed to create stdout pipe for %q: %w" , m .ExporterHost .Name , err )
95+ }
96+
97+ stderr , err := session .StderrPipe ()
98+ if err != nil {
99+ return nil , fmt .Errorf ("failed to create stderr pipe for %q: %w" , m .ExporterHost .Name , err )
100+ }
101+
102+ // Capture stdout and stderr
103+ var stdoutBytes , stderrBytes []byte
104+ var stdoutErr , stderrErr error
105+ var wg sync.WaitGroup
106+
107+ wg .Add (2 )
108+ go func () {
109+ defer wg .Done ()
110+ stdoutBytes , stdoutErr = io .ReadAll (stdout )
111+ }()
112+ go func () {
113+ defer wg .Done ()
114+ stderrBytes , stderrErr = io .ReadAll (stderr )
115+ }()
116+
117+ // Run the command
118+ err = session .Run (command )
119+
120+ // Wait for stdout and stderr to be read
121+ wg .Wait ()
122+
123+ // Check for errors in reading stdout/stderr
124+ if stdoutErr != nil {
125+ return nil , fmt .Errorf ("failed to read stdout for %q: %w" , m .ExporterHost .Name , stdoutErr )
126+ }
127+ if stderrErr != nil {
128+ return nil , fmt .Errorf ("failed to read stderr for %q: %w" , m .ExporterHost .Name , stderrErr )
129+ }
130+
131+ // Get exit code
132+ exitCode := 0
133+ if err != nil {
134+ if exitErr , ok := err .(* ssh.ExitError ); ok {
135+ exitCode = exitErr .ExitStatus ()
136+ } else {
137+ // If it's not an exit error, return the error
138+ return nil , fmt .Errorf ("failed to run command for %q: %w" , m .ExporterHost .Name , err )
139+ }
140+ }
141+
142+ return & CommandResult {
143+ Stdout : string (stdoutBytes ),
144+ Stderr : string (stderrBytes ),
145+ ExitCode : exitCode ,
146+ }, nil
61147}
62148
63149func (m * SSHHostManager ) NeedsUpdate () (bool , error ) {
0 commit comments