Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

correct the condition check of suspended vm on force stop #3632

Merged
merged 10 commits into from
Aug 30, 2024
8 changes: 7 additions & 1 deletion src/platform/backends/qemu/qemu_virtual_machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,13 @@ void mp::QemuVirtualMachine::shutdown(bool force)
mpl::log(mpl::Level::debug, vm_name, "No process to kill");
}

if (state == State::suspended || mp::backend::instance_image_has_snapshot(desc.image.image_path, suspend_tag))
const auto has_suspend_snapshot = mp::backend::instance_image_has_snapshot(desc.image.image_path, suspend_tag);
if (has_suspend_snapshot != (state == State::suspended)) // clang-format off
mpl::log(mpl::Level::warning, vm_name, fmt::format("Image has {} suspension snapshot, but the state is {}",
has_suspend_snapshot ? "a" : "no",
static_cast<short>(state))); // clang-format on

if (has_suspend_snapshot)
{
mpl::log(mpl::Level::info, vm_name, "Deleting suspend image");
ricab marked this conversation as resolved.
Show resolved Hide resolved
mp::backend::delete_instance_suspend_image(desc.image.image_path, suspend_tag);
Expand Down
77 changes: 68 additions & 9 deletions tests/qemu/test_qemu_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,14 @@ TEST_F(QemuBackend, forceShutdownSuspendDeletesSuspendImageAndOffState)
return std::move(mock_qemu_platform);
});

auto factory = mpt::StubProcessFactory::Inject();
mpt::MockProcessFactory::Callback snapshot_list_suspend_tag_callback = [](mpt::MockProcess* process) {
if (process->program().contains("qemu-img") && process->arguments().contains("snapshot") &&
process->arguments().contains("-l"))
{
EXPECT_CALL(*process, read_all_standard_output()).WillOnce(Return(fake_snapshot_list_with_suspend_tag));
}
};
process_factory->register_callback(snapshot_list_suspend_tag_callback);

logger_scope.mock_logger->screen_logs(mpl::Level::debug);
logger_scope.mock_logger->expect_log(mpl::Level::info, "Forcing shutdown");
Expand All @@ -517,21 +524,73 @@ TEST_F(QemuBackend, forceShutdownSuspendDeletesSuspendImageAndOffState)
mpt::StubVMStatusMonitor stub_monitor;
mp::QemuVirtualMachineFactory backend{data_dir.path()};

auto machine = backend.create_virtual_machine(default_description, key_provider, stub_monitor);
const auto machine = backend.create_virtual_machine(default_description, key_provider, stub_monitor);
machine->state = mp::VirtualMachine::State::suspended;
machine->shutdown(true);

EXPECT_EQ(machine->current_state(), mp::VirtualMachine::State::off);

const std::vector<mpt::MockProcessFactory::ProcessInfo> processes = process_factory->process_list();
EXPECT_FALSE(processes.empty());
EXPECT_TRUE(processes.back().command == "qemu-img" && processes.back().arguments.contains("-d") &&
processes.back().arguments.contains(suspend_tag));
}

TEST_F(QemuBackend, forceShutdownSuspendedStateButNoSuspensionSnapshotInImage)
{
EXPECT_CALL(*mock_qemu_platform_factory, make_qemu_platform(_)).WillOnce([this](auto...) {
return std::move(mock_qemu_platform);
});

logger_scope.mock_logger->screen_logs(mpl::Level::debug);
logger_scope.mock_logger->expect_log(mpl::Level::info, "Forcing shutdown");
logger_scope.mock_logger->expect_log(mpl::Level::debug, "No process to kill");
logger_scope.mock_logger->expect_log(mpl::Level::warning, "Image has no suspension snapshot, but the state is 7");

mpt::StubVMStatusMonitor stub_monitor;
mp::QemuVirtualMachineFactory backend{data_dir.path()};

const auto machine = backend.create_virtual_machine(default_description, key_provider, stub_monitor);
machine->state = mp::VirtualMachine::State::suspended;
machine->shutdown(true);

EXPECT_EQ(machine->current_state(), mp::VirtualMachine::State::off);
}

TEST_F(QemuBackend, forceShutdownRunningStateButWithSuspensionSnapshotInImage)
{
EXPECT_CALL(*mock_qemu_platform_factory, make_qemu_platform(_)).WillOnce([this](auto...) {
return std::move(mock_qemu_platform);
});

mpt::MockProcessFactory::Callback snapshot_list_suspend_tag_callback = [](mpt::MockProcess* process) {
if (process->program().contains("qemu-img") && process->arguments().contains("snapshot") &&
process->arguments().contains("-l"))
{
EXPECT_CALL(*process, read_all_standard_output()).WillOnce(Return(fake_snapshot_list_with_suspend_tag));
}
};
process_factory->register_callback(snapshot_list_suspend_tag_callback);

logger_scope.mock_logger->screen_logs(mpl::Level::debug);
logger_scope.mock_logger->expect_log(mpl::Level::info, "Forcing shutdown");
logger_scope.mock_logger->expect_log(mpl::Level::debug, "No process to kill");
logger_scope.mock_logger->expect_log(mpl::Level::info, "Deleting suspend image");
logger_scope.mock_logger->expect_log(mpl::Level::warning, "Image has a suspension snapshot, but the state is 4");

mpt::StubVMStatusMonitor stub_monitor;
mp::QemuVirtualMachineFactory backend{data_dir.path()};

const auto machine = backend.create_virtual_machine(default_description, key_provider, stub_monitor);
machine->state = mp::VirtualMachine::State::running;
machine->shutdown(true);

EXPECT_EQ(machine->current_state(), mp::VirtualMachine::State::off);

auto processes = factory->process_list();
EXPECT_TRUE(std::find_if(processes.cbegin(),
processes.cend(),
[](const mpt::StubProcessFactory::ProcessInfo& process_info) {
return process_info.command == "qemu-img" && process_info.arguments.contains("-d") &&
process_info.arguments.contains(suspend_tag);
}) != processes.cend());
const std::vector<mpt::MockProcessFactory::ProcessInfo> processes = process_factory->process_list();
EXPECT_FALSE(processes.empty());
EXPECT_TRUE(processes.back().command == "qemu-img" && processes.back().arguments.contains("-d") &&
processes.back().arguments.contains(suspend_tag));
}

TEST_F(QemuBackend, verify_dnsmasq_qemuimg_and_qemu_processes_created)
Expand Down
Loading