diff --git a/go.mod b/go.mod index e4879244bd4..30723289177 100644 --- a/go.mod +++ b/go.mod @@ -395,7 +395,7 @@ replace ( github.com/mholt/certmagic => github.com/mholt/certmagic v0.6.2-0.20190624175158-6a42ef9fe8c2 github.com/miekg/dns => github.com/miekg/dns v1.1.4 github.com/mindprince/gonvml => github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989 - github.com/mistifyio/go-zfs => github.com/mistifyio/go-zfs v2.1.1+incompatible + github.com/mistifyio/go-zfs => github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible github.com/mitchellh/go-homedir => github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-ps => github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936 github.com/mitchellh/go-wordwrap => github.com/mitchellh/go-wordwrap v1.0.0 diff --git a/go.sum b/go.sum index 951d20fc8d1..d82acd505c8 100644 --- a/go.sum +++ b/go.sum @@ -361,8 +361,8 @@ github.com/miekg/dns v1.1.4 h1:rCMZsU2ScVSYcAsOXgmC6+AKOK+6pmQTOcw03nfwYV0= github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989 h1:PS1dLCGtD8bb9RPKJrc8bS7qHL6JnW1CZvwzH9dPoUs= github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY= -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/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible h1:aKW/4cBs+yK6gpqU3K/oIwk9Q/XICqd3zOX/UFuvqmk= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+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/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= diff --git a/vendor/github.com/mistifyio/go-zfs/.travis.yml b/vendor/github.com/mistifyio/go-zfs/.travis.yml new file mode 100644 index 00000000000..acbd39cefe9 --- /dev/null +++ b/vendor/github.com/mistifyio/go-zfs/.travis.yml @@ -0,0 +1,43 @@ +language: go +dist: trusty +sudo: required +cache: + directories: + - $HOME/.ccache + - $HOME/zfs + +branches: + only: + - master + +env: + - rel=0.6.5.11 + - rel=0.7.6 + +go: + - "1.10.x" + - master + +before_install: + - export MAKEFLAGS=-j$(($(grep -c '^processor' /proc/cpuinfo) * 2 + 1)) + - export PATH=/usr/lib/ccache:$PATH + - go get github.com/alecthomas/gometalinter + - gometalinter --install --update + - sudo apt-get update -y && sudo apt-get install -y libattr1-dev libblkid-dev linux-headers-$(uname -r) tree uuid-dev + - mkdir -p $HOME/zfs + - cd $HOME/zfs + - [[ -d spl-$rel.tar.gz ]] || curl -L https://github.com/zfsonlinux/zfs/releases/download/zfs-$rel/spl-$rel.tar.gz | tar xz + - [[ -d zfs-$rel.tar.gz ]] || curl -L https://github.com/zfsonlinux/zfs/releases/download/zfs-$rel/zfs-$rel.tar.gz | tar xz + - (cd spl-$rel && ./configure --prefix=/usr && make && sudo make install) + - (cd zfs-$rel && ./configure --prefix=/usr && make && sudo make install) + - sudo modprobe zfs + - cd $TRAVIS_BUILD_DIR + +script: + - sudo -E $(which go) test -v ./... + - gometalinter --vendor --vendored-linters ./... || true + - gometalinter --errors --vendor --vendored-linters ./... + +notifications: + email: false + irc: "chat.freenode.net#cerana" diff --git a/vendor/github.com/mistifyio/go-zfs/BUILD b/vendor/github.com/mistifyio/go-zfs/BUILD index 3c54d6601b9..03376510fb8 100644 --- a/vendor/github.com/mistifyio/go-zfs/BUILD +++ b/vendor/github.com/mistifyio/go-zfs/BUILD @@ -5,12 +5,15 @@ go_library( srcs = [ "error.go", "utils.go", + "utils_notsolaris.go", + "utils_solaris.go", "zfs.go", "zpool.go", ], importmap = "k8s.io/kubernetes/vendor/github.com/mistifyio/go-zfs", importpath = "github.com/mistifyio/go-zfs", visibility = ["//visibility:public"], + deps = ["//vendor/github.com/google/uuid:go_default_library"], ) filegroup( diff --git a/vendor/github.com/mistifyio/go-zfs/README.md b/vendor/github.com/mistifyio/go-zfs/README.md index 2515e588e0d..fef80d727b1 100644 --- a/vendor/github.com/mistifyio/go-zfs/README.md +++ b/vendor/github.com/mistifyio/go-zfs/README.md @@ -29,7 +29,7 @@ The tests have decent examples for most functions. ```go //assuming a zpool named test -//error handling ommitted +//error handling omitted f, err := zfs.CreateFilesystem("test/snapshot-test", nil) diff --git a/vendor/github.com/mistifyio/go-zfs/utils.go b/vendor/github.com/mistifyio/go-zfs/utils.go index d5b73534940..c18c2c3dae6 100644 --- a/vendor/github.com/mistifyio/go-zfs/utils.go +++ b/vendor/github.com/mistifyio/go-zfs/utils.go @@ -2,12 +2,16 @@ package zfs import ( "bytes" + "errors" "fmt" "io" "os/exec" "regexp" + "runtime" "strconv" "strings" + + "github.com/google/uuid" ) type command struct { @@ -34,16 +38,17 @@ func (c *command) Run(arg ...string) ([][]string, error) { } cmd.Stderr = &stderr - debug := strings.Join([]string{cmd.Path, strings.Join(cmd.Args, " ")}, " ") - if logger != nil { - logger.Log(cmd.Args) - } + id := uuid.New().String() + joinedArgs := strings.Join(cmd.Args, " ") + + logger.Log([]string{"ID:" + id, "START", joinedArgs}) err := cmd.Run() + logger.Log([]string{"ID:" + id, "FINISH"}) if err != nil { return nil, &Error{ Err: err, - Debug: debug, + Debug: strings.Join([]string{cmd.Path, joinedArgs[1:]}, " "), Stderr: stderr.String(), } } @@ -88,34 +93,50 @@ func setUint(field *uint64, value string) error { } func (ds *Dataset) parseLine(line []string) error { - prop := line[1] - val := line[2] - var err error - switch prop { - case "available": - err = setUint(&ds.Avail, val) - case "compression": - setString(&ds.Compression, val) - case "mountpoint": - setString(&ds.Mountpoint, val) - case "quota": - err = setUint(&ds.Quota, val) - case "type": - setString(&ds.Type, val) - case "origin": - setString(&ds.Origin, val) - case "used": - err = setUint(&ds.Used, val) - case "volsize": - err = setUint(&ds.Volsize, val) - case "written": - err = setUint(&ds.Written, val) - case "logicalused": - err = setUint(&ds.Logicalused, val) + if len(line) != len(dsPropList) { + return errors.New("Output does not match what is expected on this platform") } - return err + setString(&ds.Name, line[0]) + setString(&ds.Origin, line[1]) + + if err = setUint(&ds.Used, line[2]); err != nil { + return err + } + if err = setUint(&ds.Avail, line[3]); err != nil { + return err + } + + setString(&ds.Mountpoint, line[4]) + setString(&ds.Compression, line[5]) + setString(&ds.Type, line[6]) + + if err = setUint(&ds.Volsize, line[7]); err != nil { + return err + } + if err = setUint(&ds.Quota, line[8]); err != nil { + return err + } + if err = setUint(&ds.Referenced, line[9]); err != nil { + return err + } + + if runtime.GOOS == "solaris" { + return nil + } + + if err = setUint(&ds.Written, line[10]); err != nil { + return err + } + if err = setUint(&ds.Logicalused, line[11]); err != nil { + return err + } + if err = setUint(&ds.Usedbydataset, line[12]); err != nil { + return err + } + + return nil } /* @@ -264,7 +285,8 @@ func parseInodeChanges(lines [][]string) ([]*InodeChange, error) { } func listByType(t, filter string) ([]*Dataset, error) { - args := []string{"get", "-rHp", "-t", t, "all"} + args := []string{"list", "-rHp", "-t", t, "-o", dsPropListOptions} + if filter != "" { args = append(args, filter) } @@ -307,6 +329,8 @@ func (z *Zpool) parseLine(line []string) error { var err error switch prop { + case "name": + setString(&z.Name, val) case "health": setString(&z.Health, val) case "allocated": @@ -315,6 +339,22 @@ func (z *Zpool) parseLine(line []string) error { err = setUint(&z.Size, val) case "free": err = setUint(&z.Free, val) + case "fragmentation": + // Trim trailing "%" before parsing uint + i := strings.Index(val, "%") + if i < 0 { + i = len(val) + } + err = setUint(&z.Fragmentation, val[:i]) + case "readonly": + z.ReadOnly = val == "on" + case "freeing": + err = setUint(&z.Freeing, val) + case "leaked": + err = setUint(&z.Leaked, val) + case "dedupratio": + // Trim trailing "x" before parsing float64 + z.DedupRatio, err = strconv.ParseFloat(val[:len(val)-1], 64) } return err } diff --git a/vendor/github.com/mistifyio/go-zfs/utils_notsolaris.go b/vendor/github.com/mistifyio/go-zfs/utils_notsolaris.go new file mode 100644 index 00000000000..a46f73060d1 --- /dev/null +++ b/vendor/github.com/mistifyio/go-zfs/utils_notsolaris.go @@ -0,0 +1,17 @@ +// +build !solaris + +package zfs + +import ( + "strings" +) + +// List of ZFS properties to retrieve from zfs list command on a non-Solaris platform +var dsPropList = []string{"name", "origin", "used", "available", "mountpoint", "compression", "type", "volsize", "quota", "referenced", "written", "logicalused", "usedbydataset"} + +var dsPropListOptions = strings.Join(dsPropList, ",") + +// List of Zpool properties to retrieve from zpool list command on a non-Solaris platform +var zpoolPropList = []string{"name", "health", "allocated", "size", "free", "readonly", "dedupratio", "fragmentation", "freeing", "leaked"} +var zpoolPropListOptions = strings.Join(zpoolPropList, ",") +var zpoolArgs = []string{"get", "-p", zpoolPropListOptions} diff --git a/vendor/github.com/mistifyio/go-zfs/utils_solaris.go b/vendor/github.com/mistifyio/go-zfs/utils_solaris.go new file mode 100644 index 00000000000..0a7e90f2227 --- /dev/null +++ b/vendor/github.com/mistifyio/go-zfs/utils_solaris.go @@ -0,0 +1,17 @@ +// +build solaris + +package zfs + +import ( + "strings" +) + +// List of ZFS properties to retrieve from zfs list command on a Solaris platform +var dsPropList = []string{"name", "origin", "used", "available", "mountpoint", "compression", "type", "volsize", "quota", "referenced"} + +var dsPropListOptions = strings.Join(dsPropList, ",") + +// List of Zpool properties to retrieve from zpool list command on a non-Solaris platform +var zpoolPropList = []string{"name", "health", "allocated", "size", "free", "readonly", "dedupratio"} +var zpoolPropListOptions = strings.Join(zpoolPropList, ",") +var zpoolArgs = []string{"get", "-p", zpoolPropListOptions} diff --git a/vendor/github.com/mistifyio/go-zfs/zfs.go b/vendor/github.com/mistifyio/go-zfs/zfs.go index a1d740e07e5..4e5087ffe28 100644 --- a/vendor/github.com/mistifyio/go-zfs/zfs.go +++ b/vendor/github.com/mistifyio/go-zfs/zfs.go @@ -32,9 +32,10 @@ type Dataset struct { Type string Written uint64 Volsize uint64 - Usedbydataset uint64 Logicalused uint64 + Usedbydataset uint64 Quota uint64 + Referenced uint64 } // InodeType is the type of inode as reported by Diff @@ -92,12 +93,20 @@ type Logger interface { Log(cmd []string) } -var logger Logger +type defaultLogger struct{} + +func (*defaultLogger) Log(cmd []string) { + return +} + +var logger Logger = &defaultLogger{} // SetLogger set a log handler to log all commands including arguments before // they are executed func SetLogger(l Logger) { - logger = l + if l != nil { + logger = l + } } // zfs is a helper function to wrap typical calls to zfs. @@ -137,7 +146,7 @@ func Volumes(filter string) ([]*Dataset, error) { // GetDataset retrieves a single ZFS dataset by name. This dataset could be // any valid ZFS dataset type, such as a clone, filesystem, snapshot, or volume. func GetDataset(name string) (*Dataset, error) { - out, err := zfs("get", "-Hp", "all", name) + out, err := zfs("list", "-Hp", "-o", dsPropListOptions, name) if err != nil { return nil, err } @@ -172,6 +181,46 @@ func (d *Dataset) Clone(dest string, properties map[string]string) (*Dataset, er return GetDataset(dest) } +// Unmount unmounts currently mounted ZFS file systems. +func (d *Dataset) Unmount(force bool) (*Dataset, error) { + if d.Type == DatasetSnapshot { + return nil, errors.New("cannot unmount snapshots") + } + args := make([]string, 1, 3) + args[0] = "umount" + if force { + args = append(args, "-f") + } + args = append(args, d.Name) + _, err := zfs(args...) + if err != nil { + return nil, err + } + return GetDataset(d.Name) +} + +// Mount mounts ZFS file systems. +func (d *Dataset) Mount(overlay bool, options []string) (*Dataset, error) { + if d.Type == DatasetSnapshot { + return nil, errors.New("cannot mount snapshots") + } + args := make([]string, 1, 5) + args[0] = "mount" + if overlay { + args = append(args, "-O") + } + if options != nil { + args = append(args, "-o") + args = append(args, strings.Join(options, ",")) + } + args = append(args, d.Name) + _, err := zfs(args...) + if err != nil { + return nil, err + } + return GetDataset(d.Name) +} + // ReceiveSnapshot receives a ZFS stream from the input io.Reader, creates a // new snapshot with the specified name, and streams the input data into the // newly-created snapshot. @@ -259,7 +308,7 @@ func (d *Dataset) SetProperty(key, val string) error { // A full list of available ZFS properties may be found here: // https://www.freebsd.org/cgi/man.cgi?zfs(8). func (d *Dataset) GetProperty(key string) (string, error) { - out, err := zfs("get", key, d.Name) + out, err := zfs("get", "-H", key, d.Name) if err != nil { return "", err } @@ -267,6 +316,26 @@ func (d *Dataset) GetProperty(key string) (string, error) { return out[0][2], nil } +// Rename renames a dataset. +func (d *Dataset) Rename(name string, createParent bool, recursiveRenameSnapshots bool) (*Dataset, error) { + args := make([]string, 3, 5) + args[0] = "rename" + args[1] = d.Name + args[2] = name + if createParent { + args = append(args, "-p") + } + if recursiveRenameSnapshots { + args = append(args, "-r") + } + _, err := zfs(args...) + if err != nil { + return d, err + } + + return GetDataset(name) +} + // Snapshots returns a slice of all ZFS snapshots of a given dataset. func (d *Dataset) Snapshots() ([]*Dataset, error) { return Snapshots(d.Name) @@ -335,13 +404,14 @@ func (d *Dataset) Rollback(destroyMoreRecent bool) error { // A recursion depth may be specified, or a depth of 0 allows unlimited // recursion. func (d *Dataset) Children(depth uint64) ([]*Dataset, error) { - args := []string{"get", "-t", "all", "-Hp", "all"} + args := []string{"list"} if depth > 0 { args = append(args, "-d") args = append(args, strconv.FormatUint(depth, 10)) } else { args = append(args, "-r") } + args = append(args, "-t", "all", "-Hp", "-o", dsPropListOptions) args = append(args, d.Name) out, err := zfs(args...) diff --git a/vendor/github.com/mistifyio/go-zfs/zpool.go b/vendor/github.com/mistifyio/go-zfs/zpool.go index 6ba52d30cb0..d8db945d708 100644 --- a/vendor/github.com/mistifyio/go-zfs/zpool.go +++ b/vendor/github.com/mistifyio/go-zfs/zpool.go @@ -15,11 +15,16 @@ const ( // Zpool is a ZFS zpool. A pool is a top-level structure in ZFS, and can // contain many descendent datasets. type Zpool struct { - Name string - Health string - Allocated uint64 - Size uint64 - Free uint64 + Name string + Health string + Allocated uint64 + Size uint64 + Free uint64 + Fragmentation uint64 + ReadOnly bool + Freeing uint64 + Leaked uint64 + DedupRatio float64 } // zpool is a helper function to wrap typical calls to zpool. @@ -30,7 +35,9 @@ func zpool(arg ...string) ([][]string, error) { // GetZpool retrieves a single ZFS zpool by name. func GetZpool(name string) (*Zpool, error) { - out, err := zpool("get", "all", "-p", name) + args := zpoolArgs + args = append(args, name) + out, err := zpool(args...) if err != nil { return nil, err } diff --git a/vendor/modules.txt b/vendor/modules.txt index db533f15e3f..60f9f51698a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -518,7 +518,7 @@ github.com/matttproud/golang_protobuf_extensions/pbutil github.com/miekg/dns # github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989 => github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989 github.com/mindprince/gonvml -# github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible => github.com/mistifyio/go-zfs v2.1.1+incompatible +# github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible => github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible github.com/mistifyio/go-zfs # github.com/mitchellh/go-wordwrap v1.0.0 => github.com/mitchellh/go-wordwrap v1.0.0 github.com/mitchellh/go-wordwrap