package zfs import ( "errors" "fmt" "github.com/mistifyio/go-zfs" "github.com/sirupsen/logrus" "github.com/wagoodman/dive/dive/filetree" "github.com/wagoodman/dive/dive/image" "os" "os/exec" "strings" ) type resolver struct{} func NewResolverFromEngine() *resolver { return &resolver{} } func (r *resolver) Build(args []string) (*image.Image, error) { return nil, errors.New("can't build ZFS") } func (r *resolver) Fetch(id string) (*image.Image, error) { img, err := r.resolveFromZfsDataset(id) if err == nil { return img, err } return nil, fmt.Errorf("unable to resolve image '%s': %+v", id, err) } func filterOutDatasetSnapshots(snapshots []*zfs.Dataset, datasetName string) []*zfs.Dataset { var result []*zfs.Dataset for _, snap := range snapshots { if strings.HasPrefix(snap.Name, datasetName+"@") { result = append(result, snap) } } return result } func iterate(path string) ([]string, error) { cmd := exec.Command("find", path, "-type", "f", "-o", "-type", "d") //cmd.Stderr = os.Stderr stdout, _ := cmd.Output() //if err != nil { // println("Error is") // println(err.Error()) // panic(err) //} //println("Returning iterate") //println(stdout) //time.Sleep(100000) return strings.Split(string(stdout), "\n"), nil } func (r *resolver) resolveFromZfsDataset(id string) (*image.Image, error) { ds, err := zfs.GetDataset(id) if err != nil { return nil, err } snapshots, err := ds.Snapshots() snapshots = filterOutDatasetSnapshots(snapshots, ds.Name) if err != nil { return nil, err } var trees []*filetree.FileTree var layers []*image.Layer dsMountpoint := ds.Mountpoint if dsMountpoint == "" { return nil, errors.New("Failed to find mountpoint for " + ds.Name) } for idx, snap := range snapshots { snapName := strings.TrimPrefix(snap.Name, ds.Name+"@") logrus.Info("Processing snapshot " + snapName) snapMountpoint := dsMountpoint + ".zfs/snapshot/" + snapName tree := filetree.NewFileTree() files, err := iterate(snapMountpoint) if err != nil { return nil, err } for _, realPath := range files { virtualPath := strings.TrimPrefix(realPath, snapMountpoint) if virtualPath == "" { continue } osStat, err := os.Lstat(realPath) if err != nil { return nil, err } //print("Adding virtualPath: " + virtualPath) println("Adding realPath: " + realPath) _, _, err = tree.AddPath(virtualPath, filetree.NewFileInfo(realPath, virtualPath, osStat)) if err != nil { return nil, err } } trees = append(trees, tree) layers = append(layers, &image.Layer{ Id: snapName, Index: idx, Command: "zfs snapshot command", Size: uint64(tree.VisibleSize()), Tree: tree, Names: make([]string, 0), Digest: "zfs snapshot digest-" + snapName, }) } logrus.Info("Returning resolved zfs image obj") return &image.Image{ Trees: trees, Layers: layers, }, nil }