summaryrefslogtreecommitdiff
path: root/internal/zfsutil/zfsutil.go
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-08-07 00:03:04 -0500
committerClaude <noreply@anthropic.com>2026-08-07 00:03:04 -0500
commitd1e1c226d9a63432c652d373c039a3ae4430f3a2 (patch)
tree79b72917b757f6807c1beb9872efc2ea694cce6d /internal/zfsutil/zfsutil.go
parentf34ba20fc566ab861179a8ac2fd55eaabbc6a327 (diff)
Guard deploys and config changes against leftover state on retry
- Extract deploy.Run's snapshot -> apply -> restart -> health-check -> rollback-on-failure sequence into deploy.GuardedApply, shared with cmd/skiff's applyConfigChange, which duplicated it verbatim. - Clean up the worktree and snapshot a deploy creates when it fails before cutover (e.g. a failing release-phase migration), so retrying the same sha no longer needs manual cleanup. - Make checkout and snapshotting idempotent for a same-sha retry after a cutover that later got rolled back on a failed health check, where the release dir and snapshot are deliberately left behind by design. - Document the actual cause of a jail not surviving a host reboot: FreeBSD ships no /etc/jail.conf, so boot-time `service jail start` finds nothing to start regardless of jail.conf.d - only name-targeted starts read jail.conf.d directly, which is why manual starts worked.
Diffstat (limited to 'internal/zfsutil/zfsutil.go')
-rw-r--r--internal/zfsutil/zfsutil.go8
1 files changed, 8 insertions, 0 deletions
diff --git a/internal/zfsutil/zfsutil.go b/internal/zfsutil/zfsutil.go
index 8f1b0e2..918289c 100644
--- a/internal/zfsutil/zfsutil.go
+++ b/internal/zfsutil/zfsutil.go
@@ -33,6 +33,14 @@ func Rollback(ctx context.Context, out io.Writer, dataset, tag string) error {
return sh.Run(ctx, out, "", "zfs", "rollback", "-r", snapRef(dataset, tag))
}
+// DestroySnapshot removes a snapshot that was never needed as a rollback
+// target - e.g. one taken right before an apply step that failed before
+// anything actually changed. Left behind, it collides with the same tag on
+// the next retry.
+func DestroySnapshot(ctx context.Context, out io.Writer, dataset, tag string) error {
+ return sh.Run(ctx, out, "", "zfs", "destroy", snapRef(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)