From 70d3d0b297c277c160befc4f1d26b0bb1109cfdd Mon Sep 17 00:00:00 2001 From: Marcelo Politzer <251334+mpolitzer@users.noreply.github.com> Date: Mon, 11 May 2026 12:14:31 -0300 Subject: [PATCH] fix: pre-clean snapshot dir before store --- internal/advancer/advancer.go | 7 +++++++ internal/advancer/advancer_test.go | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/internal/advancer/advancer.go b/internal/advancer/advancer.go index 68a6b639c..51a9dedd0 100644 --- a/internal/advancer/advancer.go +++ b/internal/advancer/advancer.go @@ -465,6 +465,13 @@ func (s *Service) createSnapshot(ctx context.Context, app *Application, machine "input", input.Index, "path", snapshotPath) + // Guard against partial store by cleaning up before a retry + if _, err := os.Stat(snapshotPath); err == nil { + if err := s.removeSnapshot(snapshotPath, app.Name); err != nil { + return fmt.Errorf("failed to clean stale snapshot directory: %w", err) + } + } + // Ensure the parent directory exists if err := os.MkdirAll(s.snapshotsDir, 0755); err != nil { //nolint: mnd return fmt.Errorf("failed to create snapshots directory: %w", err) diff --git a/internal/advancer/advancer_test.go b/internal/advancer/advancer_test.go index 229825d29..0b38686b4 100644 --- a/internal/advancer/advancer_test.go +++ b/internal/advancer/advancer_test.go @@ -9,6 +9,7 @@ import ( "encoding/json" "errors" "fmt" + "io/fs" mrand "math/rand" "os" "path/filepath" @@ -937,6 +938,27 @@ func (s *AdvancerSuite) TestCreateSnapshot() { require.True(os.IsNotExist(statErr)) }) + s.Run("OverwritesPartialPriorAttempt", func() { + + require := s.Require() + env, machine, tmpDir := setupCreateSnapshot() + + prevPath := filepath.Join(tmpDir, "testapp_epoch0_input0") + require.Nil(os.MkdirAll(prevPath, 0755)) + + input := repotest.NewInputBuilder().WithIndex(0).WithEpochIndex(0).Build() + input.EpochApplicationID = env.app.Application.ID + + err := env.service.createSnapshot(context.Background(), env.app.Application, machine, input) + require.Nil(err) + require.NotNil(input.SnapshotURI) + require.Equal(prevPath, *input.SnapshotURI) + + // This works because the machine mock doesn't create directories + _, statErr := os.Stat(prevPath) + require.True(errors.Is(statErr, fs.ErrNotExist)) + }) + s.Run("CreateSnapshotError", func() { require := s.Require() env, machine, _ := setupCreateSnapshot()