mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-31 10:05:20 +00:00
ci: Add integration test for live migration with OVS-DPDK
Signed-off-by: Bo Chen <chen.bo@intel.com>
This commit is contained in:
parent
9023412e31
commit
a181b77bc8
2
Jenkinsfile
vendored
2
Jenkinsfile
vendored
@ -228,6 +228,7 @@ pipeline{
|
|||||||
timeout(time: 1, unit: 'HOURS')
|
timeout(time: 1, unit: 'HOURS')
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
|
sh "sudo modprobe openvswitch"
|
||||||
sh "scripts/dev_cli.sh tests --integration-live-migration"
|
sh "scripts/dev_cli.sh tests --integration-live-migration"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,6 +237,7 @@ pipeline{
|
|||||||
timeout(time: 1, unit: 'HOURS')
|
timeout(time: 1, unit: 'HOURS')
|
||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
|
sh "sudo modprobe openvswitch"
|
||||||
sh "scripts/dev_cli.sh tests --integration-live-migration --libc musl"
|
sh "scripts/dev_cli.sh tests --integration-live-migration --libc musl"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,8 +79,17 @@ strip target/$BUILD_TARGET/release/cloud-hypervisor
|
|||||||
strip target/$BUILD_TARGET/release/vhost_user_net
|
strip target/$BUILD_TARGET/release/vhost_user_net
|
||||||
strip target/$BUILD_TARGET/release/ch-remote
|
strip target/$BUILD_TARGET/release/ch-remote
|
||||||
|
|
||||||
export RUST_BACKTRACE=1
|
# Test ovs-dpdk relies on hugepages
|
||||||
|
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
||||||
|
sudo chmod a+rwX /dev/hugepages
|
||||||
|
|
||||||
|
# Setup ovs-dpdk
|
||||||
|
service openvswitch-switch start
|
||||||
|
ovs-vsctl init
|
||||||
|
ovs-vsctl set Open_vSwitch . other_config:dpdk-init=true
|
||||||
|
service openvswitch-switch restart
|
||||||
|
|
||||||
|
export RUST_BACKTRACE=1
|
||||||
time cargo test $features_test "tests::live_migration::$test_filter" -- --test-threads=1
|
time cargo test $features_test "tests::live_migration::$test_filter" -- --test-threads=1
|
||||||
RES=$?
|
RES=$?
|
||||||
|
|
||||||
|
@ -7019,6 +7019,199 @@ mod tests {
|
|||||||
fn test_live_migration_numa() {
|
fn test_live_migration_numa() {
|
||||||
_test_live_migration(true)
|
_test_live_migration(true)
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_live_migration_ovs_dpdk() {
|
||||||
|
let ovs_focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||||
|
let ovs_guest = Guest::new(Box::new(ovs_focal));
|
||||||
|
|
||||||
|
let migration_focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||||
|
let migration_guest = Guest::new(Box::new(migration_focal));
|
||||||
|
let src_api_socket = temp_api_path(&migration_guest.tmp_dir);
|
||||||
|
|
||||||
|
// Start two VMs that are connected through ovs-dpdk and one of the VMs is the source VM for live-migration
|
||||||
|
let (mut ovs_child, mut src_child) =
|
||||||
|
setup_ovs_dpdk_guests(&ovs_guest, &migration_guest, &src_api_socket);
|
||||||
|
|
||||||
|
// Start the destination VM
|
||||||
|
let mut dest_api_socket = temp_api_path(&migration_guest.tmp_dir);
|
||||||
|
dest_api_socket.push_str(".dest");
|
||||||
|
let mut dest_child = GuestCommand::new(&migration_guest)
|
||||||
|
.args(&["--api-socket", &dest_api_socket])
|
||||||
|
.capture_output()
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let r = std::panic::catch_unwind(|| {
|
||||||
|
// Give it '1s' to make sure the 'dest_api_socket' file is properly created
|
||||||
|
thread::sleep(std::time::Duration::new(1, 0));
|
||||||
|
|
||||||
|
// Start the live-migration
|
||||||
|
let migration_socket = String::from(
|
||||||
|
migration_guest
|
||||||
|
.tmp_dir
|
||||||
|
.as_path()
|
||||||
|
.join("live-migration.sock")
|
||||||
|
.to_str()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
// Start to receive migration from the destintion VM
|
||||||
|
let mut receive_migration = Command::new(clh_command("ch-remote"))
|
||||||
|
.args(&[
|
||||||
|
&format!("--api-socket={}", &dest_api_socket),
|
||||||
|
"receive-migration",
|
||||||
|
&format! {"unix:{}", migration_socket},
|
||||||
|
])
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
// Give it '1s' to make sure the 'migration_socket' file is properly created
|
||||||
|
thread::sleep(std::time::Duration::new(1, 0));
|
||||||
|
// Start to send migration from the source VM
|
||||||
|
let mut send_migration = Command::new(clh_command("ch-remote"))
|
||||||
|
.args(&[
|
||||||
|
&format!("--api-socket={}", &src_api_socket),
|
||||||
|
"send-migration",
|
||||||
|
&format! {"unix:{}", migration_socket},
|
||||||
|
])
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut success;
|
||||||
|
// The 'send-migration' command should be executed successfully within the given timeout
|
||||||
|
if let Some(status) = send_migration
|
||||||
|
.wait_timeout(std::time::Duration::from_secs(30))
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
success = status.success();
|
||||||
|
} else {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
if !success {
|
||||||
|
let _ = send_migration.kill();
|
||||||
|
let output = send_migration.wait_with_output().unwrap();
|
||||||
|
eprintln!("\n\n==== Start 'send_migration' output ====\n\n---stdout---\n{}\n\n---stderr---\n{}\n\n==== End 'send_migration' output ====\n\n",
|
||||||
|
String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
// The 'receive-migration' command should be executed successfully within the given timeout
|
||||||
|
if let Some(status) = receive_migration
|
||||||
|
.wait_timeout(std::time::Duration::from_secs(30))
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
success = status.success();
|
||||||
|
} else {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
if !success {
|
||||||
|
let _ = receive_migration.kill();
|
||||||
|
let output = receive_migration.wait_with_output().unwrap();
|
||||||
|
eprintln!("\n\n==== Start 'receive_migration' output ====\n\n---stdout---\n{}\n\n---stderr---\n{}\n\n==== End 'receive_migration' output ====\n\n",
|
||||||
|
String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
assert!(
|
||||||
|
success,
|
||||||
|
"Unsuccessful command: 'send-migration' or 'receive-migration'."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let print_and_panic = |src_vm: Child,
|
||||||
|
dest_vm: Child,
|
||||||
|
ovs_vm: Child,
|
||||||
|
message: &str|
|
||||||
|
-> ! {
|
||||||
|
let mut src_vm = src_vm;
|
||||||
|
let mut dest_vm = dest_vm;
|
||||||
|
let mut ovs_vm = ovs_vm;
|
||||||
|
|
||||||
|
let _ = src_vm.kill();
|
||||||
|
let src_output = src_vm.wait_with_output().unwrap();
|
||||||
|
eprintln!(
|
||||||
|
"\n\n==== Start 'source_vm' stdout ====\n\n{}\n\n==== End 'source_vm' stdout ====",
|
||||||
|
String::from_utf8_lossy(&src_output.stdout)
|
||||||
|
);
|
||||||
|
eprintln!(
|
||||||
|
"\n\n==== Start 'source_vm' stderr ====\n\n{}\n\n==== End 'source_vm' stderr ====",
|
||||||
|
String::from_utf8_lossy(&src_output.stderr)
|
||||||
|
);
|
||||||
|
let _ = dest_vm.kill();
|
||||||
|
let dest_output = dest_vm.wait_with_output().unwrap();
|
||||||
|
eprintln!(
|
||||||
|
"\n\n==== Start 'destination_vm' stdout ====\n\n{}\n\n==== End 'destination_vm' stdout ====",
|
||||||
|
String::from_utf8_lossy(&dest_output.stdout)
|
||||||
|
);
|
||||||
|
eprintln!(
|
||||||
|
"\n\n==== Start 'destination_vm' stderr ====\n\n{}\n\n==== End 'destination_vm' stderr ====",
|
||||||
|
String::from_utf8_lossy(&dest_output.stderr)
|
||||||
|
);
|
||||||
|
let _ = ovs_vm.kill();
|
||||||
|
let ovs_output = ovs_vm.wait_with_output().unwrap();
|
||||||
|
eprintln!(
|
||||||
|
"\n\n==== Start 'ovs_vm' stdout ====\n\n{}\n\n==== End 'ovs_vm' stdout ====",
|
||||||
|
String::from_utf8_lossy(&ovs_output.stdout)
|
||||||
|
);
|
||||||
|
eprintln!(
|
||||||
|
"\n\n==== Start 'ovs_vm' stderr ====\n\n{}\n\n==== End 'ovs_vm' stderr ====",
|
||||||
|
String::from_utf8_lossy(&ovs_output.stderr)
|
||||||
|
);
|
||||||
|
|
||||||
|
panic!("Test failed: {}", message)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check and report any errors occured during the live-migration
|
||||||
|
if r.is_err() {
|
||||||
|
print_and_panic(
|
||||||
|
src_child,
|
||||||
|
dest_child,
|
||||||
|
ovs_child,
|
||||||
|
"Error occured during live-migration",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the source vm has been terminated successful (give it '3s' to settle)
|
||||||
|
thread::sleep(std::time::Duration::new(3, 0));
|
||||||
|
if !src_child.try_wait().unwrap().map_or(false, |s| s.success()) {
|
||||||
|
print_and_panic(
|
||||||
|
src_child,
|
||||||
|
dest_child,
|
||||||
|
ovs_child,
|
||||||
|
"source VM was not terminated successfully.",
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Post live-migration check to make sure the destination VM is funcational
|
||||||
|
let r = std::panic::catch_unwind(|| {
|
||||||
|
// Perform same checks to validate VM has been properly migrated
|
||||||
|
// Spawn a new netcat listener in the OVS VM
|
||||||
|
let guest_ip = ovs_guest.network.guest_ip.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
ssh_command_ip(
|
||||||
|
"nc -l 12345",
|
||||||
|
&guest_ip,
|
||||||
|
DEFAULT_SSH_RETRIES,
|
||||||
|
DEFAULT_SSH_TIMEOUT,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for the server to be listening
|
||||||
|
thread::sleep(std::time::Duration::new(5, 0));
|
||||||
|
|
||||||
|
// And check the connection is still functional after live-migration
|
||||||
|
migration_guest
|
||||||
|
.ssh_command("nc -vz 172.100.0.1 12345")
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clean-up the destination VM and OVS VM, and make sure they terminated correctly
|
||||||
|
let _ = dest_child.kill();
|
||||||
|
let _ = ovs_child.kill();
|
||||||
|
let dest_output = dest_child.wait_with_output().unwrap();
|
||||||
|
handle_child_output(r, &dest_output);
|
||||||
|
let ovs_output = ovs_child.wait_with_output().unwrap();
|
||||||
|
handle_child_output(Ok(()), &ovs_output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_arch = "aarch64", feature = "acpi"))]
|
#[cfg(all(target_arch = "aarch64", feature = "acpi"))]
|
||||||
|
Loading…
Reference in New Issue
Block a user