func TestSnapshot(t *testing.T) { nItems := 2484 l, err := zfs.ListSnapshots() if err != nil { t.Error(err) } if len(l) != nItems { t.Errorf("List should countain %d items but had %d", nItems, len(l)) } for _, res := range testSnapshotResult { i := l[res.Idx] if i.Dataset != res.Dataset { t.Errorf("Dataset mismatch for %d: %s != %s", res.Idx, i.Dataset, res.Dataset) } if i.Snapshot != res.Snapshot { t.Errorf("Snapshot mismatch for %d: %s != %s", res.Idx, i.Snapshot, res.Snapshot) } if i.Used != res.Used { t.Errorf("Used mismatch for %d: %d != %d", res.Idx, i.Used, res.Used) } if i.Refer != res.Refer { t.Errorf("Refer mismatch for %d: %d != %d", res.Idx, i.Refer, res.Refer) } if i.Creation != res.Creation { t.Errorf("Type mismatch for %d: %d != %d", res.Idx, i.Creation, res.Creation) } } }
func server() { bstdin := bufio.NewReader(os.Stdin) e := gob.NewEncoder(os.Stdout) d := gob.NewDecoder(bstdin) negotiateVersion(e, d) logf(VERBOSE, "server: starting up\n") var c Command for { err := d.Decode(&c) if err == io.EOF { break } panicOn(err) switch c.Command { case CmdListSnapshots: logf(DEBUG, "server: listing snapshots\n") s, _ := zfs.ListSnapshots(c.Params[0]) err = e.Encode(s) panicOn(err) case CmdReceive: logf(DEBUG, "server: zfs recv %v\n", c.Params) receive(c, e, bstdin) } } }
func client(ds, host string) { var command Command var sourceSs string var serverDs string if strings.ContainsRune(host, ':') { fs := strings.SplitN(host, ":", 2) host = fs[0] serverDs = fs[1] } else { serverDs = ds } if strings.ContainsRune(ds, '@') { fs := strings.SplitN(ds, "@", 2) ds = fs[0] sourceSs = fs[1] } sshCmd := exec.Command("ssh", host, opts.ZsyncPath, "--server") stdin, err := sshCmd.StdinPipe() panicOn(err) stdout, err := sshCmd.StdoutPipe() panicOn(err) stderr, err := sshCmd.StderrPipe() panicOn(err) go printLines("remote: ", stderr) err = sshCmd.Start() panicOn(err) e := gob.NewEncoder(stdin) d := gob.NewDecoder(stdout) negotiateVersion(e, d) command = Command{Command: CmdListSnapshots, Params: []string{serverDs}} err = e.Encode(&command) panicOn(err) var serverSnapshots []zfs.SnapshotEntry err = d.Decode(&serverSnapshots) panicOn(err) clientSnapshots, err := zfs.ListSnapshots(ds) panicOn(err) var toSend *zfs.SnapshotEntry if sourceSs != "" { for i, s := range clientSnapshots { if s.Snapshot == sourceSs { toSend = &s clientSnapshots = clientSnapshots[:i+1] break } } } else { toSend = &clientSnapshots[len(clientSnapshots)-1] logf(VERBOSE, "zsync: our latest: %s@%s\n", toSend.Dataset, toSend.Snapshot) } if toSend == nil { logf(INFO, "zsync: no snapshot to send\n") return } latest := latestCommon(serverSnapshots, clientSnapshots) if latest != nil { logf(VERBOSE, "zsync: snapshot in common: %s@%s\n", latest.Dataset, latest.Snapshot) if toSend.Snapshot == latest.Snapshot { logf(INFO, "zsync: nothing to send (destination in sync)\n") return } } else { logf(VERBOSE, "zsync: remote dataset missing or no snapshots in common\n") } params := []string{"send"} if opts.Recursive { params = append(params, "-R") } if latest != nil { params = append(params, "-I", "@"+latest.Snapshot) } params = append(params, ds+"@"+toSend.Snapshot) sendCmd := exec.Command("zfs", params...) stream, err := sendCmd.StdoutPipe() panicOn(err) sendStderr, err := sendCmd.StderrPipe() panicOn(err) go printLines("zfs send: ", sendStderr) err = sendCmd.Start() panicOn(err) params = nil if opts.Rollback { params = append(params, "-F") } if opts.NoMount { params = append(params, "-u") } params = append(params, serverDs) sc := Command{Command: CmdReceive, Params: params} err = e.Encode(sc) panicOn(err) logf(VERBOSE, "zsync: sending %s@%s\n", toSend.Dataset, toSend.Snapshot) t0 := time.Now() bufout := bufio.NewWriterSize(stdin, opts.bufferBytes) chunkout := ChunkedWriter{bufout} tot, err := io.Copy(chunkout, stream) panicOn(err) err = chunkout.Flush() panicOn(err) err = bufout.Flush() panicOn(err) err = sendCmd.Wait() panicOn(err) err = d.Decode(&command) panicOn(err) stdin.Close() err = sshCmd.Wait() panicOn(err) td := time.Since(t0) logf(INFO, "zsync: sent %s@%s; %sB in %.2f seconds (%sB/s)\n", toSend.Dataset, toSend.Snapshot, toSi(int(tot)), td.Seconds(), toSi(int(float64(tot)/td.Seconds()))) }