Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/dev/preview/previewctl/pkg/ssh/ssh.go
2501 views
1
// Copyright (c) 2022 Gitpod GmbH. All rights reserved.
2
// Licensed under the GNU Affero General Public License (AGPL).
3
// See License.AGPL.txt in the project root for license information.
4
5
package ssh
6
7
import (
8
"context"
9
"fmt"
10
"io"
11
"net"
12
13
"golang.org/x/crypto/ssh"
14
)
15
16
type Client interface {
17
io.Closer
18
19
Run(ctx context.Context, cmd string, stdout io.Writer, stderr io.Writer) error
20
}
21
22
type ClientFactory interface {
23
Dial(ctx context.Context, host, port string) (Client, error)
24
}
25
26
type ClientImplementation struct {
27
Client *ssh.Client
28
}
29
30
var _ Client = &ClientImplementation{}
31
32
func (s *ClientImplementation) Run(ctx context.Context, cmd string, stdout io.Writer, stderr io.Writer) error {
33
sess, err := s.Client.NewSession()
34
if err != nil {
35
return err
36
}
37
38
defer func(sess *ssh.Session) {
39
err := sess.Close()
40
if err != nil && err != io.EOF {
41
panic(err)
42
}
43
}(sess)
44
45
sess.Stdout = stdout
46
sess.Stderr = stderr
47
48
return sess.Run(cmd)
49
}
50
51
func (s *ClientImplementation) Close() error {
52
return s.Client.Close()
53
}
54
55
type FactoryImplementation struct {
56
SSHConfig *ssh.ClientConfig
57
}
58
59
var _ ClientFactory = &FactoryImplementation{}
60
61
func (f *FactoryImplementation) Dial(ctx context.Context, host, port string) (Client, error) {
62
addr := fmt.Sprintf("%s:%s", host, port)
63
d := net.Dialer{}
64
conn, err := d.DialContext(ctx, "tcp", addr)
65
if err != nil {
66
return nil, err
67
}
68
69
var client *ssh.Client
70
c, chans, reqs, err := ssh.NewClientConn(conn, addr, f.SSHConfig)
71
if err != nil {
72
return nil, err
73
}
74
75
client = ssh.NewClient(c, chans, reqs)
76
77
return &ClientImplementation{
78
Client: client,
79
}, nil
80
}
81
82