|
6 | 6 | import logging
|
7 | 7 | import os
|
8 | 8 | import re
|
| 9 | +import shutil |
9 | 10 | from pathlib import Path
|
10 | 11 |
|
11 | 12 | import pytest
|
@@ -411,3 +412,49 @@ def test_create_large_diff_snapshot(test_microvm_with_api):
|
411 | 412 |
|
412 | 413 | # If the regression was not fixed, this would have failed. The Firecracker
|
413 | 414 | # process would have been taken down.
|
| 415 | + |
| 416 | + |
| 417 | +def test_diff_snapshot_overlay(guest_kernel, rootfs, microvm_factory): |
| 418 | + """ |
| 419 | + Tests that if we take a diff snapshot and direct firecracker to write it on |
| 420 | + top of an existing snapshot file, it will successfully merge them. |
| 421 | + """ |
| 422 | + basevm = microvm_factory.build(guest_kernel, rootfs) |
| 423 | + basevm.spawn() |
| 424 | + basevm.basic_config(track_dirty_pages=True) |
| 425 | + basevm.add_net_iface() |
| 426 | + basevm.start() |
| 427 | + |
| 428 | + # Wait for microvm to be booted |
| 429 | + rc, _, stderr = basevm.ssh.run("true") |
| 430 | + assert rc == 0, stderr |
| 431 | + |
| 432 | + # The first snapshot taken will always contain all memory (even if its specified as "diff"). |
| 433 | + # We use a diff snapshot here, as taking a full snapshot does not clear the dirty page tracking, |
| 434 | + # meaning the `snapshot_diff()` call below would again dump the entire guest memory instead of |
| 435 | + # only dirty regions. |
| 436 | + full_snapshot = basevm.snapshot_diff() |
| 437 | + basevm.resume() |
| 438 | + |
| 439 | + # Run some command to dirty some pages |
| 440 | + rc, _, stderr = basevm.ssh.run("true") |
| 441 | + assert rc == 0, stderr |
| 442 | + |
| 443 | + # First copy the base snapshot somewhere else, so we can make sure |
| 444 | + # it will actually get updated |
| 445 | + first_snapshot_backup = Path(basevm.chroot()) / "mem.old" |
| 446 | + shutil.copyfile(full_snapshot.mem, first_snapshot_backup) |
| 447 | + |
| 448 | + # One Microvm object will always write its snapshot files to the same location |
| 449 | + merged_snapshot = basevm.snapshot_diff() |
| 450 | + assert full_snapshot.mem == merged_snapshot.mem |
| 451 | + |
| 452 | + assert not filecmp.cmp(merged_snapshot.mem, first_snapshot_backup, shallow=False) |
| 453 | + |
| 454 | + new_vm = microvm_factory.build() |
| 455 | + new_vm.spawn() |
| 456 | + new_vm.restore_from_snapshot(merged_snapshot, resume=True) |
| 457 | + |
| 458 | + # Run some command to check that the restored VM works |
| 459 | + rc, _, stderr = new_vm.ssh.run("true") |
| 460 | + assert rc == 0, stderr |
0 commit comments