Skip to content

Commit cd3a19f

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 837e72c commit cd3a19f

File tree

4 files changed

+94
-1
lines changed

4 files changed

+94
-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!(parsed_request
@@ -209,6 +210,7 @@ mod tests {
209210
},
210211
enable_diff_snapshots: true,
211212
resume_vm: false,
213+
network_overrides: vec![],
212214
};
213215
let mut parsed_request = parse_put_snapshot(&Body::new(body), Some("load")).unwrap();
214216
assert!(parsed_request
@@ -236,6 +238,44 @@ mod tests {
236238
},
237239
enable_diff_snapshots: false,
238240
resume_vm: true,
241+
network_overrides: vec![],
242+
};
243+
let mut parsed_request = parse_put_snapshot(&Body::new(body), Some("load")).unwrap();
244+
assert!(parsed_request
245+
.parsing_info()
246+
.take_deprecation_message()
247+
.is_none());
248+
assert_eq!(
249+
vmm_action_from_request(parsed_request),
250+
VmmAction::LoadSnapshot(expected_config)
251+
);
252+
253+
let body = r#"{
254+
"snapshot_path": "foo",
255+
"mem_backend": {
256+
"backend_path": "bar",
257+
"backend_type": "Uffd"
258+
},
259+
"resume_vm": true,
260+
"network_overrides": [
261+
{
262+
"iface_id": "eth0",
263+
"host_dev_name": "vmtap2"
264+
}
265+
]
266+
}"#;
267+
let expected_config = LoadSnapshotParams {
268+
snapshot_path: PathBuf::from("foo"),
269+
mem_backend: MemBackendConfig {
270+
backend_path: PathBuf::from("bar"),
271+
backend_type: MemBackendType::Uffd,
272+
},
273+
enable_diff_snapshots: false,
274+
resume_vm: true,
275+
network_overrides: vec![NetworkOverride {
276+
iface_id: String::from("eth0"),
277+
host_dev_name: String::from("vmtap2"),
278+
}],
239279
};
240280
let mut parsed_request = parse_put_snapshot(&Body::new(body), Some("load")).unwrap();
241281
assert!(parsed_request
@@ -260,6 +300,7 @@ mod tests {
260300
},
261301
enable_diff_snapshots: false,
262302
resume_vm: true,
303+
network_overrides: vec![],
263304
};
264305
let parsed_request = parse_put_snapshot(&Body::new(body), Some("load")).unwrap();
265306
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: 33 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,33 @@ 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+
# We start at an unused tap index to avoid conflicts with other tests.
584+
base_iface = net_tools.NetIfaceConfig.with_id(102)
585+
586+
vm = uvm_nano
587+
base_iface = vm.add_net_iface()
588+
vm.start()
589+
snapshot = vm.snapshot_full()
590+
591+
# We don't reuse the network namespace as it may conflict with
592+
# previous/future devices
593+
restored_vm = microvm_factory.build(netns=net_tools.NetNs(str(uuid.uuid4())))
594+
# Overrid the tap name, but keep the same IP configuration
595+
iface_override = dataclasses.replace(base_iface, tap_name="tap_override")
596+
597+
restored_vm.spawn()
598+
snapshot.net_ifaces.clear()
599+
snapshot.net_ifaces.append(iface_override)
600+
restored_vm.restore_from_snapshot(
601+
snapshot,
602+
rename_interfaces={iface_override.dev_name: iface_override.tap_name},
603+
resume=True,
604+
)
605+
restored_vm.wait_for_ssh_up()

0 commit comments

Comments
 (0)