Skip to content

WIP: Add snapshot export import#152

Open
kwonkwonn wants to merge 4 commits into
mainfrom
add_snapshot_export_import
Open

WIP: Add snapshot export import#152
kwonkwonn wants to merge 4 commits into
mainfrom
add_snapshot_export_import

Conversation

@kwonkwonn

@kwonkwonn kwonkwonn commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Summary

  • presignedImageUrl 필드 추가 (/createVM): 베이스 이미지가 로컬에 없을 때 presigned GET URL로 RustFS에서 자동 다운로드 후 VM 생성. 이미 이미지가 존재하면 기존 경로 그대로 사용하므로 하위 호환성 유지.
  • POST /TakeExternalSnapshot 신규 엔드포인트: 외부 스냅샷 생성과 RustFS presigned PUT 업로드를 단일 요청으로 처리. 기존 /CreateExternalSnapshot은 변경 없이 유지 (WKS_Control 이전 버전과의 하위 호환성 보장).
  • 원자적 파일 다운로드: 베이스 이미지 다운로드 시 .tmp → rename 패턴으로 중간 실패 시 불완전한 파일이 남지 않도록 처리.
  • 유닛 테스트 추가: ensureBaseImage, UploadToPresignedURL, TakeExternalSnapshot 핸들러에 대한 httptest 기반 테스트.

Changes

파일 내용
pkg/types/vm.go VM_Init_InfopresignedImageUrl 필드 추가
api/Create/model.go CreateVMRequest에 동일 필드 추가 및 toVMInitInfo() 연결
services/creation/generate_files.go ensureBaseImage() 구현 — 로컬 확인 → presigned GET 다운로드
api/Snapshot/model.go TakeExternalSnapshotRequest/Response 타입 추가
services/snapshot/external_snap/upload_ext.go UploadToPresignedURL(), SnapshotFilePath() 구현
api/Snapshot/Snapshot.go TakeExternalSnapshot 핸들러 추가
internal/server/server.go POST /TakeExternalSnapshot 라우트 등록

WIP / Known Limitations

  • 통합 테스트 미완: WKS_Control과의 end-to-end 테스트 (presigned URL 발급 → Core 호출 → RustFS 저장 확인) 미진행. 현재 유닛 테스트는 httptest mock 서버 기준.
  • 단일 디스크 가정: TakeExternalSnapshotvda 하드코딩. WKS_Control의 TakeSnapshotRequest가 단일 presignedUrl을 전달하는 구조에 맞춘 것으로, 멀티 디스크 VM은 미지원.
  • 업로드 실패 롤백 없음: 스냅샷 생성 후 RustFS 업로드 실패 시 로컬 스냅샷 파일이 남음.

Test Plan

  • /createVM (이미지 있을 때) — /var/lib/kws/baseimg/{os} 파일 존재 확인 후 기존 동작 유지 확인
  • /createVM + presignedImageUrl (이미지 없을 때) — 호출 후 /var/lib/kws/baseimg/{os} 파일 생성 확인
    ls -lh /var/lib/kws/baseimg/
  • POST /TakeExternalSnapshot — 호출 후 /var/lib/kws/{uuid}/snapshots/{snapKey}/vda.qcow2 파일 생성 확인 + RustFS 버킷에 업로드됨 확인
  • /CreateExternalSnapshot — 기존 동작 회귀 없음 확인
  • WKS_Control ↔ KWS_Core end-to-end 통합 테스트 (미진행, WIP)


// UploadToPresignedURL uploads the file at filePath via an S3-compatible presigned PUT URL.
func UploadToPresignedURL(ctx context.Context, filePath, presignedURL string) error {
f, err := os.Open(filePath)
}
req.ContentLength = info.Size()

resp, err := http.DefaultClient.Do(req)
@kwonkwonn

Copy link
Copy Markdown
Contributor Author

요약:
presigned(omitempty)로 추가됨,
새로운 엔드포인트 upload( 하위 호완성을 위해 추가됨),
CreateVM 시 basedir 확인 후 없을 시에 pull 진행,
<-- 아직 수동으로도 통합 테스트 진행안됨, 머지는 말아주세옹

Copilot AI left a comment

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.

Pull request overview

Adds presigned-URL based image fetch and snapshot upload capabilities to support “snapshot export/import” workflows, while keeping existing snapshot APIs for backward compatibility.

Changes:

  • Extends VM creation request/types with presignedImageUrl and downloads missing base images via presigned GET before qemu-img create.
  • Introduces POST /TakeExternalSnapshot to create an external snapshot and upload it via presigned PUT in one call.
  • Adds helper utilities + unit tests for base-image download and presigned uploads; updates CPU status to use atomic operations.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
services/snapshot/external_snap/upload_ext.go Adds SnapshotFilePath and UploadToPresignedURL helper functions for snapshot upload flows.
services/snapshot/external_snap/upload_ext_test.go Adds httptest-based unit coverage for presigned upload + path helper.
services/creation/generate_files.go Adds ensureBaseImage and wires presigned base image download into disk image creation.
services/creation/generate_files_test.go Adds unit tests for ensureBaseImage behaviors (exists/missing/download/error cleanup).
pkg/types/vm.go Adds presignedImageUrl to VM_Init_Info for downstream creation flow.
api/Create/model.go Adds presignedImageUrl to /createVM request and maps it into VM_Init_Info.
api/Snapshot/model.go Adds request/response types for TakeExternalSnapshot.
api/Snapshot/Snapshot.go Implements TakeExternalSnapshot handler (snapshot + presigned PUT upload).
api/Snapshot/snapshot_test.go Adds handler tests for request decode/validation and domain lookup failure.
internal/server/server.go Registers POST /TakeExternalSnapshot route.
DomCon/domainList_status/cpu_status.go Switches CPU status bookkeeping to atomic operations and simplifies idle calc.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +42 to +44
if _, err := os.Stat(path); err == nil {
return nil
}
Comment on lines +54 to +77
tmpPath := path + ".tmp"

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()

req, err := http.NewRequestWithContext(ctx, http.MethodGet, presignedURL, nil)
if err != nil {
return fmt.Errorf("failed to build download request: %w", err)
}

resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("failed to download base image: %w", err)
}
defer resp.Body.Close()

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return fmt.Errorf("download base image returned status %d", resp.StatusCode)
}

tmp, err := os.Create(tmpPath)
if err != nil {
return fmt.Errorf("failed to create temp file: %w", err)
}
Comment thread api/Snapshot/Snapshot.go
Comment on lines +323 to +328
snapName, err := externalsnapshot.CreateExternalSnapshot(dom, param.SnapKey, &externalsnapshot.ExternalSnapshotOptions{})
if err != nil {
resp.ResponseWriteErr(w, err, http.StatusInternalServerError)
h.Logger.Error("take external snapshot failed - create snapshot", zap.String("uuid", param.UUID), zap.Error(err))
return
}
Comment on lines +70 to +74
got := SnapshotFilePath("/var/lib/kws", "vm-uuid", "snap1", "vda")
want := "/var/lib/kws/vm-uuid/snapshots/snap1/vda.qcow2"
if got != want {
t.Errorf("got %q, want %q", got, want)
}
Comment thread api/Snapshot/model.go
Comment on lines +39 to +48
type TakeExternalSnapshotRequest struct {
UUID string `json:"uuid"`
SnapKey string `json:"snapKey"`
PresignedURL string `json:"presignedUrl"`
}

type TakeExternalSnapshotResponse struct {
UUID string `json:"uuid"`
SnapKey string `json:"snapKey"`
}
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.

3 participants