in plugins/teststeps/exec/transport/ssh_transport.go [56:125]
func (st *SSHTransport) NewProcess(ctx xcontext.Context, bin string, args []string) (Process, error) {
var signer ssh.Signer
if st.IdentityFile != "" {
key, err := ioutil.ReadFile(st.IdentityFile)
if err != nil {
return nil, fmt.Errorf("cannot read private key at %s: %v", st.IdentityFile, err)
}
signer, err = ssh.ParsePrivateKey(key)
if err != nil {
return nil, fmt.Errorf("cannot parse private key: %v", err)
}
}
auth := []ssh.AuthMethod{}
if signer != nil {
auth = append(auth, ssh.PublicKeys(signer))
}
if st.Password != "" {
auth = append(auth, ssh.Password(st.Password))
}
addr := net.JoinHostPort(st.Host, strconv.Itoa(st.Port))
clientConfig := &ssh.ClientConfig{
User: st.User,
Auth: auth,
// TODO expose this in the plugin arguments
//HostKeyCallback: ssh.FixedHostKey(hostKey),
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: time.Duration(st.Timeout),
}
// stack mechanism similar to defer, but run after the exec process ends
stack := newDeferedStack()
client, err := ssh.Dial("tcp", addr, clientConfig)
if err != nil {
return nil, fmt.Errorf("cannot connect to SSH server %s: %v", addr, err)
}
// cleanup the ssh client after the operations have ended
stack.Add(func() {
if err := client.Close(); err != nil {
ctx.Warnf("failed to close SSH client: %w", err)
}
})
if st.SendBinary {
if err := checkBinary(bin); err != nil {
return nil, err
}
bin, err = st.sendFile(ctx, client, bin, 0500)
if err != nil {
return nil, fmt.Errorf("cannot send binary to remote ssh: %w", err)
}
// cleanup the sent file so we don't leave hanging files around
stack.Add(func() {
ctx.Debugf("cleaning remote file: %s", bin)
if err := st.unlinkFile(ctx, client, bin); err != nil {
ctx.Warnf("failed to cleanup remote file: %w", err)
}
})
}
if st.Async != nil {
return st.newAsync(ctx, client, addr, clientConfig, bin, args, stack)
}
return st.new(ctx, client, bin, args, stack)
}