From 1524b7d2c3648ccd158671cb0dd8b7cd55a4ba2a Mon Sep 17 00:00:00 2001 From: Artyom Kartasov Date: Sat, 23 Aug 2025 13:16:51 +0000 Subject: [PATCH] fix: clean up clone dataset on destroy --- engine/internal/cloning/base.go | 5 +++ engine/internal/provision/mode_local.go | 42 +++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/engine/internal/cloning/base.go b/engine/internal/cloning/base.go index e5edb759..be3e2b20 100644 --- a/engine/internal/cloning/base.go +++ b/engine/internal/cloning/base.go @@ -387,8 +387,13 @@ func (c *Base) destroyClone(cloneID string, w *CloneWrapper) { if w.Clone.Snapshot != nil { c.decrementCloneNumber(w.Clone.Snapshot.ID) } + c.observingCh <- cloneID + if err := c.provision.CleanupCloneDataset(w.Clone, w.Clone.Snapshot.Pool); err != nil { + log.Errf("failed to cleanup clone dataset: %v", err) + } + c.SaveClonesState() c.webhookCh <- webhooks.CloneEvent{ diff --git a/engine/internal/provision/mode_local.go b/engine/internal/provision/mode_local.go index 7bc89cab..1d9e4958 100644 --- a/engine/internal/provision/mode_local.go +++ b/engine/internal/provision/mode_local.go @@ -571,6 +571,48 @@ func (p *Provisioner) StopAllSessions(exceptClones map[string]struct{}) error { return nil } +func reviewDown(repo *models.Repo, cloneDataset string) string { + for snapshotID := range repo.Snapshots { + if strings.HasPrefix(snapshotID, cloneDataset) { + return snapshotID + } + } + + return "" +} + +// CleanupCloneDataset removes a clone dataset. +func (p *Provisioner) CleanupCloneDataset(clone *models.Clone, pool string) error { + if clone.Snapshot == nil { + return fmt.Errorf("clone has no snapshot, so the pool cannot be determined. Skip cleanup") + } + + fsm, err := p.pm.GetFSManager(clone.Snapshot.Pool) + if err != nil { + return fmt.Errorf("cannot work with pool %s: %w", pool, err) + } + + repo, err := fsm.GetRepo() + if err != nil { + return fmt.Errorf("failed to get snapshots: %w", err) + } + + snapshotDep := reviewDown(repo, branching.CloneName(pool, clone.Branch, clone.ID, clone.Revision)) + if snapshotDep != "" { + log.Dbg(fmt.Sprintf("Dataset has commit: %s. Skip destroying", snapshotDep)) + + return nil + } + + if clone.Revision == branching.DefaultRevision && !clone.HasDependent { + if err := fsm.DestroyDataset(branching.CloneDataset(pool, clone.Branch, clone.ID)); err != nil { + return fmt.Errorf("failed to destroy clone dataset: %w", err) + } + } + + return nil +} + func (p *Provisioner) stopPoolSessions(fsm pool.FSManager, exceptClones map[string]struct{}) error { fsPool := fsm.Pool()