diff --git a/include/multipass/ssh/ssh_session.h b/include/multipass/ssh/ssh_session.h index aa199ed8f8..7e8f9a7acb 100644 --- a/include/multipass/ssh/ssh_session.h +++ b/include/multipass/ssh/ssh_session.h @@ -32,8 +32,10 @@ class SSHKeyProvider; class SSHSession { public: - SSHSession(const std::string& host, int port, const std::chrono::milliseconds timeout = std::chrono::seconds(1)); - SSHSession(const std::string& host, int port, const std::string& ssh_username, const SSHKeyProvider& key_provider, + SSHSession(const std::string& host, + int port, + const std::string& ssh_username, + const SSHKeyProvider& key_provider, const std::chrono::milliseconds timeout = std::chrono::seconds(20)); SSHProcess exec(const std::string& cmd); @@ -42,9 +44,6 @@ class SSHSession operator ssh_session() const; private: - SSHSession(const std::string& host, int port, const std::string& ssh_username, const SSHKeyProvider* key_provider); - SSHSession(const std::string& host, int port, const std::string& ssh_username, const SSHKeyProvider* key_provider, - const std::chrono::milliseconds timeout = std::chrono::seconds(20)); void set_option(ssh_options_e type, const void* value); std::unique_ptr session; }; diff --git a/include/multipass/utils.h b/include/multipass/utils.h index 1b254d70b8..93674cfa32 100644 --- a/include/multipass/utils.h +++ b/include/multipass/utils.h @@ -111,8 +111,11 @@ std::string match_line_for(const std::string& output, const std::string& matcher // virtual machine helpers bool is_running(const VirtualMachine::State& state); -void wait_until_ssh_up(VirtualMachine* virtual_machine, std::chrono::milliseconds timeout, - std::function const& ensure_vm_is_running = []() {}); +void wait_until_ssh_up( + VirtualMachine* virtual_machine, + std::chrono::milliseconds timeout, + const SSHKeyProvider& key_provider, + std::function const& ensure_vm_is_running = []() {}); std::string run_in_ssh_session(SSHSession& session, const std::string& cmd); // yaml helpers diff --git a/include/multipass/virtual_machine.h b/include/multipass/virtual_machine.h index e57aea857a..fc9323496c 100644 --- a/include/multipass/virtual_machine.h +++ b/include/multipass/virtual_machine.h @@ -68,10 +68,10 @@ class VirtualMachine : private DisabledCopyMove }; virtual std::string ssh_hostname(std::chrono::milliseconds timeout) = 0; virtual std::string ssh_username() = 0; - virtual std::string management_ipv4() = 0; + virtual std::string management_ipv4(const SSHKeyProvider& key_provider) = 0; virtual std::vector get_all_ipv4(const SSHKeyProvider& key_provider) = 0; virtual std::string ipv6() = 0; - virtual void wait_until_ssh_up(std::chrono::milliseconds timeout) = 0; + virtual void wait_until_ssh_up(std::chrono::milliseconds timeout, const SSHKeyProvider& key_provider) = 0; virtual void ensure_vm_is_running() = 0; virtual void update_state() = 0; virtual void update_cpus(int num_cores) = 0; diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index e714c0fd05..a7d287072d 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -1629,7 +1629,7 @@ try // clang-format on mpu::run_in_ssh_session(session, "df -t ext4 -t vfat --total -B1 --output=size | tail -n 1")); info->set_cpu_count(mpu::run_in_ssh_session(session, "nproc")); - std::string management_ip = vm.management_ipv4(); + std::string management_ip = vm.management_ipv4(*config->ssh_key_provider); auto all_ipv4 = vm.get_all_ipv4(*config->ssh_key_provider); if (is_ipv4_valid(management_ip)) @@ -1710,7 +1710,7 @@ try // clang-format on if (request->request_ipv4() && mp::utils::is_running(present_state)) { - std::string management_ip = vm->management_ipv4(); + std::string management_ip = vm->management_ipv4(*config->ssh_key_provider); auto all_ipv4 = vm->get_all_ipv4(*config->ssh_key_provider); if (is_ipv4_valid(management_ip)) @@ -2888,7 +2888,7 @@ mp::Daemon::async_wait_for_ssh_and_start_mounts_for(const std::string& name, con { auto it = operative_instances.find(name); auto vm = it->second; - vm->wait_until_ssh_up(timeout); + vm->wait_until_ssh_up(timeout, *config->ssh_key_provider); if (std::is_same::value) { diff --git a/src/platform/backends/libvirt/libvirt_virtual_machine.cpp b/src/platform/backends/libvirt/libvirt_virtual_machine.cpp index b87ace3fd0..705b53778e 100644 --- a/src/platform/backends/libvirt/libvirt_virtual_machine.cpp +++ b/src/platform/backends/libvirt/libvirt_virtual_machine.cpp @@ -255,6 +255,22 @@ void update_max_and_property(virDomainPtr domain_ptr, Updater* fun_ptr, Integer flags &= ~max_flag; } while (!twice++); // first set the maximum, then actual } + +std::string management_ipv4_impl(std::optional& management_ip, + const std::string& mac_addr, + const mp::LibvirtWrapper::UPtr& libvirt_wrapper) +{ + if (!management_ip) + { + auto result = instance_ip_for(mac_addr, libvirt_wrapper); + if (result) + management_ip.emplace(result.value()); + else + return "UNKNOWN"; + } + + return management_ip.value().as_string(); +} } // namespace mp::LibVirtVirtualMachine::LibVirtVirtualMachine(const mp::VirtualMachineDescription& desc, @@ -440,18 +456,9 @@ std::string mp::LibVirtVirtualMachine::ssh_username() return username; } -std::string mp::LibVirtVirtualMachine::management_ipv4() +std::string mp::LibVirtVirtualMachine::management_ipv4(const SSHKeyProvider& /* not used on this backend */) { - if (!management_ip) - { - auto result = instance_ip_for(mac_addr, libvirt_wrapper); - if (result) - management_ip.emplace(result.value()); - else - return "UNKNOWN"; - } - - return management_ip.value().as_string(); + return management_ipv4_impl(management_ip, mac_addr, libvirt_wrapper); } std::string mp::LibVirtVirtualMachine::ipv6() @@ -459,9 +466,12 @@ std::string mp::LibVirtVirtualMachine::ipv6() return {}; } -void mp::LibVirtVirtualMachine::wait_until_ssh_up(std::chrono::milliseconds timeout) +void mp::LibVirtVirtualMachine::wait_until_ssh_up(std::chrono::milliseconds timeout, const SSHKeyProvider& key_provider) { - mp::utils::wait_until_ssh_up(this, timeout, std::bind(&LibVirtVirtualMachine::ensure_vm_is_running, this)); + mp::utils::wait_until_ssh_up(this, + timeout, + key_provider, + std::bind(&LibVirtVirtualMachine::ensure_vm_is_running, this)); } void mp::LibVirtVirtualMachine::update_state() @@ -481,7 +491,7 @@ mp::LibVirtVirtualMachine::DomainUPtr mp::LibVirtVirtualMachine::initialize_doma if (mac_addr.empty()) mac_addr = instance_mac_addr_for(domain.get(), libvirt_wrapper); - management_ipv4(); // To set ip + management_ipv4_impl(management_ip, mac_addr, libvirt_wrapper); // To set the IP. state = refresh_instance_state_for_domain(domain.get(), state, libvirt_wrapper); return domain; diff --git a/src/platform/backends/libvirt/libvirt_virtual_machine.h b/src/platform/backends/libvirt/libvirt_virtual_machine.h index e0018ab4b2..bf717fc3dd 100644 --- a/src/platform/backends/libvirt/libvirt_virtual_machine.h +++ b/src/platform/backends/libvirt/libvirt_virtual_machine.h @@ -47,9 +47,9 @@ class LibVirtVirtualMachine final : public BaseVirtualMachine int ssh_port() override; std::string ssh_hostname(std::chrono::milliseconds timeout) override; std::string ssh_username() override; - std::string management_ipv4() override; + std::string management_ipv4(const SSHKeyProvider& key_provider) override; std::string ipv6() override; - void wait_until_ssh_up(std::chrono::milliseconds timeout) override; + void wait_until_ssh_up(std::chrono::milliseconds timeout, const SSHKeyProvider& key_provider) override; void ensure_vm_is_running() override; void update_state() override; void update_cpus(int num_cores) override; diff --git a/src/platform/backends/lxd/lxd_virtual_machine.cpp b/src/platform/backends/lxd/lxd_virtual_machine.cpp index b884444d4d..80249b8f0c 100644 --- a/src/platform/backends/lxd/lxd_virtual_machine.cpp +++ b/src/platform/backends/lxd/lxd_virtual_machine.cpp @@ -365,7 +365,7 @@ std::string mp::LXDVirtualMachine::ssh_username() return username; } -std::string mp::LXDVirtualMachine::management_ipv4() +std::string mp::LXDVirtualMachine::management_ipv4(const SSHKeyProvider& /* unused on this backend */) { if (!management_ip) { @@ -385,9 +385,9 @@ std::string mp::LXDVirtualMachine::ipv6() return {}; } -void mp::LXDVirtualMachine::wait_until_ssh_up(std::chrono::milliseconds timeout) +void mp::LXDVirtualMachine::wait_until_ssh_up(std::chrono::milliseconds timeout, const SSHKeyProvider& key_provider) { - mpu::wait_until_ssh_up(this, timeout, [this] { ensure_vm_is_running(); }); + mpu::wait_until_ssh_up(this, timeout, key_provider, [this] { ensure_vm_is_running(); }); } const QUrl mp::LXDVirtualMachine::url() diff --git a/src/platform/backends/lxd/lxd_virtual_machine.h b/src/platform/backends/lxd/lxd_virtual_machine.h index c463526592..11569c62a9 100644 --- a/src/platform/backends/lxd/lxd_virtual_machine.h +++ b/src/platform/backends/lxd/lxd_virtual_machine.h @@ -44,11 +44,11 @@ class LXDVirtualMachine : public BaseVirtualMachine int ssh_port() override; std::string ssh_hostname(std::chrono::milliseconds timeout) override; std::string ssh_username() override; - std::string management_ipv4() override; + std::string management_ipv4(const SSHKeyProvider& key_provider) override; std::string ipv6() override; void ensure_vm_is_running() override; void ensure_vm_is_running(const std::chrono::milliseconds& timeout); - void wait_until_ssh_up(std::chrono::milliseconds timeout) override; + void wait_until_ssh_up(std::chrono::milliseconds timeout, const SSHKeyProvider& key_provider) override; void update_state() override; void update_cpus(int num_cores) override; void resize_memory(const MemorySize& new_size) override; diff --git a/src/platform/backends/qemu/qemu_virtual_machine.cpp b/src/platform/backends/qemu/qemu_virtual_machine.cpp index 8a0a197fb8..35b5dd6a28 100644 --- a/src/platform/backends/qemu/qemu_virtual_machine.cpp +++ b/src/platform/backends/qemu/qemu_virtual_machine.cpp @@ -477,7 +477,7 @@ std::string mp::QemuVirtualMachine::ssh_username() return username; } -std::string mp::QemuVirtualMachine::management_ipv4() +std::string mp::QemuVirtualMachine::management_ipv4(const SSHKeyProvider& /* unused on this backend */) { if (!management_ip) { @@ -496,9 +496,12 @@ std::string mp::QemuVirtualMachine::ipv6() return {}; } -void mp::QemuVirtualMachine::wait_until_ssh_up(std::chrono::milliseconds timeout) +void mp::QemuVirtualMachine::wait_until_ssh_up(std::chrono::milliseconds timeout, const SSHKeyProvider& key_provider) { - mp::utils::wait_until_ssh_up(this, timeout, std::bind(&QemuVirtualMachine::ensure_vm_is_running, this)); + mp::utils::wait_until_ssh_up(this, + timeout, + key_provider, + std::bind(&QemuVirtualMachine::ensure_vm_is_running, this)); if (is_starting_from_suspend) { diff --git a/src/platform/backends/qemu/qemu_virtual_machine.h b/src/platform/backends/qemu/qemu_virtual_machine.h index 4e43427698..f0bd31ce66 100644 --- a/src/platform/backends/qemu/qemu_virtual_machine.h +++ b/src/platform/backends/qemu/qemu_virtual_machine.h @@ -52,10 +52,10 @@ class QemuVirtualMachine : public QObject, public BaseVirtualMachine int ssh_port() override; std::string ssh_hostname(std::chrono::milliseconds timeout) override; std::string ssh_username() override; - std::string management_ipv4() override; + std::string management_ipv4(const SSHKeyProvider& key_provider) override; std::string ipv6() override; void ensure_vm_is_running() override; - void wait_until_ssh_up(std::chrono::milliseconds timeout) override; + void wait_until_ssh_up(std::chrono::milliseconds timeout, const SSHKeyProvider& key_provider) override; void update_state() override; void update_cpus(int num_cores) override; void resize_memory(const MemorySize& new_size) override; diff --git a/src/ssh/ssh_session.cpp b/src/ssh/ssh_session.cpp index 68f73f3f53..365f1045f4 100644 --- a/src/ssh/ssh_session.cpp +++ b/src/ssh/ssh_session.cpp @@ -32,8 +32,11 @@ namespace mp = multipass; namespace mpl = multipass::logging; -mp::SSHSession::SSHSession(const std::string& host, int port, const std::string& username, - const SSHKeyProvider* key_provider, const std::chrono::milliseconds timeout) +mp::SSHSession::SSHSession(const std::string& host, + int port, + const std::string& username, + const SSHKeyProvider& key_provider, + const std::chrono::milliseconds timeout) : session{ssh_new(), ssh_free} { if (session == nullptr) @@ -53,22 +56,12 @@ mp::SSHSession::SSHSession(const std::string& host, int port, const std::string& set_option(SSH_OPTIONS_SSH_DIR, ssh_dir.c_str()); SSH::throw_on_error(session, "ssh connection failed", ssh_connect); - if (key_provider) - { - SSH::throw_on_error(session, "ssh failed to authenticate", ssh_userauth_publickey, nullptr, - key_provider->private_key()); - } -} -mp::SSHSession::SSHSession(const std::string& host, int port, const std::string& username, - const SSHKeyProvider& key_provider, const std::chrono::milliseconds timeout) - : SSHSession(host, port, username, &key_provider, timeout) -{ -} - -mp::SSHSession::SSHSession(const std::string& host, int port, const std::chrono::milliseconds timeout) - : SSHSession(host, port, "ubuntu", nullptr, timeout) -{ + SSH::throw_on_error(session, + "ssh failed to authenticate", + ssh_userauth_publickey, + nullptr, + key_provider.private_key()); } mp::SSHProcess mp::SSHSession::exec(const std::string& cmd) diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index ebb9cfac29..7668009d32 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -320,17 +320,22 @@ bool mp::utils::valid_mac_address(const std::string& mac) return match.hasMatch(); } -void mp::utils::wait_until_ssh_up(VirtualMachine* virtual_machine, std::chrono::milliseconds timeout, +void mp::utils::wait_until_ssh_up(VirtualMachine* virtual_machine, + std::chrono::milliseconds timeout, + const mp::SSHKeyProvider& key_provider, std::function const& ensure_vm_is_running) { static constexpr auto wait_step = 1s; mpl::log(mpl::Level::debug, virtual_machine->vm_name, "Waiting for SSH to be up"); - auto action = [virtual_machine, &ensure_vm_is_running] { + auto action = [virtual_machine, &key_provider, &ensure_vm_is_running] { ensure_vm_is_running(); try { - mp::SSHSession session{virtual_machine->ssh_hostname(wait_step), virtual_machine->ssh_port()}; + mp::SSHSession session{virtual_machine->ssh_hostname(wait_step), + virtual_machine->ssh_port(), + virtual_machine->ssh_username(), + key_provider}; std::lock_guardstate_mutex)> lock{virtual_machine->state_mutex}; virtual_machine->state = VirtualMachine::State::running; diff --git a/tests/libvirt/test_libvirt_backend.cpp b/tests/libvirt/test_libvirt_backend.cpp index dfa79658cf..483d64d705 100644 --- a/tests/libvirt/test_libvirt_backend.cpp +++ b/tests/libvirt/test_libvirt_backend.cpp @@ -51,7 +51,7 @@ struct LibVirtBackend : public Test "pied-piper-valley", "", {}, - "", + "ubuntu", {dummy_image.name(), "", "", "", "", {}}, dummy_cloud_init_iso.name(), {}, @@ -130,7 +130,9 @@ TEST_F(LibVirtBackend, creates_in_suspended_state_with_managed_save) TEST_F(LibVirtBackend, machine_sends_monitoring_events) { + const mpt::StubSSHKeyProvider key_provider; REPLACE(ssh_connect, [](auto...) { return SSH_OK; }); + REPLACE(ssh_userauth_publickey, [](auto...) { return SSH_AUTH_SUCCESS; }); mp::LibVirtVirtualMachineFactory backend{data_dir.path(), fake_libvirt_path}; backend.libvirt_wrapper->virNetworkGetDHCPLeases = [](auto, auto, auto leases, auto) { @@ -154,7 +156,7 @@ TEST_F(LibVirtBackend, machine_sends_monitoring_events) return 0; }; - machine->wait_until_ssh_up(2min); + machine->wait_until_ssh_up(2min, key_provider); EXPECT_CALL(mock_monitor, on_shutdown()); machine->shutdown(); diff --git a/tests/lxd/test_lxd_backend.cpp b/tests/lxd/test_lxd_backend.cpp index eeb5ad8303..4cf7ac838b 100644 --- a/tests/lxd/test_lxd_backend.cpp +++ b/tests/lxd/test_lxd_backend.cpp @@ -25,6 +25,7 @@ #include "tests/mock_logger.h" #include "tests/mock_platform.h" #include "tests/mock_status_monitor.h" +#include "tests/stub_ssh_key_provider.h" #include "tests/stub_status_monitor.h" #include "tests/stub_url_downloader.h" #include "tests/temp_dir.h" @@ -1099,7 +1100,7 @@ TEST_P(LXDNetworkInfoSuite, returns_expected_network_info) mp::LXDVirtualMachine machine{default_description, stub_monitor, mock_network_access_manager.get(), base_url, bridge_name, default_storage_pool}; - EXPECT_EQ(machine.management_ipv4(), "10.217.27.168"); + EXPECT_EQ(machine.management_ipv4(mpt::StubSSHKeyProvider()), "10.217.27.168"); EXPECT_TRUE(machine.ipv6().empty()); EXPECT_EQ(machine.ssh_username(), default_description.ssh_username); EXPECT_EQ(machine.ssh_port(), 22); @@ -1182,7 +1183,7 @@ TEST_F(LXDBackend, no_ip_address_returns_unknown) mp::LXDVirtualMachine machine{default_description, stub_monitor, mock_network_access_manager.get(), base_url, bridge_name, default_storage_pool}; - EXPECT_EQ(machine.management_ipv4(), "UNKNOWN"); + EXPECT_EQ(machine.management_ipv4(mpt::StubSSHKeyProvider()), "UNKNOWN"); } TEST_F(LXDBackend, lxd_request_timeout_aborts_and_throws) diff --git a/tests/mock_virtual_machine.h b/tests/mock_virtual_machine.h index b892986e40..81df94b440 100644 --- a/tests/mock_virtual_machine.h +++ b/tests/mock_virtual_machine.h @@ -41,7 +41,7 @@ struct MockVirtualMachineT : public T ON_CALL(*this, ssh_hostname()).WillByDefault(Return("localhost")); ON_CALL(*this, ssh_hostname(_)).WillByDefault(Return("localhost")); ON_CALL(*this, ssh_username()).WillByDefault(Return("ubuntu")); - ON_CALL(*this, management_ipv4()).WillByDefault(Return("0.0.0.0")); + ON_CALL(*this, management_ipv4(_)).WillByDefault(Return("0.0.0.0")); ON_CALL(*this, get_all_ipv4(_)).WillByDefault(Return(std::vector{"192.168.2.123"})); ON_CALL(*this, ipv6()).WillByDefault(Return("::/0")); } @@ -55,11 +55,11 @@ struct MockVirtualMachineT : public T MOCK_METHOD(std::string, ssh_hostname, (), (override)); MOCK_METHOD(std::string, ssh_hostname, (std::chrono::milliseconds), (override)); MOCK_METHOD(std::string, ssh_username, (), (override)); - MOCK_METHOD(std::string, management_ipv4, (), (override)); + MOCK_METHOD(std::string, management_ipv4, (const SSHKeyProvider&), (override)); MOCK_METHOD(std::vector, get_all_ipv4, (const SSHKeyProvider&), (override)); MOCK_METHOD(std::string, ipv6, (), (override)); MOCK_METHOD(void, ensure_vm_is_running, (), (override)); - MOCK_METHOD(void, wait_until_ssh_up, (std::chrono::milliseconds), (override)); + MOCK_METHOD(void, wait_until_ssh_up, (std::chrono::milliseconds, const SSHKeyProvider&), (override)); MOCK_METHOD(void, update_state, (), (override)); MOCK_METHOD(void, update_cpus, (int num_cores), (override)); MOCK_METHOD(void, resize_memory, (const MemorySize& new_size), (override)); diff --git a/tests/qemu/test_qemu_backend.cpp b/tests/qemu/test_qemu_backend.cpp index fdabf705ce..01e7ea4b4d 100644 --- a/tests/qemu/test_qemu_backend.cpp +++ b/tests/qemu/test_qemu_backend.cpp @@ -641,7 +641,7 @@ TEST_F(QemuBackend, gets_management_ip) machine.start(); machine.state = mp::VirtualMachine::State::running; - EXPECT_EQ(machine.management_ipv4(), expected_ip); + EXPECT_EQ(machine.management_ipv4(mpt::StubSSHKeyProvider()), expected_ip); } TEST_F(QemuBackend, fails_to_get_management_ip_if_dnsmasq_does_not_return_an_ip) @@ -655,7 +655,7 @@ TEST_F(QemuBackend, fails_to_get_management_ip_if_dnsmasq_does_not_return_an_ip) machine.start(); machine.state = mp::VirtualMachine::State::running; - EXPECT_EQ(machine.management_ipv4(), "UNKNOWN"); + EXPECT_EQ(machine.management_ipv4(mpt::StubSSHKeyProvider()), "UNKNOWN"); } TEST_F(QemuBackend, ssh_hostname_timeout_throws_and_sets_unknown_state) diff --git a/tests/stub_virtual_machine.h b/tests/stub_virtual_machine.h index 11836fc7a1..5ed0f25f5d 100644 --- a/tests/stub_virtual_machine.h +++ b/tests/stub_virtual_machine.h @@ -71,7 +71,7 @@ struct StubVirtualMachine final : public multipass::VirtualMachine return "ubuntu"; } - std::string management_ipv4() override + std::string management_ipv4(const SSHKeyProvider& key_provider) override { return {}; } @@ -91,7 +91,7 @@ struct StubVirtualMachine final : public multipass::VirtualMachine throw std::runtime_error("Not running"); } - void wait_until_ssh_up(std::chrono::milliseconds) override + void wait_until_ssh_up(std::chrono::milliseconds, const SSHKeyProvider&) override { } diff --git a/tests/test_base_virtual_machine.cpp b/tests/test_base_virtual_machine.cpp index 844d3ac66b..aa49695ea3 100644 --- a/tests/test_base_virtual_machine.cpp +++ b/tests/test_base_virtual_machine.cpp @@ -79,7 +79,7 @@ struct StubBaseVirtualMachine : public mp::BaseVirtualMachine return "ubuntu"; } - std::string management_ipv4() override + std::string management_ipv4(const mp::SSHKeyProvider&) override { return "1.2.3.4"; } @@ -89,7 +89,7 @@ struct StubBaseVirtualMachine : public mp::BaseVirtualMachine return ""; } - void wait_until_ssh_up(std::chrono::milliseconds timeout) override + void wait_until_ssh_up(std::chrono::milliseconds timeout, const mp::SSHKeyProvider& key_provider) override { } diff --git a/tests/test_daemon.cpp b/tests/test_daemon.cpp index a44d75b875..0d6c126708 100644 --- a/tests/test_daemon.cpp +++ b/tests/test_daemon.cpp @@ -1874,8 +1874,10 @@ TEST_P(DaemonLaunchTimeoutValueTestSuite, uses_correct_launch_timeout) EXPECT_CALL(*mock_blueprint_provider, blueprint_timeout(_)).WillOnce(Return(blueprint_timeout)); - EXPECT_CALL(*instance_ptr, wait_until_ssh_up(std::chrono::duration_cast( - std::chrono::seconds(expected_timeout)))) + EXPECT_CALL( + *instance_ptr, + wait_until_ssh_up(std::chrono::duration_cast(std::chrono::seconds(expected_timeout)), + _)) .WillRepeatedly(Return()); EXPECT_CALL( mock_utils, diff --git a/tests/test_daemon_start.cpp b/tests/test_daemon_start.cpp index cebf857609..9cb152864a 100644 --- a/tests/test_daemon_start.cpp +++ b/tests/test_daemon_start.cpp @@ -63,7 +63,7 @@ TEST_F(TestDaemonStart, successfulStartOkStatus) EXPECT_CALL(*mock_factory, create_virtual_machine(_, _)).WillOnce([&instance_ptr](const auto&, auto&) { return std::move(instance_ptr); }); - EXPECT_CALL(*instance_ptr, wait_until_ssh_up(_)).WillRepeatedly(Return()); + EXPECT_CALL(*instance_ptr, wait_until_ssh_up).WillRepeatedly(Return()); EXPECT_CALL(*instance_ptr, current_state()).WillRepeatedly(Return(mp::VirtualMachine::State::off)); EXPECT_CALL(*instance_ptr, start()).Times(1); diff --git a/tests/test_delayed_shutdown.cpp b/tests/test_delayed_shutdown.cpp index c80d382423..cad98e1906 100644 --- a/tests/test_delayed_shutdown.cpp +++ b/tests/test_delayed_shutdown.cpp @@ -18,6 +18,7 @@ #include "common.h" #include "mock_ssh_test_fixture.h" #include "signal.h" +#include "stub_ssh_key_provider.h" #include "stub_virtual_machine.h" #include @@ -39,9 +40,10 @@ struct DelayedShutdown : public Test vm->state = mp::VirtualMachine::State::running; } + const mpt::StubSSHKeyProvider key_provider; mpt::MockSSHTestFixture mock_ssh_test_fixture; mp::VirtualMachine::UPtr vm; - mp::SSHSession session{"a", 42}; + mp::SSHSession session{"a", 42, "ubuntu", key_provider}; QEventLoop loop; ssh_channel_callbacks callbacks{nullptr}; }; diff --git a/tests/test_sftp_client.cpp b/tests/test_sftp_client.cpp index c74f49e114..fb2366eb81 100644 --- a/tests/test_sftp_client.cpp +++ b/tests/test_sftp_client.cpp @@ -23,6 +23,7 @@ #include "mock_sftp_dir_iterator.h" #include "mock_sftp_utils.h" #include "mock_ssh_test_fixture.h" +#include "stub_ssh_key_provider.h" #include #include @@ -70,15 +71,16 @@ struct SFTPClient : public testing::Test close.returnValue(SSH_OK); } - static mp::SFTPClient make_sftp_client() + mp::SFTPClient make_sftp_client() { - return {std::make_unique("b", 43)}; + return {std::make_unique("b", 43, "ubuntu", key_provider)}; } decltype(MOCK(sftp_close)) close{MOCK(sftp_close)}; MockScope sftp_new; MockScope free_sftp; + const mpt::StubSSHKeyProvider key_provider; mpt::MockSSHTestFixture mock_ssh_test_fixture; mpt::MockFileOps::GuardedMock mock_file_ops_guard{mpt::MockFileOps::inject()}; diff --git a/tests/test_sftpserver.cpp b/tests/test_sftpserver.cpp index e5cbc0ce2b..49cfea935a 100644 --- a/tests/test_sftpserver.cpp +++ b/tests/test_sftpserver.cpp @@ -24,6 +24,7 @@ #include "mock_ssh_process_exit_status.h" #include "path.h" #include "sftp_server_test_fixture.h" +#include "stub_ssh_key_provider.h" #include "temp_dir.h" #include "temp_file.h" @@ -56,7 +57,7 @@ struct SftpServer : public mp::test::SftpServerTest mp::SftpServer make_sftpserver(const std::string& path, const mp::id_mappings& gid_mappings = {}, const mp::id_mappings& uid_mappings = {}) { - mp::SSHSession session{"a", 42}; + mp::SSHSession session{"a", 42, "ubuntu", key_provider}; return {std::move(session), path, path, gid_mappings, uid_mappings, default_id, default_id, "sshfs"}; } @@ -92,6 +93,7 @@ struct SftpServer : public mp::test::SftpServerTest return reply_status; } + const mpt::StubSSHKeyProvider key_provider; mpt::ExitStatusMock exit_status_mock; std::queue messages; int default_id{1000}; diff --git a/tests/test_ssh_client.cpp b/tests/test_ssh_client.cpp index 608e5b0487..2ac5e04c43 100644 --- a/tests/test_ssh_client.cpp +++ b/tests/test_ssh_client.cpp @@ -21,6 +21,7 @@ #include "mock_ssh_client.h" #include "mock_ssh_test_fixture.h" #include "stub_console.h" +#include "stub_ssh_key_provider.h" #include #include @@ -34,9 +35,10 @@ struct SSHClient : public testing::Test { mp::SSHClient make_ssh_client() { - return {std::make_unique("a", 42), console_creator}; + return {std::make_unique("a", 42, "ubuntu", key_provider), console_creator}; } + const mpt::StubSSHKeyProvider key_provider; mpt::MockSSHTestFixture mock_ssh_test_fixture; mp::SSHClient::ConsoleCreator console_creator = [](auto /*channel*/) { return std::make_unique(); diff --git a/tests/test_ssh_process.cpp b/tests/test_ssh_process.cpp index d7ee6d6653..d697997842 100644 --- a/tests/test_ssh_process.cpp +++ b/tests/test_ssh_process.cpp @@ -17,6 +17,7 @@ #include "common.h" #include "mock_ssh_test_fixture.h" +#include "stub_ssh_key_provider.h" #include @@ -32,8 +33,9 @@ namespace { struct SSHProcess : public Test { + const mpt::StubSSHKeyProvider key_provider; mpt::MockSSHTestFixture mock_ssh_test_fixture; - mp::SSHSession session{"theanswertoeverything", 42}; + mp::SSHSession session{"theanswertoeverything", 42, "ubuntu", key_provider}; }; } // namespace diff --git a/tests/test_ssh_session.cpp b/tests/test_ssh_session.cpp index bf0758fa77..09bae83492 100644 --- a/tests/test_ssh_session.cpp +++ b/tests/test_ssh_session.cpp @@ -24,64 +24,80 @@ namespace mp = multipass; using namespace testing; -TEST(SSHSession, throws_when_unable_to_allocate_session) +namespace +{ +struct SSHSession : public Test +{ + mp::SSHSession make_ssh_session() + { + return mp::SSHSession("theanswertoeverything", 42, "ubuntu", key_provider); + } + + mp::test::StubSSHKeyProvider key_provider; +}; +} // namespace + +TEST_F(SSHSession, throws_when_unable_to_allocate_session) { REPLACE(ssh_new, []() { return nullptr; }); - EXPECT_THROW(mp::SSHSession("theanswertoeverything", 42), std::runtime_error); + EXPECT_THROW(make_ssh_session(), std::runtime_error); } -TEST(SSHSession, throws_when_unable_to_set_option) +TEST_F(SSHSession, throws_when_unable_to_set_option) { REPLACE(ssh_options_set, [](auto...) { return SSH_ERROR; }); - EXPECT_THROW(mp::SSHSession("theanswertoeverything", 42), std::runtime_error); + EXPECT_THROW(make_ssh_session(), std::runtime_error); } -TEST(SSHSession, throws_when_unable_to_connect) +TEST_F(SSHSession, throws_when_unable_to_connect) { REPLACE(ssh_connect, [](auto...) { return SSH_ERROR; }); - EXPECT_THROW(mp::SSHSession("theanswertoeverything", 42), std::runtime_error); + EXPECT_THROW(make_ssh_session(), std::runtime_error); } -TEST(SSHSession, throws_when_unable_to_auth) +TEST_F(SSHSession, throws_when_unable_to_auth) { - mp::test::StubSSHKeyProvider key_provider; REPLACE(ssh_connect, [](auto...) { return SSH_OK; }); REPLACE(ssh_userauth_publickey, [](auto...) { return SSH_AUTH_ERROR; }); - EXPECT_THROW(mp::SSHSession("theanswertoeverything", 42, "ubuntu", key_provider), std::runtime_error); + EXPECT_THROW(make_ssh_session(), std::runtime_error); } -TEST(SSHSession, exec_throws_on_a_dead_session) +TEST_F(SSHSession, exec_throws_on_a_dead_session) { REPLACE(ssh_connect, [](auto...) { return SSH_OK; }); - mp::SSHSession session{"theanswertoeverything", 42}; + REPLACE(ssh_userauth_publickey, [](auto...) { return SSH_AUTH_SUCCESS; }); + mp::SSHSession session = make_ssh_session(); REPLACE(ssh_is_connected, [](auto...) { return false; }); EXPECT_THROW(session.exec("dummy"), std::runtime_error); } -TEST(SSHSession, exec_throws_if_ssh_is_dead) +TEST_F(SSHSession, exec_throws_if_ssh_is_dead) { REPLACE(ssh_connect, [](auto...) { return SSH_OK; }); - mp::SSHSession session{"theanswertoeverything", 42}; + REPLACE(ssh_userauth_publickey, [](auto...) { return SSH_AUTH_SUCCESS; }); + mp::SSHSession session = make_ssh_session(); REPLACE(ssh_is_connected, [](auto...) { return false; }); EXPECT_THROW(session.exec("dummy"), std::runtime_error); } -TEST(SSHSession, exec_throws_when_unable_to_open_a_channel_session) +TEST_F(SSHSession, exec_throws_when_unable_to_open_a_channel_session) { REPLACE(ssh_connect, [](auto...) { return SSH_OK; }); - mp::SSHSession session{"theanswertoeverything", 42}; + REPLACE(ssh_userauth_publickey, [](auto...) { return SSH_AUTH_SUCCESS; }); + mp::SSHSession session = make_ssh_session(); REPLACE(ssh_is_connected, [](auto...) { return true; }); REPLACE(ssh_channel_open_session, [](auto...) { return SSH_ERROR; }); EXPECT_THROW(session.exec("dummy"), std::runtime_error); } -TEST(SSHSession, exec_throws_when_unable_to_request_channel_exec) +TEST_F(SSHSession, exec_throws_when_unable_to_request_channel_exec) { REPLACE(ssh_connect, [](auto...) { return SSH_OK; }); - mp::SSHSession session{"theanswertoeverything", 42}; + REPLACE(ssh_userauth_publickey, [](auto...) { return SSH_AUTH_SUCCESS; }); + mp::SSHSession session = make_ssh_session(); REPLACE(ssh_is_connected, [](auto...) { return true; }); REPLACE(ssh_channel_open_session, [](auto...) { return SSH_OK; }); @@ -89,10 +105,11 @@ TEST(SSHSession, exec_throws_when_unable_to_request_channel_exec) EXPECT_THROW(session.exec("dummy"), std::runtime_error); } -TEST(SSHSession, exec_succeeds) +TEST_F(SSHSession, exec_succeeds) { REPLACE(ssh_connect, [](auto...) { return SSH_OK; }); - mp::SSHSession session{"theanswertoeverything", 42}; + REPLACE(ssh_userauth_publickey, [](auto...) { return SSH_AUTH_SUCCESS; }); + mp::SSHSession session = make_ssh_session(); REPLACE(ssh_is_connected, [](auto...) { return true; }); REPLACE(ssh_channel_open_session, [](auto...) { return SSH_OK; }); diff --git a/tests/test_sshfsmount.cpp b/tests/test_sshfsmount.cpp index 6db300dce9..36d9c355f8 100644 --- a/tests/test_sshfsmount.cpp +++ b/tests/test_sshfsmount.cpp @@ -20,6 +20,7 @@ #include "mock_ssh_process_exit_status.h" #include "sftp_server_test_fixture.h" #include "signal.h" +#include "stub_ssh_key_provider.h" #include @@ -48,7 +49,7 @@ struct SshfsMount : public mp::test::SftpServerTest { mp::SshfsMount make_sshfsmount(std::optional target = std::nullopt) { - mp::SSHSession session{"a", 42}; + mp::SSHSession session{"a", 42, "ubuntu", key_provider}; return {std::move(session), default_source, target.value_or(default_target), default_mappings, default_mappings}; } @@ -181,6 +182,7 @@ struct SshfsMount : public mp::test::SftpServerTest mp::id_mappings default_mappings; int default_id{1000}; mpt::MockLogger::Scope logger_scope = mpt::MockLogger::inject(); + const mpt::StubSSHKeyProvider key_provider; const std::unordered_map default_cmds{ {"snap run multipass-sshfs.env", "LD_LIBRARY_PATH=/foo/bar\nSNAP=/baz\n"},