|
5 | 5 | import filecmp
|
6 | 6 | import logging
|
7 | 7 | import os
|
| 8 | +import shutil |
8 | 9 | import tempfile
|
9 | 10 | from pathlib import Path
|
10 | 11 |
|
@@ -188,6 +189,90 @@ def _test_compare_mem_files(context):
|
188 | 189 | basevm.kill()
|
189 | 190 |
|
190 | 191 |
|
| 192 | +def _test_overwrite_diff_snapshot(context): |
| 193 | + logger = context.custom['logger'] |
| 194 | + vm_builder = context.custom['builder'] |
| 195 | + |
| 196 | + # Create a rw copy artifact. |
| 197 | + root_disk = context.disk.copy() |
| 198 | + # Get ssh key from read-only artifact. |
| 199 | + ssh_key = context.disk.ssh_key() |
| 200 | + # Create a fresh microvm from artifacts. |
| 201 | + vm_instance = vm_builder.build(kernel=context.kernel, |
| 202 | + disks=[root_disk], |
| 203 | + ssh_key=ssh_key, |
| 204 | + config=context.microvm, |
| 205 | + diff_snapshots=True) |
| 206 | + microvm = vm_instance.vm |
| 207 | + microvm.start() |
| 208 | + ssh_connection = net_tools.SSHConnection(microvm.ssh_config) |
| 209 | + |
| 210 | + # Verify if guest can run commands. |
| 211 | + exit_code, _, _ = ssh_connection.execute_command("sync") |
| 212 | + assert exit_code == 0 |
| 213 | + |
| 214 | + # Create a snapshot builder from a microvm. |
| 215 | + snapshot_builder = SnapshotBuilder(microvm) |
| 216 | + |
| 217 | + logger.info("Create full snapshot.") |
| 218 | + # Create full snapshot. |
| 219 | + full_snapshot = snapshot_builder.create([root_disk.local_path()], |
| 220 | + ssh_key, |
| 221 | + SnapshotType.DIFF, |
| 222 | + mem_file_name="vm.mem", |
| 223 | + snapshot_name="vm.vmstate") |
| 224 | + |
| 225 | + microvm.kill() |
| 226 | + |
| 227 | + logger.info("Load VM from snapshot.") |
| 228 | + |
| 229 | + logger.info("Load snapshot, mem %s", full_snapshot.mem) |
| 230 | + microvm, _ = vm_builder.build_from_snapshot( |
| 231 | + full_snapshot, |
| 232 | + resume=True, |
| 233 | + diff_snapshots=True |
| 234 | + ) |
| 235 | + ssh_connection = net_tools.SSHConnection(microvm.ssh_config) |
| 236 | + |
| 237 | + # Verify that guest is able to run commands. |
| 238 | + exit_code, _, _ = ssh_connection.execute_command("cat /proc/cpuinfo") |
| 239 | + assert exit_code == 0 |
| 240 | + |
| 241 | + # Create a snapshot builder from a microvm. |
| 242 | + snapshot_builder = SnapshotBuilder(microvm) |
| 243 | + |
| 244 | + # Copy over the existing snapshot to the snapshot save location, |
| 245 | + # this snapshot will be overwritten. |
| 246 | + snapshot_dir = snapshot_builder.create_snapshot_dir() |
| 247 | + shutil.copyfile(full_snapshot.mem, os.path.join(snapshot_dir, "vm.mem")) |
| 248 | + os.chown(os.path.join(snapshot_dir, "vm.mem"), |
| 249 | + microvm.jailer.uid, microvm.jailer.gid) |
| 250 | + |
| 251 | + logger.info("Create diff snapshot.") |
| 252 | + # Create diff snapshot _on top_ of full snapshot. |
| 253 | + new_snapshot = snapshot_builder.create([root_disk.local_path()], |
| 254 | + ssh_key, |
| 255 | + SnapshotType.DIFF, |
| 256 | + mem_file_name="vm.mem", |
| 257 | + snapshot_name="vm.vmstate") |
| 258 | + microvm.kill() |
| 259 | + |
| 260 | + logger.info("Load VM from combined snapshot.") |
| 261 | + # Verify that we can load from new snapshot |
| 262 | + logger.info("Load snapshot, mem %s", new_snapshot.mem) |
| 263 | + microvm, _ = vm_builder.build_from_snapshot( |
| 264 | + new_snapshot, |
| 265 | + resume=True, |
| 266 | + diff_snapshots=True |
| 267 | + ) |
| 268 | + ssh_connection = net_tools.SSHConnection(microvm.ssh_config) |
| 269 | + # Run command to verify it loaded |
| 270 | + exit_code, _, _ = ssh_connection.execute_command("sync") |
| 271 | + assert exit_code == 0 |
| 272 | + |
| 273 | + microvm.kill() |
| 274 | + |
| 275 | + |
191 | 276 | def test_patch_drive_snapshot(bin_cloner_path):
|
192 | 277 | """
|
193 | 278 | Test that a patched drive is correctly used by guests loaded from snapshot.
|
@@ -416,6 +501,43 @@ def test_cmp_full_and_first_diff_mem(network_config,
|
416 | 501 | test_matrix.run_test(_test_compare_mem_files)
|
417 | 502 |
|
418 | 503 |
|
| 504 | +def test_overwrite_diff_snapshot(network_config, |
| 505 | + bin_cloner_path): |
| 506 | + """ |
| 507 | + Can write a diff snapshot on top of a full snapshot. |
| 508 | +
|
| 509 | + @type: functional |
| 510 | + """ |
| 511 | + logger = logging.getLogger("snapshot_diff_overwrite") |
| 512 | + |
| 513 | + artifacts = ArtifactCollection(_test_images_s3_bucket()) |
| 514 | + # Testing matrix: |
| 515 | + # - Guest kernel: All supported ones |
| 516 | + # - Rootfs: Ubuntu 18.04 |
| 517 | + # - Microvm: 2vCPU with 512 MB RAM |
| 518 | + microvm_artifacts = ArtifactSet(artifacts.microvms(keyword="2vcpu_512mb")) |
| 519 | + kernel_artifacts = ArtifactSet(artifacts.kernels()) |
| 520 | + disk_artifacts = ArtifactSet(artifacts.disks(keyword="ubuntu")) |
| 521 | + |
| 522 | + # Create a test context and add builder, logger, network. |
| 523 | + test_context = TestContext() |
| 524 | + test_context.custom = { |
| 525 | + 'builder': MicrovmBuilder(bin_cloner_path), |
| 526 | + 'network_config': network_config, |
| 527 | + 'logger': logger |
| 528 | + } |
| 529 | + |
| 530 | + # Create the test matrix. |
| 531 | + test_matrix = TestMatrix(context=test_context, |
| 532 | + artifact_sets=[ |
| 533 | + microvm_artifacts, |
| 534 | + kernel_artifacts, |
| 535 | + disk_artifacts |
| 536 | + ]) |
| 537 | + |
| 538 | + test_matrix.run_test(_test_overwrite_diff_snapshot) |
| 539 | + |
| 540 | + |
419 | 541 | def test_negative_postload_api(bin_cloner_path):
|
420 | 542 | """
|
421 | 543 | Test APIs fail after loading from snapshot.
|
|
0 commit comments