PoC: zfs support
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
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
This commit is contained in:
parent
925cdd8648
commit
534bb92185
@ -2,6 +2,7 @@ package dive
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/wagoodman/dive/dive/image/zfs"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ const (
|
|||||||
SourceDockerEngine
|
SourceDockerEngine
|
||||||
SourcePodmanEngine
|
SourcePodmanEngine
|
||||||
SourceDockerArchive
|
SourceDockerArchive
|
||||||
|
SourceZFS
|
||||||
)
|
)
|
||||||
|
|
||||||
type ImageSource int
|
type ImageSource int
|
||||||
@ -22,10 +24,11 @@ type ImageSource int
|
|||||||
var ImageSources = []string{SourceDockerEngine.String(), SourcePodmanEngine.String(), SourceDockerArchive.String()}
|
var ImageSources = []string{SourceDockerEngine.String(), SourcePodmanEngine.String(), SourceDockerArchive.String()}
|
||||||
|
|
||||||
func (r ImageSource) String() string {
|
func (r ImageSource) String() string {
|
||||||
return [...]string{"unknown", "docker", "podman", "docker-archive"}[r]
|
return [...]string{"unknown", "docker", "podman", "docker-archive", "zfs"}[r]
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseImageSource(r string) ImageSource {
|
func ParseImageSource(r string) ImageSource {
|
||||||
|
|
||||||
switch r {
|
switch r {
|
||||||
case SourceDockerEngine.String():
|
case SourceDockerEngine.String():
|
||||||
return SourceDockerEngine
|
return SourceDockerEngine
|
||||||
@ -57,6 +60,8 @@ func DeriveImageSource(image string) (ImageSource, string) {
|
|||||||
return SourceDockerArchive, imageSource
|
return SourceDockerArchive, imageSource
|
||||||
case "docker-tar":
|
case "docker-tar":
|
||||||
return SourceDockerArchive, imageSource
|
return SourceDockerArchive, imageSource
|
||||||
|
case SourceZFS.String():
|
||||||
|
return SourceZFS, imageSource
|
||||||
}
|
}
|
||||||
return SourceUnknown, ""
|
return SourceUnknown, ""
|
||||||
}
|
}
|
||||||
@ -69,6 +74,8 @@ func GetImageResolver(r ImageSource) (image.Resolver, error) {
|
|||||||
return podman.NewResolverFromEngine(), nil
|
return podman.NewResolverFromEngine(), nil
|
||||||
case SourceDockerArchive:
|
case SourceDockerArchive:
|
||||||
return docker.NewResolverFromArchive(), nil
|
return docker.NewResolverFromArchive(), nil
|
||||||
|
case SourceZFS:
|
||||||
|
return zfs.NewResolverFromEngine(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("unable to determine image resolver")
|
return nil, fmt.Errorf("unable to determine image resolver")
|
||||||
|
124
dive/image/zfs/resolver.go
Normal file
124
dive/image/zfs/resolver.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
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
|
||||||
|
}
|
1
go.mod
1
go.mod
@ -13,6 +13,7 @@ require (
|
|||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
github.com/logrusorgru/aurora v0.0.0-20190803045625-94edacc10f9b
|
github.com/logrusorgru/aurora v0.0.0-20190803045625-94edacc10f9b
|
||||||
github.com/lunixbochs/vtclean v1.0.0
|
github.com/lunixbochs/vtclean v1.0.0
|
||||||
|
github.com/mistifyio/go-zfs v2.1.1+incompatible
|
||||||
github.com/mitchellh/go-homedir v1.1.0
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee
|
github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee
|
||||||
github.com/sergi/go-diff v1.0.0
|
github.com/sergi/go-diff v1.0.0
|
||||||
|
2
go.sum
2
go.sum
@ -112,6 +112,8 @@ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
|
|||||||
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
|
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
|
||||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8=
|
||||||
|
github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
|
Loading…
x
Reference in New Issue
Block a user