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 }