backup/ssh.go
2021-11-14 15:58:47 +08:00

176 lines
3.6 KiB
Go

package main
import (
"bytes"
"encoding/csv"
"fmt"
"log"
"golang.org/x/crypto/ssh"
)
type SSHConfig struct {
signer ssh.Signer
config *ssh.ClientConfig
client *ssh.Client
logged bool
name string
zfs map[string]string
snapshot []Snapshot
}
func (s *SSHConfig) getLastSnapshot(path string) (Snapshot, error) {
if *debugFlag {
log.Printf("SSHConfig.getLastSnapshot : Start %s:%s (%d snapshots)", s.name, path, len(s.snapshot))
}
var last Snapshot
for _, v := range s.snapshot {
if v.Path() == path {
last = v
} else {
if len(string(last)) > 0 {
return last, nil
}
}
}
if len(string(last)) > 0 {
return last, nil
}
return last, fmt.Errorf("no snapshot")
}
func (s *SSHConfig) isLastSnapshot(snapshot Snapshot) bool {
if *debugFlag {
log.Printf("SSHConfig.isLastSnapshot : Start %s:%s", s.name, string(snapshot))
}
_, err := s.getNextSnapshot(snapshot)
if err != nil {
return true
} else {
return false
}
}
func (s *SSHConfig) getFirstSnapshot(path string) (Snapshot, error) {
if *debugFlag {
log.Printf("SSHConfig.getFirstSnapshot : Start %s:%s", s.name, path)
}
var first Snapshot
for _, v := range s.snapshot {
if v.Path() == path {
first = v
if *debugFlag {
log.Printf("SSHConfig.getFirstSnapshot : Return %s", string(first))
}
return first, nil
}
}
return first, fmt.Errorf("no snapshot")
}
func (s *SSHConfig) getNextSnapshot(snapshot Snapshot) (Snapshot, error) {
if *debugFlag {
log.Printf("SSHConfig.getNextSnapshot : Start %s:%s", s.name, string(snapshot))
}
var next Snapshot
for id, v := range s.snapshot {
if v == snapshot {
if len(s.snapshot) > id+1 {
next = s.snapshot[id+1]
if next.Path() == snapshot.Path() {
return next, nil
} else {
return next, fmt.Errorf("no snapshot")
}
} else {
return next, fmt.Errorf("no snapshot")
}
}
}
return next, fmt.Errorf("no snapshot")
}
func (s *SSHConfig) getSnapshotList() error {
if *debugFlag {
log.Printf("SSHConfig.getSnapshotList : %s : Start", s.name)
}
if !s.logged {
return fmt.Errorf("Client %s not logged in.", s.name)
}
session, err := s.client.NewSession()
if err != nil {
if *debugFlag {
log.Printf("SSHConfig.getSnapshotList : %s : client.NewSession() : %s", s.name, err)
}
return err
}
var b bytes.Buffer
session.Stdout = &b
err = session.Run("TZ=\"" + cfg.Timezone + "\" zfs list -H -t snapshot -o name")
if err != nil {
if *debugFlag {
log.Printf("SSHConfig.getSnapshotList : %s : session.Run() : %s", s.name, err)
}
return err
}
s.snapshot = make([]Snapshot, 0)
csvReader := csv.NewReader(&b)
csvReader.Comma = '\t'
csvReader.FieldsPerRecord = 1
csvData, err := csvReader.ReadAll()
if err != nil {
if *debugFlag {
log.Printf("SSHConfig.getSnapshotList : %s : csvReader.ReadAll() : %s", s.name, err)
}
return err
}
for _, rec := range csvData {
s.snapshot = append(s.snapshot, Snapshot(rec[0]))
}
if *debugFlag {
log.Printf("SSHConfig.getSnapshotList : %s : read %d zfs snapshots", s.name, len(s.snapshot))
}
session.Close()
return nil
}
func (s *SSHConfig) exec(cmd string) (b *bytes.Buffer, err error) {
if *debugFlag {
log.Printf("SSHConfig.exec : %s : Start %s", s.name, cmd)
}
session, err := s.client.NewSession()
if err != nil {
if *debugFlag {
log.Printf("SSHConfig.exec : %s : client().NewSession(%s) : %s", s.name, cmd, err)
}
return
}
var buf bytes.Buffer
b = &buf
session.Stdout = b
err = session.Run("TZ=\"" + cfg.Timezone + "\" " + cmd)
if err != nil {
if *debugFlag {
log.Printf("SSHConfig.exec : session(%s).Run(%s) : %s", s.name, cmd, err)
}
return
}
session.Close()
return
}