Implement DatasetMapping + basic ZFS list functionality.

This commit is contained in:
Christian Schwarz
2017-04-26 17:39:16 +02:00
parent 4494afe47f
commit 40f3b530e1
6 changed files with 384 additions and 4 deletions
+102 -4
View File
@@ -1,13 +1,111 @@
package zfs
func InitialSend(snapshot string) (io.Read, error) {
import (
"github.com/zrepl/zrepl/model"
"os/exec"
"bufio"
"strings"
"errors"
"io"
"fmt"
"io/ioutil"
)
func InitialSend(snapshot string) (io.Reader, error) {
return nil, nil
}
func IncrementalSend(from, to string) (io.Reader, error) {
return nil, nil
}
func FilesystemsAtRoot(root string) (fs model.Filesystem, err error) {
_, _ = zfsList("zroot", func(path DatasetPath) bool {
return true
})
return
}
func IncrementalSend(from, to string) (io.Read, error) {
type DatasetPath []string
func (p DatasetPath) ToString() string {
return strings.Join(p, "/")
}
func FilesystemsAtRoot(root string) (model.Filesystem, error) {
func toDatasetPath(s string) DatasetPath {
return strings.Split(s, "/")
}
}
type DatasetFilter func(path DatasetPath) bool
type ZFSError struct {
Stderr []byte
WaitErr error
}
func (e ZFSError) Error() string {
return fmt.Sprintf("zfs exited with error: %s", e.WaitErr.Error())
}
var ZFS_BINARY string = "zfs"
func zfsList(root string, filter DatasetFilter) (datasets []DatasetPath, err error) {
const ZFS_LIST_FIELD_COUNT = 1
cmd := exec.Command(ZFS_BINARY, "list", "-H", "-r",
"-t", "filesystem,volume",
"-o", "name",
root)
var stdout io.Reader
var stderr io.Reader
if stdout, err = cmd.StdoutPipe(); err != nil {
return
}
if stderr, err = cmd.StderrPipe(); err != nil {
return
}
if err = cmd.Start(); err != nil {
return
}
s := bufio.NewScanner(stdout)
buf := make([]byte, 1024)
s.Buffer(buf, 0)
datasets = make([]DatasetPath, 0)
for s.Scan() {
fields := strings.SplitN(s.Text(), "\t", ZFS_LIST_FIELD_COUNT)
if len(fields) != ZFS_LIST_FIELD_COUNT {
err = errors.New("unexpected output")
return
}
dp := toDatasetPath(fields[0])
if filter(dp) {
datasets = append(datasets, dp)
}
}
stderrOutput, err := ioutil.ReadAll(stderr)
if waitErr:= cmd.Wait(); waitErr != nil {
err := ZFSError{
Stderr: stderrOutput,
WaitErr: waitErr,
}
return nil, err
}
return
}