-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.go
121 lines (105 loc) · 2.4 KB
/
server.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package geploy
import (
"bytes"
"fmt"
"net"
"os"
"path/filepath"
"strings"
"time"
"github.com/fatih/color"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/knownhosts"
)
var (
HostKeyCallback ssh.HostKeyCallback
Signer ssh.Signer
)
func init() {
var err error
HostKeyCallback, err = knownhosts.New(filepath.Join(os.Getenv("HOME"), ".ssh", "known_hosts"))
if err != nil {
panic(err)
}
key, err := os.ReadFile(filepath.Join(os.Getenv("HOME"), ".ssh", "id_rsa"))
if err != nil {
panic(err)
}
Signer, err = ssh.ParsePrivateKey(key)
if err != nil {
panic(err)
}
}
type Server struct {
host string
port string
usr string
hostname string
cli *ssh.Client
}
func NewServer(host, usr string) (*Server, error) {
cfg := &ssh.ClientConfig{
User: usr,
Auth: []ssh.AuthMethod{
ssh.PublicKeys(Signer),
},
HostKeyCallback: HostKeyCallback,
}
port := "22"
addr := net.JoinHostPort(host, port)
cli, err := ssh.Dial("tcp", addr, cfg)
if err != nil {
return nil, err
}
session, err := cli.NewSession()
if err != nil {
cli.Close()
return nil, err
}
defer session.Close()
var stdout bytes.Buffer
session.Stdout = &stdout
if err := session.Run("hostname"); err != nil {
return nil, err
}
hostname := strings.TrimRight(stdout.String(), "\n")
s := &Server{
host: host,
port: port,
usr: usr,
hostname: hostname,
cli: cli,
}
return s, nil
}
func (s *Server) Close() error {
return s.cli.Close()
}
func (s *Server) Session() (*ssh.Session, error) {
return s.cli.NewSession()
}
func (s *Server) Run(cmds ...string) (string, string, error) {
if len(cmds) == 0 {
return "", "", nil
}
var stdout, stderr bytes.Buffer
for _, cmd := range cmds {
session, err := s.Session()
if err != nil {
return "", "", err
}
session.Stdout, session.Stderr = &stdout, &stderr
defer session.Close()
id := nextCommandId()
start := time.Now()
fmt.Printf("%3d [%s] Running %s on %s\n", id, color.HiBlueString(s.hostname), color.HiYellowString(cmd), color.HiBlueString(s.host))
if err := session.Run(cmd); err != nil {
return stdout.String(), stderr.String(), err
}
if stderr.Len() > 0 {
fmt.Printf("%3d [%s] %s\n", id, s.hostname, color.HiRedString(stderr.String()))
}
color.HiBlack("%3d [%s] Finished in %s\n", id, s.hostname, time.Since(start).Truncate(time.Millisecond).String())
}
return stdout.String(), stderr.String(), nil
}