Skip to content

Hyper-V API: Snapshots feature#4722

Open
xmkg wants to merge 3 commits into
mainfrom
feature/hyperv-api-snapshots
Open

Hyper-V API: Snapshots feature#4722
xmkg wants to merge 3 commits into
mainfrom
feature/hyperv-api-snapshots

Conversation

@xmkg

@xmkg xmkg commented Mar 11, 2026

Copy link
Copy Markdown
Member

Implement forward-merge on erase behavior for the virtdisk snapshot feature.

@codecov

codecov Bot commented Mar 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.55%. Comparing base (7e0d2db) to head (f4c9c92).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4722   +/-   ##
=======================================
  Coverage   87.55%   87.55%           
=======================================
  Files         275      275           
  Lines       14674    14674           
=======================================
  Hits        12847    12847           
  Misses       1827     1827           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@xmkg xmkg force-pushed the feature/hyperv-api-backend-virtual-machine branch from 921de08 to e32e80a Compare March 17, 2026 18:47
@xmkg xmkg force-pushed the feature/hyperv-api-snapshots branch from cb9b720 to 5c39aaa Compare March 17, 2026 21:06
@xmkg xmkg force-pushed the feature/hyperv-api-backend-virtual-machine branch 2 times, most recently from 4642fa0 to 3de21e5 Compare March 23, 2026 14:00
@xmkg xmkg force-pushed the feature/hyperv-api-snapshots branch 4 times, most recently from 23064f4 to 7ca5e4f Compare March 24, 2026 11:37
@xmkg xmkg requested a review from ricab March 24, 2026 13:23
@xmkg xmkg marked this pull request as ready for review March 24, 2026 13:23
@xmkg xmkg force-pushed the feature/hyperv-api-backend-virtual-machine branch from 6fcebbe to fd2109f Compare April 1, 2026 12:56
@xmkg xmkg force-pushed the feature/hyperv-api-backend-virtual-machine branch from 7c75400 to 54ab42e Compare April 9, 2026 15:54
@xmkg xmkg force-pushed the feature/hyperv-api-snapshots branch from 7ca5e4f to 53c7be4 Compare April 9, 2026 15:58
@xmkg xmkg force-pushed the feature/hyperv-api-backend-virtual-machine branch 2 times, most recently from af7732b to ec5aa2c Compare April 13, 2026 11:52
@xmkg xmkg force-pushed the feature/hyperv-api-snapshots branch 2 times, most recently from 6904553 to 62a4f25 Compare April 13, 2026 17:00
@xmkg xmkg force-pushed the feature/hyperv-api-snapshots branch 5 times, most recently from 118790b to cf2a75a Compare May 5, 2026 14:42
Base automatically changed from feature/hyperv-api-backend-virtual-machine to main May 5, 2026 20:36
@ricab ricab requested a review from Copilot June 29, 2026 18:25

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 a virtdisk-based snapshot implementation for the Hyper-V API backend, with a focus on “forward-merge on erase” semantics so deleting a snapshot preserves descendant state by consolidating differencing disks.

Changes:

  • Introduce VirtDiskSnapshot (capture/apply/erase) backed by VHDX/AVHDX differencing disks.
  • Wire snapshot creation/loading into HCSVirtualMachine, and make VM startup prefer head.avhdx when present.
  • Add Hyper-V API integration tests covering snapshot erase/merge scenarios and update CMake sources.

Reviewed changes

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

Show a summary per file
File Description
tests/unit/hyperv_api/test_it_hyperv_virtdisk_snapshot.cpp New integration tests validating erase/merge behavior across several snapshot topologies
tests/unit/hyperv_api/CMakeLists.txt Adds the new snapshot integration test source to the Hyper-V API test target
tests/unit/CMakeLists.txt Ensures the integration test executable has baseline sources
src/platform/backends/hyperv_api/virtdisk/virtdisk_snapshot.h Declares the virtdisk snapshot implementation and helpers (head name, paths)
src/platform/backends/hyperv_api/virtdisk/virtdisk_snapshot.cpp Implements capture/apply/erase using differencing disks + forward-merge on erase
src/platform/backends/hyperv_api/hcs_virtual_machine.cpp Enables snapshot support and prefers head.avhdx as the primary disk when present; adds resize guard
src/platform/backends/hyperv_api/CMakeLists.txt Builds the new virtdisk_snapshot.cpp into the backend library

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

Comment on lines +66 to +87
VMSpecs specs{.num_cores = 1,
.mem_size = MemorySize{"1G"},
.disk_space = MemorySize{"5G"},
.default_mac_address = "00:00:00:00:00:00",
.extra_interfaces = {},
.ssh_username = "ubuntu",
.state = VirtualMachine::State::off,
.mounts = {},
.deleted = false,
.metadata = {}};
++counter;
auto ss = std::make_shared<VirtDiskSnapshot>(name,
"",
"test-id",
std::move(parent),
specs,
vm,
desc);
snapshots.push_back(ss);
ss->capture();
return ss;
}
Comment on lines +72 to +75
std::string VirtDiskSnapshot::make_snapshot_filename(const Snapshot& ss)
{
return fmt::format("{}.avhdx", ss.get_name());
}
Comment on lines +96 to +110
// Check if head disk already exists. The head disk may not exist for a VM
// that has no snapshots yet.
if (!MP_FILEOPS.exists(head_path))
{
const auto parent = get_parent();
const auto target = parent ? make_snapshot_path(*parent) : base_vhdx_path;
create_new_child_disk(target, head_path);
}

// Step 1: Rename current head to snapshot name
MP_FILEOPS.rename(head_path, snapshot_path);

// Step 2: Create a new head from the snapshot
create_new_child_disk(snapshot_path, head_path);
}
Comment on lines +185 to +203
auto self_temp_path = self_path;
self_temp_path += ".tmp";
MP_FILEOPS.rename(self_path, self_temp_path);

// Pass 1: merge each child into a copy, stash the result as child.new
// No original files are modified. If anything fails, we clean up and bail.
std::vector<std::pair<std::filesystem::path, std::filesystem::path>>
staged; // {child, child.new}

auto rollback = [&] {
for (const auto& [original, stashed] : staged)
{
std::error_code ec;
MP_FILEOPS.remove(stashed, ec);
}
// Restore the snapshot file
MP_FILEOPS.remove(self_path);
MP_FILEOPS.rename(self_temp_path, self_path);
};
Comment on lines +659 to 667
if (get_num_snapshots() > 0)
{
throw ResizeDiskException{"Cannot resize the primary disk while there are "
"snapshots. To resize, delete the snapshots first."};
}

if (const auto result =
VirtDisk().resize_virtual_disk(description.image.image_path, new_size.in_bytes());
!result)
xmkg added 3 commits June 29, 2026 23:45
The old merge behavior was backward, meaning the deleted disk would
be merged to its parent. The new implementation now correctly merges
forward -- each child disk would have the deleted disk's contents.

Added integration tests for the snapshot erase.
@xmkg xmkg force-pushed the feature/hyperv-api-snapshots branch from cf2a75a to f4c9c92 Compare June 29, 2026 20:46
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