add cmdexec package to execute commands on remote hosts via SSH

This commit is contained in:
Pavel Sviderski
2024-08-24 19:55:28 +10:00
parent 32448381ac
commit 3f13f6c0e6
6 changed files with 1131 additions and 2 deletions
+59
View File
@@ -0,0 +1,59 @@
package cmdexec
import (
"context"
"fmt"
"golang.org/x/crypto/ssh"
"strings"
)
type Remote struct {
client *ssh.Client
}
// Run runs the command on the remote host and returns its output with all leading and trailing
// white space removed.
func (r *Remote) Run(ctx context.Context, cmd string) (string, error) {
session, err := r.client.NewSession()
if err != nil {
return "", fmt.Errorf("create session: %w", err)
}
defer func() {
_ = session.Close()
}()
// Run the command in a goroutine to be able to cancel it.
type result struct {
out string
err error
}
done := make(chan result)
go func() {
outBytes, outErr := session.CombinedOutput(cmd)
res := result{
err: outErr,
}
if outErr == nil {
res.out = strings.TrimSpace(string(outBytes))
}
done <- res
}()
select {
case res := <-done:
if res.err != nil {
return "", fmt.Errorf("run command on remote host: %w", res.err)
}
return res.out, nil
case <-ctx.Done():
if err = session.Signal(ssh.SIGINT); err != nil {
return "", fmt.Errorf("send interrupt signal to remote process: %w", err)
}
return "", fmt.Errorf("canceled: %w", ctx.Err())
}
}
// Close closes the connection to the remote host.
func (r *Remote) Close() error {
return r.client.Close()
}