Skip to content

feat: wire snapshot TakeExternalSnapshot to Core endpoint#70

Open
kwonkwonn wants to merge 1 commit into
stagingfrom
feat/snapshot-core-integration
Open

feat: wire snapshot TakeExternalSnapshot to Core endpoint#70
kwonkwonn wants to merge 1 commit into
stagingfrom
feat/snapshot-core-integration

Conversation

@kwonkwonn

@kwonkwonn kwonkwonn commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

#WIP

Summary

  • TakeSnapshotResponse 를 Core 응답 스펙(uuid, snapKey)에 맞게 수정
  • CoreClient.TakeExternalSnapshot 추가 — POST /TakeExternalSnapshot 호출, 스냅샷 생성+업로드 소요 시간 고려해 12분 timeout 전용 클라이언트 사용
  • service/external_snap.go:TakeSnapshot TODO 제거 — presigned PUT URL 발급 후 Core에 실제 전달하는 흐름 완성

Paired PR

이 PR은 Core 측 구현과 페어로 동작합니다.

Core PR #152: easy-cloud-Knet/KWS_Core#152

현재 코어에 해당 엔드포인트가 개발이 된 상태입니다.

두 Pr 을 기준으로 Control ↔ Core end-to-end 테스트를 진행하고, 통과 시 본 PR을 머지합니다.

현재 컨트롤의 서비스 로직은 단순히 엔드포인트가 돌아걸 정도의 최소 구현입니다 .

추후에 db 조작등+ 인증, 롤백등 구현을 통해 서비스 로직이 추가될거에요

Flow

POST /vm/snapshot (Control)
  → RustFS: presigned PUT URL 발급
  → Core POST /TakeExternalSnapshot (presignedUrl 전달)
    → Core: 스냅샷 생성 + RustFS 직접 업로드

WIP / Merge Condition

  • Core PR #152 머지 완료
  • Control ↔ Core e2e 테스트 통과 (POST /vm/snapshot → RustFS 버킷 확인)

Summary by CodeRabbit

  • New Features

    • Added support for taking external snapshots through the app’s snapshot flow.
    • Snapshot responses now return a snapshot UUID and key, enabling clearer tracking of created snapshots.
  • Bug Fixes

    • Completed the snapshot creation path so the system now calls the backend instead of stopping at a placeholder.
    • Improved error handling when snapshot creation fails.

- Fix TakeSnapshotResponse to match Core response shape (uuid, snapKey)
- Add CoreClient.TakeExternalSnapshot with 12m timeout for snapshot+upload
- Fill in TakeSnapshot TODO: presigned PUT URL -> Core -> RustFS upload
@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

TakeSnapshotResponse is updated to expose UUID and SnapKey fields instead of message. A new CoreClient.TakeExternalSnapshot method is added with a 12-minute HTTP timeout. The TakeSnapshot service method replaces its TODO placeholder with a real call to this new method.

Changes

External Snapshot Core Integration

Layer / File(s) Summary
Snapshot model and CoreClient method
client/model/snapshot.go, client/vm.go
TakeSnapshotResponse drops message and gains UUID/SnapKey fields. CoreClient.TakeExternalSnapshot is added, posting to /TakeExternalSnapshot via an internal client with a 12-minute timeout.
Service TakeSnapshot wiring
service/external_snap.go
Imports client/model and replaces the TODO placeholder with a coreClient.TakeExternalSnapshot call passing UUID, SnapKey, and PresignedURL, returning a wrapped error on failure.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 A snapshot in time, no message to send,
UUID and SnapKey arrive 'round the bend.
Twelve minutes to wait while the core does its thing,
No more TODO — the real call takes wing!
Hop hop, it's wired, let the snapshots begin! 🌟

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: wiring snapshot handling to Core via TakeExternalSnapshot.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/snapshot-core-integration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@client/vm.go`:
- Around line 189-195: The TakeExternalSnapshot path is sending
model.TakeSnapshotRequest into doRequest without redacting PresignedURL, which
will leak the presigned upload URL in the request-body logs. Update
CoreClient.TakeExternalSnapshot to sanitize or copy-and-clear the PresignedURL
before calling doRequest, or bypass the body logging in doRequest for this
request, so the JSON logged from the TakeExternalSnapshot flow no longer
contains the credential.

In `@service/external_snap.go`:
- Around line 56-63: The Core snapshot request is being started with a detached
background context, so cancellation from the caller cannot stop the work. Update
TakeSnapshot to accept and pass through the caller’s context, then thread that
context from its callers instead of using context.Background(); use the existing
TakeSnapshot and TakeExternalSnapshot call sites to locate the change and keep
the error handling unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b1100777-10ee-4e85-9f90-f7eab3d365cd

📥 Commits

Reviewing files that changed from the base of the PR and between 5a96e73 and eb0de68.

📒 Files selected for processing (3)
  • client/model/snapshot.go
  • client/vm.go
  • service/external_snap.go

Comment thread client/vm.go
Comment on lines +189 to +195
func (c *CoreClient) TakeExternalSnapshot(ctx context.Context, req model.TakeSnapshotRequest) (model.TakeSnapshotResponse, error) {
snapClient := &CoreClient{
baseURL: c.baseURL,
client: &http.Client{Timeout: 12 * time.Minute},
}
var response model.TakeSnapshotResponse
if err := snapClient.doRequest(ctx, http.MethodPost, "/TakeExternalSnapshot", req, &response); err != nil {

@coderabbitai coderabbitai Bot Jun 28, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Redact the presigned URL before this request goes through doRequest.

model.TakeSnapshotRequest includes PresignedURL, and doRequest logs the full JSON body at client/vm.go Line 41. This new path would write a live upload credential into logs for every snapshot request unless that body logging is skipped or redacted first.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/vm.go` around lines 189 - 195, The TakeExternalSnapshot path is
sending model.TakeSnapshotRequest into doRequest without redacting PresignedURL,
which will leak the presigned upload URL in the request-body logs. Update
CoreClient.TakeExternalSnapshot to sanitize or copy-and-clear the PresignedURL
before calling doRequest, or bypass the body logging in doRequest for this
request, so the JSON logged from the TakeExternalSnapshot flow no longer
contains the credential.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

