backup/ssh.go

123 lines
3.7 KiB
Go
Raw Normal View History

2021-10-16 15:39:54 +02:00
package main
import (
"bytes"
2023-06-29 22:58:24 +02:00
"os"
"time"
2021-10-16 15:39:54 +02:00
2023-06-29 22:58:24 +02:00
"github.com/silenceper/pool"
log "github.com/sirupsen/logrus"
2021-10-16 15:39:54 +02:00
"golang.org/x/crypto/ssh"
)
2023-06-29 22:58:24 +02:00
const SshDialTimeout = time.Duration(10 * time.Second)
const SshInactivityTimeout = time.Duration(time.Minute)
type Ssh struct {
name string
signer ssh.Signer
config *ssh.ClientConfig
client *ssh.Client
2021-10-16 15:39:54 +02:00
}
2023-06-29 22:58:24 +02:00
func NewSsh(name, addr, user, key string) (*Ssh, error) {
log.WithFields(log.Fields{"name": name, "addr": addr, "user": user, "key": key}).Debugf("starting")
defer log.WithFields(log.Fields{"name": name, "addr": addr, "user": user, "key": key}).Debugf("done")
s := &Ssh{
name: name,
}
k, err := os.ReadFile(key)
if err != nil {
log.WithFields(log.Fields{"name": name, "addr": addr, "user": user, "key": key, "call": "os.ReadFile", "error": err}).Errorf("")
return s, err
}
parsedKey, err := ssh.ParseRawPrivateKey(k)
if err != nil {
log.WithFields(log.Fields{"name": name, "addr": addr, "user": user, "key": key, "call": "ssh.ParseRawPrivateKey", "error": err}).Errorf("")
return s, err
}
s.signer, err = ssh.NewSignerFromKey(parsedKey)
if err != nil {
log.WithFields(log.Fields{"name": name, "addr": addr, "user": user, "key": key, "call": "ssh.NewSignerFromKey", "error": err}).Errorf("")
return s, err
}
s.config = &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.PublicKeys(s.signer),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
Timeout: SshDialTimeout,
}
s.client, err = ssh.Dial("tcp", addr, s.config)
if err != nil {
log.WithFields(log.Fields{"name": name, "addr": addr, "user": user, "key": key, "call": "ssh.Dial", "error": err}).Errorf("")
return s, err
2021-10-16 15:39:54 +02:00
}
2023-06-29 22:58:24 +02:00
return s, nil
}
func (s *Ssh) Close() error {
log.WithFields(log.Fields{"name": s.name}).Debugf("starting")
defer log.WithFields(log.Fields{"name": s.name}).Debugf("done")
return s.client.Close()
}
func NewSshPool(name, addr, user, key string) (pool.Pool, error) {
log.WithFields(log.Fields{"name": name, "addr": addr, "user": user, "key": key}).Debugf("starting")
defer log.WithFields(log.Fields{"name": name, "addr": addr, "user": user, "key": key}).Debugf("done")
//factory Specify the method to create the connection
factory := func() (interface{}, error) { return NewSsh(name, addr, user, key) }
// close Specify the method to close the connection
close := func(v interface{}) error { return v.(*Ssh).Close() }
// Create a connection pool: Initialize the number of connections to 0, the maximum idle connection is 2, and the maximum concurrent connection is 25
poolConfig := &pool.Config{
InitialCap: 0,
MaxIdle: 2,
MaxCap: 25,
Factory: factory,
Close: close,
//Ping: ping,
//The maximum idle time of the connection, the connection exceeding this time will be closed, which can avoid the problem of automatic failure when connecting to EOF when idle
IdleTimeout: SshInactivityTimeout,
}
return pool.NewChannelPool(poolConfig)
}
func (s *Ssh) Exec(cmd string) (string, error) {
log.WithFields(log.Fields{"name": s.name, "cmd": cmd}).Debugf("starting")
defer log.WithFields(log.Fields{"name": s.name, "cmd": cmd}).Debugf("done")
2021-10-16 15:39:54 +02:00
session, err := s.client.NewSession()
if err != nil {
2023-06-29 22:58:24 +02:00
log.WithFields(log.Fields{"name": s.name, "cmd": cmd, "call": "client.NewSession", "error": err}).Errorf("")
return "", err
2021-10-16 15:39:54 +02:00
}
2023-06-29 22:58:24 +02:00
defer session.Close()
2021-10-16 15:39:54 +02:00
2023-06-29 22:58:24 +02:00
var bufout, buferr bytes.Buffer
session.Stdout = &bufout
session.Stderr = &buferr
2021-11-14 08:58:47 +01:00
2021-10-16 15:39:54 +02:00
err = session.Run("TZ=\"" + cfg.Timezone + "\" " + cmd)
if err != nil {
2023-06-29 22:58:24 +02:00
log.WithFields(log.Fields{"name": s.name, "cmd": cmd, "call": "session.Run", "error": err, "stderr": buferr.String()}).Errorf("")
return "", err
2021-10-16 15:39:54 +02:00
}
2023-06-29 22:58:24 +02:00
return bufout.String(), nil
2021-10-16 15:39:54 +02:00
}