diff --git a/main.go b/main.go index 58e18f2..a4dca5f 100644 --- a/main.go +++ b/main.go @@ -57,7 +57,9 @@ func processAll(now time.Time, conf *conf.Config, zfsExecutor zfs.Executor) ([]z list := zfs.SnapshotList{} list, err := list.NewSnapshotListFromDataset(zfsExecutor, dataset) if err != nil { - return nil, err + // Write and Continue when dataset is not found + fmt.Fprintf(os.Stderr, "%s\n", err.Error()) + continue } list.KeepNamed(plan.Protect) list.KeepLatest(plan.Latest) @@ -114,6 +116,9 @@ func clean(cmd *cobra.Command, args []string) error { // We can ignore errors here, we're exiting anyway. _ = syscall.Flock(fd, syscall.LOCK_UN) }() + if err := zfsExecutor.HasZFSCommand(); err != nil { + return err + } lists, err := processAll(now, conf, zfsExecutor) if err != nil { return err diff --git a/main_test.go b/main_test.go index c117640..c0745b2 100644 --- a/main_test.go +++ b/main_test.go @@ -1,7 +1,6 @@ package main import ( - "errors" "github.com/cego/zfs-cleaner/zfs" "io/ioutil" "os" @@ -115,6 +114,10 @@ type testExecutor struct { getSnapshotListError error } +func (t *testExecutor) HasZFSCommand() error { + return nil +} + func (t *testExecutor) GetSnapshotList(dataset string) ([]byte, error) { return t.getSnapshotListResult, t.getSnapshotListError } @@ -175,37 +178,6 @@ playground/fs1@snap5 1492989587 } } -func TestProcessAllFail(t *testing.T) { - zfsTestExecutor := testExecutor{ - getSnapshotListError: errors.New("test fail"), - } - - conf := &conf.Config{ - Plans: []conf.Plan{ - { - Name: "buh", - Paths: []string{"playground/fs1"}, - Latest: 10, - Periods: []conf.Period{ - { - Frequency: 24 * time.Hour, - Age: 30 * 24 * time.Hour, - }, - }, - }, - }, - } - - lists, err := processAll(time.Now(), conf, &zfsTestExecutor) - if err == nil { - t.Errorf("processAll() did not return error") - } - - if lists != nil { - t.Errorf("processAll() returned lists") - } -} - func TestMainNoArguments(t *testing.T) { os.Args = []string{os.Args[0]} defer func() { @@ -228,39 +200,6 @@ func TestMainNoConfig(t *testing.T) { main() } -func TestMainNoZFS(t *testing.T) { - content := []byte(` -plan buh { -path /buh -keep 1d for 30d -keep latest 10 -} -`) - tmpfile, err := ioutil.TempFile("/dev/shm", "test.TestReadConfSyntaxError") - if err != nil { - t.Fatalf("Failed to create config file: %s", err.Error()) - } - defer os.Remove(tmpfile.Name()) - - _, err = tmpfile.Write(content) - if err != nil { - t.Fatalf("Failed to write config file: %s", err.Error()) - } - - err = tmpfile.Close() - if err != nil { - t.Fatalf("Failed to close config file: %s", err.Error()) - } - - os.Args = []string{os.Args[0], tmpfile.Name()} - defer func() { - if r := recover(); r == nil { - t.Errorf("The code did not panic for no arguments") - } - }() - main() -} - func TestMainFull(t *testing.T) { now = time.Unix(1492993419, 0) verbose = true diff --git a/zfs/SnapshotList_test.go b/zfs/SnapshotList_test.go index 7f64950..35d913c 100644 --- a/zfs/SnapshotList_test.go +++ b/zfs/SnapshotList_test.go @@ -45,6 +45,10 @@ type testExecutor struct { getSnapshotListError error } +func (t *testExecutor) HasZFSCommand() error { + return nil +} + func (t *testExecutor) GetSnapshotList(dataset string) ([]byte, error) { return t.getSnapshotListResult, t.getSnapshotListError } diff --git a/zfs/ZfsExecutor.go b/zfs/ZfsExecutor.go index f5d061f..72672be 100644 --- a/zfs/ZfsExecutor.go +++ b/zfs/ZfsExecutor.go @@ -1,12 +1,15 @@ package zfs import ( + "errors" "fmt" + "os" "os/exec" "strings" ) type Executor interface { + HasZFSCommand() error GetSnapshotList(dataset string) ([]byte, error) GetFilesystems() ([]byte, error) HasSnapshot(dataset string) (bool, error) @@ -26,6 +29,17 @@ func NewExecutor() Executor { } } +func (z *executorImpl) HasZFSCommand() error { + if stat, err := os.Stat(z.zfsCommandName); err == nil { + // Is executable by others + if stat.Mode()&0001 != 0 { + return errors.New("ZFS command is not executable") + } + return nil + } + return fmt.Errorf("ZFS command %s not found", z.zfsCommandName) +} + func (z *executorImpl) GetSnapshotList(dataset string) ([]byte, error) { commandArguments := []string{"list", "-t", "snapshot", "-o", "name,creation", "-s", "creation", "-d", "1", "-H", "-p", "-r", dataset} output, err := exec.Command(z.zfsCommandName, commandArguments...).Output()