Skip to content

Commit 04cc75f

Browse files
andrewlabchalios
authored andcommitted
Tests for snapshot network renames
Test that we can correctly parse configuration and API calls in a backwards compatible way. Signed-off-by: Andrew Laucius <[email protected]> Signed-off-by: Babis Chalios <[email protected]>
1 parent cc8c513 commit 04cc75f

File tree

4 files changed

+91
-1
lines changed

4 files changed

+91
-1
lines changed

src/firecracker/src/api_server/request/snapshot.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ fn parse_put_snapshot_load(body: &Body) -> Result<ParsedRequest, RequestError> {
121121

122122
#[cfg(test)]
123123
mod tests {
124-
use vmm::vmm_config::snapshot::{MemBackendConfig, MemBackendType};
124+
use vmm::vmm_config::snapshot::{MemBackendConfig, MemBackendType, NetworkOverride};
125125

126126
use super::*;
127127
use crate::api_server::parsed_request::tests::{depr_action_from_req, vmm_action_from_request};
@@ -182,6 +182,7 @@ mod tests {
182182
},
183183
enable_diff_snapshots: false,
184184
resume_vm: false,
185+
network_overrides: vec![],
185186
};
186187
let mut parsed_request = parse_put_snapshot(&Body::new(body), Some("load")).unwrap();
187188
assert!(
@@ -211,6 +212,7 @@ mod tests {
211212
},
212213
enable_diff_snapshots: true,
213214
resume_vm: false,
215+
network_overrides: vec![],
214216
};
215217
let mut parsed_request = parse_put_snapshot(&Body::new(body), Some("load")).unwrap();
216218
assert!(
@@ -240,6 +242,44 @@ mod tests {
240242
},
241243
enable_diff_snapshots: false,
242244
resume_vm: true,
245+
network_overrides: vec![],
246+
};
247+
let mut parsed_request = parse_put_snapshot(&Body::new(body), Some("load")).unwrap();
248+
assert!(parsed_request
249+
.parsing_info()
250+
.take_deprecation_message()
251+
.is_none());
252+
assert_eq!(
253+
vmm_action_from_request(parsed_request),
254+
VmmAction::LoadSnapshot(expected_config)
255+
);
256+
257+
let body = r#"{
258+
"snapshot_path": "foo",
259+
"mem_backend": {
260+
"backend_path": "bar",
261+
"backend_type": "Uffd"
262+
},
263+
"resume_vm": true,
264+
"network_overrides": [
265+
{
266+
"iface_id": "eth0",
267+
"host_dev_name": "vmtap2"
268+
}
269+
]
270+
}"#;
271+
let expected_config = LoadSnapshotParams {
272+
snapshot_path: PathBuf::from("foo"),
273+
mem_backend: MemBackendConfig {
274+
backend_path: PathBuf::from("bar"),
275+
backend_type: MemBackendType::Uffd,
276+
},
277+
enable_diff_snapshots: false,
278+
resume_vm: true,
279+
network_overrides: vec![NetworkOverride {
280+
iface_id: String::from("eth0"),
281+
host_dev_name: String::from("vmtap2"),
282+
}],
243283
};
244284
let mut parsed_request = parse_put_snapshot(&Body::new(body), Some("load")).unwrap();
245285
assert!(
@@ -266,6 +306,7 @@ mod tests {
266306
},
267307
enable_diff_snapshots: false,
268308
resume_vm: true,
309+
network_overrides: vec![],
269310
};
270311
let parsed_request = parse_put_snapshot(&Body::new(body), Some("load")).unwrap();
271312
assert_eq!(

src/vmm/tests/integration_tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ fn verify_load_snapshot(snapshot_file: TempFile, memory_file: TempFile) {
261261
},
262262
enable_diff_snapshots: false,
263263
resume_vm: true,
264+
network_overrides: vec![],
264265
}))
265266
.unwrap();
266267

