Some checks failed
Validations / Static analysis (push) Failing after 32m53s
Validations / Unit tests (ubuntu-latest) (push) Failing after 10m54s
Validations / Build snapshot artifacts (push) Failing after 32m5s
Validations / Acceptance tests (Linux) (push) Has been skipped
Validations / Acceptance tests (Mac) (push) Has been skipped
Validations / Acceptance tests (Windows) (push) Has been skipped
125 lines
2.9 KiB
Go
125 lines
2.9 KiB
Go
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
|
|
}
|