Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions lib/instances/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,12 @@ func (m *manager) deleteInstanceWithOptions(
m.closeFirecrackerUFFDSession(ctx, stored)

// Release before deleting metadata so a failed release can be retried safely.
hadVGPUAssignment := storedVGPUDevicePath(stored) != ""
if hadVGPUAssignment {
if storedVGPUDevicePath(stored) != "" {
log.InfoContext(ctx, "destroying vGPU", "instance_id", id, "uuid", stored.GPUMdevUUID)
}
if err := m.releaseStoredVGPUPersisted(ctx, meta); err != nil {
log.ErrorContext(ctx, "failed to destroy vGPU; retaining instance metadata for retry", "instance_id", id, "uuid", stored.GPUMdevUUID, "error", err)
return fmt.Errorf("release vGPU: %w", err)
if err := m.releaseStoredVGPUPersisted(ctx, meta); err != nil {
log.ErrorContext(ctx, "failed to destroy vGPU; retaining instance metadata for retry", "instance_id", id, "uuid", stored.GPUMdevUUID, "error", err)
return fmt.Errorf("release vGPU: %w", err)
}
}

// 6. Release network allocation
Expand Down
25 changes: 25 additions & 0 deletions lib/instances/lifecycle_noop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,31 @@ func TestLifecycleNoopStandbyWithOptionsStillRejectsStandbyInstance(t *testing.T
assertNoLifecycleEvent(t, events)
}

func TestDeleteWithoutVGPUDoesNotRewriteMetadata(t *testing.T) {
m, id := newLifecycleNoopManagerWithInstance(t, StateStopped, time.Now().UTC())
meta, err := m.loadMetadata(id)
require.NoError(t, err)
meta.Devices = []string{"dev-1"}
require.NoError(t, m.saveMetadata(meta))
before, err := os.Stat(m.paths.InstanceMetadata(id))
require.NoError(t, err)

deviceManager := &recordingDeviceManager{
onMarkDetached: func() {
during, err := os.Stat(m.paths.InstanceMetadata(id))
require.NoError(t, err)
// saveMetadata replaces the file, requiring free space even for deletion.
assert.True(t, os.SameFile(before, during), "delete without a vGPU must not rewrite metadata")
},
}
m.deviceManager = deviceManager

require.NoError(t, m.DeleteInstance(t.Context(), id))
assert.Equal(t, []string{"dev-1"}, deviceManager.detached)
_, err = m.loadMetadata(id)
require.ErrorIs(t, err, ErrNotFound)
}

func TestDeletePersistsVGPUReleaseBeforeTeardown(t *testing.T) {
m, id := newLifecycleNoopManagerWithInstance(t, StateStopped, time.Now().UTC())
var persisted *metadata
Expand Down
Loading