-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathssh.go
103 lines (93 loc) · 2.44 KB
/
ssh.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package gerrittest
import (
"bytes"
"errors"
"fmt"
"net"
"strings"
"github.com/opalmer/dockertest"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
)
// SSHClient implements an SSH client for talking to
// Gerrit.
type SSHClient struct {
log *log.Entry
Client *ssh.Client
}
// Close will close the SSHPort client and session.
func (s *SSHClient) Close() error {
err := s.Client.Close()
if err != nil {
if operr, ok := err.(*net.OpError); ok {
// If the error occurred due to Close() being
// called then ignore it rather than return an
// error. SSHClient is short lived so we should
// expect the socket to be closed when the program
// terminates.
if operr.Op == "close" {
err = nil
}
}
}
return err
}
// Run executes a command over ssh.
func (s *SSHClient) Run(command string) ([]byte, []byte, error) {
logger := s.log.WithField("cmd", command)
session, err := s.Client.NewSession()
if err != nil {
logger.WithError(err).Error()
return nil, nil, err
}
defer session.Close() // nolint: errcheck
var stdout bytes.Buffer
var stderr bytes.Buffer
session.Stdout = &stdout
session.Stderr = &stderr
err = session.Run(command)
if err != nil {
logger.WithError(err).Error()
} else {
logger.Debug()
}
return stdout.Bytes(), stderr.Bytes(), nil
}
// Version returns the current version of Gerrit.
func (s *SSHClient) Version() (string, error) {
stdout, _, err := s.Run("gerrit version")
return strings.Split(strings.TrimSpace(string(stdout)), " ")[2], err
}
// NewSSHClient produces an *SSHClient struct and attempts to connect to
// Gerrrit.
func NewSSHClient(config *Config, port *dockertest.Port) (*SSHClient, error) {
logger := log.WithFields(log.Fields{
"svc": "gerrittest",
"cmp": "SSHPort",
})
if len(config.SSHKeys) == 0 {
return nil, errors.New("no ssh keys present")
}
for _, key := range config.SSHKeys {
sshClient, err := ssh.Dial(
"tcp", fmt.Sprintf("%s:%d", port.Address, port.Public),
&ssh.ClientConfig{
User: config.Username,
Auth: []ssh.AuthMethod{ssh.PublicKeys(key.Private)},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
},
)
if err != nil {
logger.WithError(err).Warn()
continue
}
client := &SSHClient{
log: logger,
Client: sshClient,
}
version, err := client.Version()
logger.WithField("version", version).Debug()
return client, err
}
return nil, errors.New("failed to connect to ssh with any key")
}