Skip to content

Commit 52bfc43

Browse files
authored
Delete recordings endpoint (#43)
1 parent c118aa0 commit 52bfc43

File tree

6 files changed

+409
-30
lines changed

6 files changed

+409
-30
lines changed

server/cmd/api/api/api.go

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package api
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
7+
"os"
68
"time"
79

810
"github.com/onkernel/kernel-images/server/lib/logger"
@@ -92,7 +94,7 @@ func (s *ApiService) StopRecording(ctx context.Context, req oapi.StopRecordingRe
9294

9395
rec, exists := s.recordManager.GetRecorder(recorderID)
9496
if !exists {
95-
log.Warn("attempted to stop recording when none is active", "recorder_id", recorderID)
97+
log.Error("attempted to stop recording when none is active", "recorder_id", recorderID)
9698
return oapi.StopRecording400JSONResponse{BadRequestErrorJSONResponse: oapi.BadRequestErrorJSONResponse{Message: "no active recording to stop"}}, nil
9799
} else if !rec.IsRecording(ctx) {
98100
log.Warn("recording already stopped", "recorder_id", recorderID)
@@ -140,6 +142,10 @@ func (s *ApiService) DownloadRecording(ctx context.Context, req oapi.DownloadRec
140142
log.Error("attempted to download non-existent recording", "recorder_id", recorderID)
141143
return oapi.DownloadRecording404JSONResponse{NotFoundErrorJSONResponse: oapi.NotFoundErrorJSONResponse{Message: "no recording found"}}, nil
142144
}
145+
if rec.IsDeleted(ctx) {
146+
log.Error("attempted to download deleted recording", "recorder_id", recorderID)
147+
return oapi.DownloadRecording400JSONResponse{BadRequestErrorJSONResponse: oapi.BadRequestErrorJSONResponse{Message: "requested recording has been deleted"}}, nil
148+
}
143149

144150
out, meta, err := rec.Recording(ctx)
145151
if err != nil {
@@ -167,6 +173,36 @@ func (s *ApiService) DownloadRecording(ctx context.Context, req oapi.DownloadRec
167173
}, nil
168174
}
169175

176+
func (s *ApiService) DeleteRecording(ctx context.Context, req oapi.DeleteRecordingRequestObject) (oapi.DeleteRecordingResponseObject, error) {
177+
log := logger.FromContext(ctx)
178+
179+
recorderID := s.defaultRecorderID
180+
if req.Body != nil && req.Body.Id != nil && *req.Body.Id != "" {
181+
recorderID = *req.Body.Id
182+
}
183+
rec, exists := s.recordManager.GetRecorder(recorderID)
184+
if !exists {
185+
log.Error("attempted to delete non-existent recording", "recorder_id", recorderID)
186+
return oapi.DeleteRecording404JSONResponse{NotFoundErrorJSONResponse: oapi.NotFoundErrorJSONResponse{Message: "no recording found"}}, nil
187+
}
188+
189+
if rec.IsRecording(ctx) {
190+
log.Error("attempted to delete recording while still in progress", "recorder_id", recorderID)
191+
return oapi.DeleteRecording400JSONResponse{BadRequestErrorJSONResponse: oapi.BadRequestErrorJSONResponse{Message: "recording must be stopped first"}}, nil
192+
}
193+
194+
// fine to do this async
195+
go func() {
196+
if err := rec.Delete(context.Background()); err != nil && !errors.Is(err, os.ErrNotExist) {
197+
log.Error("failed to delete recording", "err", err, "recorder_id", recorderID)
198+
} else {
199+
log.Info("recording deleted", "recorder_id", recorderID)
200+
}
201+
}()
202+
203+
return oapi.DeleteRecording200Response{}, nil
204+
}
205+
170206
// ListRecorders returns a list of all registered recorders and whether each one is currently recording.
171207
func (s *ApiService) ListRecorders(ctx context.Context, _ oapi.ListRecordersRequestObject) (oapi.ListRecordersResponseObject, error) {
172208
infos := []oapi.RecorderInfo{}

server/cmd/api/api/api_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"io"
88
"math/rand"
9+
"os"
910
"testing"
1011

1112
oapi "github.com/onkernel/kernel-images/server/lib/oapi"
@@ -217,6 +218,7 @@ type mockRecorder struct {
217218
forceStopErr error
218219
recordingErr error
219220
recordingData []byte
221+
deleted bool
220222
}
221223

222224
func (m *mockRecorder) ID() string { return m.id }
@@ -251,6 +253,9 @@ func (m *mockRecorder) ForceStop(ctx context.Context) error {
251253
func (m *mockRecorder) IsRecording(ctx context.Context) bool { return m.isRecordingFlag }
252254

253255
func (m *mockRecorder) Recording(ctx context.Context) (io.ReadCloser, *recorder.RecordingMetadata, error) {
256+
if m.deleted {
257+
return nil, nil, fmt.Errorf("deleted: %w", os.ErrNotExist)
258+
}
254259
if m.recordingErr != nil {
255260
return nil, nil, m.recordingErr
256261
}
@@ -263,6 +268,16 @@ func (m *mockRecorder) Metadata() *recorder.RecordingMetadata {
263268
return &recorder.RecordingMetadata{}
264269
}
265270

271+
func (m *mockRecorder) Delete(ctx context.Context) error {
272+
if m.isRecordingFlag {
273+
return fmt.Errorf("still recording")
274+
}
275+
m.deleted = true
276+
return nil
277+
}
278+
279+
func (m *mockRecorder) IsDeleted(ctx context.Context) bool { return m.deleted }
280+
266281
func newMockFactory() recorder.FFmpegRecorderFactory {
267282
return func(id string, _ recorder.FFmpegRecordingParams) (recorder.Recorder, error) {
268283
rec := &mockRecorder{id: id}

0 commit comments

Comments
 (0)