@@ -344,6 +345,7 @@ fn verify_load_snap_disallowed_after_boot_resources(res: VmmAction, res_name: &s
344345
},
345346
enable_diff_snapshots: false,
346347
resume_vm: false,
348+
network_overrides: vec![],
347349
});
348350
let err = preboot_api_controller.handle_preboot_request(req);
349351
assert!(

tests/framework/microvm.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,7 @@ def restore_from_snapshot(
974974
snapshot: Snapshot,
975975
resume: bool = False,
976976
uffd_path: Path = None,
977+
rename_interfaces: dict = None,
977978
):
978979
"""Restore a snapshot"""
979980
jailed_snapshot = snapshot.copy_to_chroot(Path(self.chroot()))
@@ -1001,11 +1002,27 @@ def restore_from_snapshot(
10011002
# Adjust things just in case
10021003
self.kernel_file = Path(self.kernel_file)
10031004

1005+
iface_overrides = []
1006+
if rename_interfaces is not None:
1007+
iface_overrides = [
1008+
{"iface_id": k, "host_dev_name": v}
1009+
for k, v in rename_interfaces.items()
1010+
]
1011+
1012+
optional_kwargs = {}
1013+
if iface_overrides:
1014+
# For backwards compatibility ab testing we want to avoid adding
1015+
# new parameters until we have a release baseline with the new
1016+
# parameter. Once the release baseline has moved, this assignment
1017+
# can be inline in the snapshot_load command below
1018+
optional_kwargs["network_overrides"] = iface_overrides
1019+
10041020
self.api.snapshot_load.put(
10051021
mem_backend=mem_backend,
10061022
snapshot_path=str(jailed_vmstate),
10071023
enable_diff_snapshots=snapshot.is_diff,
10081024
resume_vm=resume,
1025+
**optional_kwargs,
10091026
)
10101027
# This is not a "wait for boot", but rather a "VM still works after restoration"
10111028
if snapshot.net_ifaces and resume:

tests/integration_tests/functional/test_snapshot_basic.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@
22
# SPDX-License-Identifier: Apache-2.0
33
"""Basic tests scenarios for snapshot save/restore."""
44

5+
import dataclasses
56
import filecmp
67
import logging
78
import os
89
import platform
910
import re
1011
import shutil
1112
import time
13+
import uuid
1214
from pathlib import Path
1315

1416
import pytest
1517

1618
import host_tools.cargo_build as host
1719
import host_tools.drive as drive_tools
20+
import host_tools.network as net_tools
1821
from framework import utils
1922
from framework.microvm import SnapshotType
2023
from framework.properties import global_props
@@ -570,3 +573,30 @@ def test_physical_counter_reset_aarch64(uvm_nano):
570573
break
571574
else:
572575
raise RuntimeError("Did not find CNTPCT_EL0 register in snapshot")
576+
577+
578+
def test_snapshot_rename_interface(uvm_nano, microvm_factory):
579+
"""
580+
Test that we can restore a snapshot and point its interface to a
581+
different host interface.
582+
"""
583+
vm = uvm_nano
584+
base_iface = vm.add_net_iface()
585+
vm.start()
586+
snapshot = vm.snapshot_full()
587+
588+
# We don't reuse the network namespace as it may conflict with
589+
# previous/future devices
590+
restored_vm = microvm_factory.build(netns=net_tools.NetNs(str(uuid.uuid4())))
591+
# Override the tap name, but keep the same IP configuration
592+
iface_override = dataclasses.replace(base_iface, tap_name="tap_override")
593+
594+
restored_vm.spawn()
595+
snapshot.net_ifaces.clear()
596+
snapshot.net_ifaces.append(iface_override)
597+
restored_vm.restore_from_snapshot(
598+
snapshot,
599+
rename_interfaces={iface_override.dev_name: iface_override.tap_name},
600+
resume=True,
601+
)
602+
restored_vm.wait_for_ssh_up()

0 commit comments

Comments
 (0)