12분 정도의 긴 Timeout 방식보다 webhook 방식이 연결 자원 점유 문제나 디버깅 상태 확인 그리고 안정성에서는 더 나은 해결책이 될 수 있을 것 같습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ukleon123 맞습니다. 장기적으로는 webhook/async 방식이 말씀하신 것처럼 연결 자원 점유, 진행 상태 확인, 재시도/복구 측면에서 더 나은 방향으로 보입니다.

다만 이번 코멘트의 핵심은 timeout 전략과는 별개로, 현재 구현에서는 model.TakeSnapshotRequest.PresignedURLclient/vm.go Line 41의 request-body 로그에 그대로 남는 점입니다. 그래서 지금 구조를 유지하더라도 이 값은 마스킹하거나 로그에서 제외하는 처리가 필요합니다.

즉:

  • 중장기 개선안: webhook/비동기 전환
  • 이번 PR의 최소 안전 조치: TakeExternalSnapshot 경로에서 PresignedURL 로그 유출 방지

원하시면 webhook 전환은 후속 이슈로 분리하고, 이 PR에서는 먼저 presigned URL 로깅만 막는 방향으로 보는 게 좋겠습니다.

Comment thread service/external_snap.go
Comment on lines +56 to +63
coreClient := client.NewCoreClient(core)
if _, err := coreClient.TakeExternalSnapshot(context.Background(), model.TakeSnapshotRequest{
UUID: uuid,
SnapKey: snapName,
PresignedURL: presignedURL,
}); err != nil {
return fmt.Errorf("TakeSnapshot %s: core failed: %w", uuid, err)
}

@coderabbitai coderabbitai Bot Jun 28, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Propagate the caller context into the Core snapshot call.

This new 12-minute request is issued with context.Background(), so cancellation from POST /vm/snapshot will not abort the Core work. The same detachment already exists at service/external_snap.go Line 51, so the fix belongs at TakeSnapshot's signature and callers rather than only at this line.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@service/external_snap.go` around lines 56 - 63, The Core snapshot request is
being started with a detached background context, so cancellation from the
caller cannot stop the work. Update TakeSnapshot to accept and pass through the
caller’s context, then thread that context from its callers instead of using
context.Background(); use the existing TakeSnapshot and TakeExternalSnapshot
call sites to locate the change and keep the error handling unchanged.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code rabbit이 말해준 영역이긴 하지만 Timeout 설정을 Background context에서 수행하는 방식보다는 timeout context를 사용하는 것이 나을것으로 보이긴 합니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ukleon123 맞습니다. 핵심은 Background()로 분리하지 않는 것이고, timeout이 필요하다면 말씀하신 것처럼 caller context를 그대로 전파한 뒤 그 위에 context.WithTimeout(...)을 씌우는 방식이 더 자연스럽습니다.

즉, 이상적인 형태는:

  • TakeSnapshot이 호출자의 ctx를 받음
  • ctxWithTimeout, cancel := context.WithTimeout(ctx, 12*time.Minute) 처럼 파생
  • ctxWithTimeoutTakeExternalSnapshot까지 전달

이렇게 하면:

  • 상위 요청 취소가 그대로 전파되고
  • snapshot 작업의 최대 시간도 명시적으로 제한할 수 있습니다

반대로 context.Background()에서 시작하면 상위 요청과 분리되어 취소 전파가 끊기는 점이 문제라, 그 부분은 그대로 유효한 우려였습니다.
현재 http.Client.Timeout만으로도 상한은 걸리지만, 취소 전파 관점에서는 timeout context 쪽이 더 낫다는 의견에 동의합니다.

(•ᴗ•)◞🐇


✏️ Learnings added
Learnt from: ukleon123
Repo: easy-cloud-Knet/KWS_Control PR: 70
File: service/external_snap.go:56-63
Timestamp: 2026-06-29T07:14:15.915Z
Learning: In the KWS_Control repository, for long-running operations such as external snapshot requests, prefer deriving `context.WithTimeout(...)` from the caller-provided context instead of starting from `context.Background()`, so cancellation from the upstream request is preserved while still enforcing a maximum duration.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants