commit f08671aee93ccafc0896c3eda2d084236db0a3e7 Author: Bill Thiede Date: Mon Oct 9 20:04:59 2017 -0700 Simple program to mimic scp. diff --git a/zfs_replication_exporter.go b/zfs_replication_exporter.go new file mode 100644 index 0000000..f535463 --- /dev/null +++ b/zfs_replication_exporter.go @@ -0,0 +1,103 @@ +package main + +import ( + "flag" + "fmt" + "io" + "log" + "os" + "strings" + "time" + + "golang.org/x/crypto/ssh" + + "xinu.tv/thumbnailer/auth" + "xinu.tv/thumbnailer/scp" +) + +var ( + host = flag.String("host", "localhost:22", "host:port to scp from") + user = flag.String("user", os.Getenv("USER"), "ssh user") +) + +func checkFatal(err error) { + if err != nil { + log.Fatal(err) + } +} + +func progress(w io.Writer, r io.Reader, size int64) error { + const ( + chunkSize = 1 << 10 + width = 50 + ) + var err error + total, bLast := int64(0), int64(0) + tLast := time.Now() + defer fmt.Println() + for { + var n int64 + n, err = io.CopyN(w, r, chunkSize) + total += n + bLast += n + if time.Since(tLast) > (300 * time.Millisecond) { + kbps := float64(bLast) / time.Since(tLast).Seconds() / 1024 + frac := int(total * width / size) + fmt.Printf("\rDownloaded: %s>%s| %.2f Kb/s", strings.Repeat("=", frac), + strings.Repeat(" ", width-frac), kbps) + tLast = time.Now() + bLast = 0 + } + + if err != nil { + break + } + } + if err == io.EOF { + return nil + } + return err +} + +var sink, _ = os.Create(os.DevNull) + +func main() { + flag.Parse() + ams, err := auth.NewPublicKey() + checkFatal(err) + + // An SSH client is represented with a ClientConn. + // + // To authenticate with the remote server you must pass at least one + // implementation of ClientAuth via the Auth field in ClientConfig. + config := &ssh.ClientConfig{ + User: *user, + Auth: ams, + // TODO(wathiede); use FixedHostKey? + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + } + client, err := ssh.Dial("tcp", *host, config) + checkFatal(err) + + for _, fn := range flag.Args() { + log.Println("Fetching", fn) + // Each ClientConn can support multiple interactive sessions, + // represented by a Session. + session, err := client.NewSession() + checkFatal(err) + + f, err := scp.ScpFrom(session, fn) + if err != nil { + log.Println(err) + continue + } + + log.Println(f.Name, f.Perm, f.Size) + + err = progress(sink, f, f.Size) + checkFatal(err) + + checkFatal(f.Close()) + checkFatal(session.Close()) + } +}