diff options
Diffstat (limited to 'internal/zfsutil')
| -rw-r--r-- | internal/zfsutil/zfsutil.go | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/internal/zfsutil/zfsutil.go b/internal/zfsutil/zfsutil.go new file mode 100644 index 0000000..3d3bd40 --- /dev/null +++ b/internal/zfsutil/zfsutil.go @@ -0,0 +1,55 @@ +// Package zfsutil wraps the zfs(8)/jail(8) CLI operations Skiff relies on as +// its only state store - no separate app-metadata database. +package zfsutil + +import ( + "context" + "fmt" + "io" + "strings" + + "skiff/internal/sh" +) + +func Exists(ctx context.Context, dataset string) bool { + _, err := sh.Output(ctx, "", "zfs", "list", "-H", "-o", "name", dataset) + return err == nil +} + +// Clone creates a new dataset from a (read-only) snapshot of base, mounted +// at mountpoint. base must already have a snapshot named baseSnapshot. +func Clone(ctx context.Context, out io.Writer, base, baseSnapshot, dataset, mountpoint string) error { + src := fmt.Sprintf("%s@%s", base, baseSnapshot) + return sh.Run(ctx, out, "", "zfs", "clone", "-o", "mountpoint="+mountpoint, src, dataset) +} + +func Snapshot(ctx context.Context, out io.Writer, dataset, tag string) error { + return sh.Run(ctx, out, "", "zfs", "snapshot", fmt.Sprintf("%s@%s", dataset, tag)) +} + +// Rollback discards everything written to dataset since the snapshot named +// tag, including any newer snapshots. This is Skiff's entire undo mechanism: +// used both for the automatic post-health-check-failure rollback and for a +// manual `skiff rollback` days later. +func Rollback(ctx context.Context, out io.Writer, dataset, tag string) error { + return sh.Run(ctx, out, "", "zfs", "rollback", "-r", fmt.Sprintf("%s@%s", dataset, tag)) +} + +// Snapshots lists snapshot names (without the dataset@ prefix), newest last. +func Snapshots(ctx context.Context, dataset string) ([]string, error) { + raw, err := sh.Output(ctx, "", "zfs", "list", "-H", "-t", "snapshot", "-o", "name", "-s", "creation", "-r", dataset) + if err != nil { + return nil, err + } + var names []string + for _, line := range strings.Split(strings.TrimSpace(raw), "\n") { + if line == "" { + continue + } + parts := strings.SplitN(line, "@", 2) + if len(parts) == 2 { + names = append(names, parts[1]) + } + } + return names, nil +} |
