diff --git a/include/multipass/daemon_rpc_context.h b/include/multipass/daemon_rpc_context.h new file mode 100644 index 0000000000..9424032ef6 --- /dev/null +++ b/include/multipass/daemon_rpc_context.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) Canonical, Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#pragma once + +#include + +#include + +#include +#include + +namespace multipass +{ + +struct DaemonRpcContext +{ + virtual void set_value(grpc::Status status) = 0; + virtual ~DaemonRpcContext() = default; +}; + +template +struct DaemonRpcContextImpl : DaemonRpcContext, private multipass::DisabledCopyMove +{ + DaemonRpcContextImpl(std::promise& promise, + grpc::ServerReaderWriterInterface* server, + logging::Level level, + logging::MultiplexingLogger& mpx) + : promise(promise), + // We have to construct the logger here since we can't move or copy it. + logger{std::make_optional>(level, mpx, server)} + { + } + + void set_value(grpc::Status status) override + { + // Free any resources that depend on server here. + logger.reset(); + promise.set_value(std::move(status)); + } + +private: + std::promise& promise; + std::optional> logger; +}; + +} // namespace multipass diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 2d5aa9846f..9d0b03bf68 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -24,6 +24,8 @@ #include #include #include + +#include #include #include #include @@ -968,8 +970,8 @@ mp::MemorySize compute_final_image_size(const mp::MemorySize image_size, if (!command_line_value) { auto default_disk_size_as_struct = mp::MemorySize(mp::default_disk_size); - disk_space = - image_size < default_disk_size_as_struct ? default_disk_size_as_struct : image_size; + disk_space = image_size < default_disk_size_as_struct ? default_disk_size_as_struct + : image_size; } else if (*command_line_value < image_size) { @@ -1288,7 +1290,10 @@ mp::Daemon::Daemon(std::unique_ptr the_config) mp::utils::backend_directory_path(config->cache_directory, config->factory->get_backend_directory_name()), *config->az_manager)}, - daemon_rpc{config->server_address, *config->cert_provider, config->client_cert_store.get()}, + daemon_rpc{config->server_address, + *config->cert_provider, + config->client_cert_store.get(), + config->logger}, instance_mod_handler{register_instance_mod( vm_instance_specs, operative_instances, @@ -1533,31 +1538,22 @@ void mp::Daemon::shutdown_grpc_server() void mp::Daemon::create(const CreateRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - return create_vm(request, server, status_promise, /*start=*/false); + return create_vm(request, server, context, /*start=*/false); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::launch(const LaunchRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - - return create_vm(request, server, status_promise, /*start=*/true); + return create_vm(request, server, context, /*start=*/true); } catch (const mp::StartException& e) { @@ -1567,16 +1563,16 @@ catch (const mp::StartException& e) operative_instances.erase(name); persist_instances(); - status_promise->set_value(grpc::Status(grpc::StatusCode::ABORTED, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::ABORTED, e.what(), "")); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::purge(const PurgeRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { PurgeReply response; @@ -1593,21 +1589,18 @@ try persist_instances(); server->Write(response); - status_promise->set_value(grpc::Status::OK); + context->set_value(grpc::Status::OK); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::find(const FindRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{mpl::level_from(request->verbosity_level()), - *config->logger, - server}; FindReply response; if (!request->search_string().empty()) @@ -1654,8 +1647,8 @@ try auto remote_name = (!request->remote_name().empty() || (request->remote_name().empty() && vm_images_info.size() > 1 && remote != mp::release_remote)) - ? remote - : ""; + ? remote + : ""; add_aliases(response.mutable_images_info(), remote_name, info); } @@ -1694,21 +1687,18 @@ try } server->Write(response); - status_promise->set_value(grpc::Status::OK); + context->set_value(grpc::Status::OK); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::info(const InfoRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{mpl::level_from(request->verbosity_level()), - *config->logger, - server}; InfoReply response; config->update_prompt->populate_if_time_to_show(response.mutable_update_info()); InstanceSnapshotsMap instance_snapshots_map; @@ -1740,8 +1730,8 @@ try const auto& name = vm.get_name(); const auto& it = instance_snapshots_map.find(name); - const auto& snapshot_pick = - it == instance_snapshots_map.end() ? SnapshotPick{{}, true} : it->second; + const auto& snapshot_pick = it == instance_snapshots_map.end() ? SnapshotPick{{}, true} + : it->second; try { @@ -1790,21 +1780,18 @@ try server->Write(response); } - status_promise->set_value(status); + context->set_value(status); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::list(const ListRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{mpl::level_from(request->verbosity_level()), - *config->logger, - server}; ListReply response; config->update_prompt->populate_if_time_to_show(response.mutable_update_info()); @@ -1899,22 +1886,18 @@ try } server->Write(response); - status_promise->set_value(status); + context->set_value(status); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::networks(const NetworksRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; NetworksReply response; config->update_prompt->populate_if_time_to_show(response.mutable_update_info()); @@ -1932,24 +1915,20 @@ try } server->Write(response); - status_promise->set_value(grpc::Status::OK); + context->set_value(grpc::Status::OK); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::mount(const MountRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - if (!MP_SETTINGS.get_as(mp::mounts_key)) - return status_promise->set_value(grpc::Status( + return context->set_value(grpc::Status( grpc::StatusCode::FAILED_PRECONDITION, "Mounts are disabled on this installation of Multipass.\n\n" "See https://canonical.com/multipass/docs/set-command#local.privileged-mounts for " @@ -2006,8 +1985,8 @@ try } const auto mount_type = request->mount_type() == MountRequest_MountType_CLASSIC - ? VMMount::MountType::Classic - : VMMount::MountType::Native; + ? VMMount::MountType::Classic + : VMMount::MountType::Native; VMMount vm_mount{request->source_path(), gid_mappings, uid_mappings, mount_type}; vm_mounts[target_path] = make_mount(vm.get(), target_path, vm_mount); @@ -2020,7 +1999,7 @@ try } catch (const mp::SSHFSMissingError&) { - return status_promise->set_value(grpc_status_for_mount_error(name)); + return context->set_value(grpc_status_for_mount_error(name)); } catch (const std::exception& e) { @@ -2035,23 +2014,18 @@ try persist_instances(); - status_promise->set_value(grpc_status_for(errors)); + context->set_value(grpc_status_for(errors)); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::recover(const RecoverRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - auto recover_reaction = require_existing_instances_reaction; recover_reaction.operative_reaction.message_template = "instance \"{}\" does not need to be recovered"; @@ -2078,23 +2052,18 @@ try persist_instances(); } - status_promise->set_value(status); + context->set_value(status); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::ssh_info(const SSHInfoRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - auto [instance_selection, status] = select_instances_and_react(operative_instances, deleted_instances, @@ -2113,24 +2082,20 @@ try server->Write(response); } - status_promise->set_value(status); + context->set_value(status); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::start(const StartRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - - auto timeout = - request->timeout() > 0 ? std::chrono::seconds(request->timeout()) : mp::default_timeout; + auto timeout = request->timeout() > 0 ? std::chrono::seconds(request->timeout()) + : mp::default_timeout; if (!instances_running(operative_instances)) config->factory->hypervisor_health_check(); @@ -2146,9 +2111,9 @@ try custom_reaction); if (!status.ok()) - return status_promise->set_value({status.error_code(), - "instance(s) missing", - make_start_error_details(instance_selection)}); + return context->set_value({status.error_code(), + "instance(s) missing", + make_start_error_details(instance_selection)}); bool complain_disabled_mounts = !MP_SETTINGS.get_as(mp::mounts_key); @@ -2210,24 +2175,20 @@ try server, starting_vms, timeout, - status_promise, + context, fmt::to_string(start_errors), fmt::to_string(start_warnings))); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::stop(const StopRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - auto [instance_selection, status] = select_instances_and_react(operative_instances, deleted_instances, @@ -2252,27 +2213,22 @@ try status = cmd_vms(instance_selection.operative_selection, operation); } - status_promise->set_value(status); + context->set_value(status); } catch (const mp::VMStateInvalidException& e) { - status_promise->set_value(grpc::Status{grpc::StatusCode::FAILED_PRECONDITION, e.what()}); + context->set_value(grpc::Status{grpc::StatusCode::FAILED_PRECONDITION, e.what()}); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what())); + context->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what())); } void mp::Daemon::suspend(const SuspendRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - auto [instance_selection, status] = select_instances_and_react(operative_instances, deleted_instances, @@ -2298,25 +2254,20 @@ try }); } - status_promise->set_value(status); + context->set_value(status); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::restart(const RestartRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - - auto timeout = - request->timeout() > 0 ? std::chrono::seconds(request->timeout()) : mp::default_timeout; + auto timeout = request->timeout() > 0 ? std::chrono::seconds(request->timeout()) + : mp::default_timeout; auto [instance_selection, status] = select_instances_and_react(operative_instances, @@ -2327,7 +2278,7 @@ try if (!status.ok()) { - return status_promise->set_value(status); + return context->set_value(status); } const auto& instance_targets = instance_selection.operative_selection; @@ -2339,7 +2290,7 @@ try if (!status.ok()) { - return status_promise->set_value(status); + return context->set_value(status); } auto future_watcher = create_future_watcher(); @@ -2349,24 +2300,20 @@ try server, names_from(instance_targets), timeout, - status_promise, + context, std::string(), std::string())); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::delet(const DeleteRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; DeleteReply response; auto [instance_selection, status] = @@ -2401,7 +2348,7 @@ try throw std::runtime_error("Cannot get confirmation from client. Aborting..."); if (!(purge_snapshots = client_response.purge_snapshots())) - return status_promise->set_value(grpc::Status{grpc::CANCELLED, "Cancelled."}); + return context->set_value(grpc::Status{grpc::CANCELLED, "Cancelled."}); } // start with deleted instances, to avoid iterator invalidation when moving instances there @@ -2422,8 +2369,8 @@ try auto snapshot_pick_it = instance_snapshots_map.find(instance_name); const auto& [pick, all] = snapshot_pick_it == instance_snapshots_map.end() - ? SnapshotPick{{}, true} - : snapshot_pick_it->second; + ? SnapshotPick{{}, true} + : snapshot_pick_it->second; if (!all || !purge) // if we're not purging the instance, we need to delete // specified snapshots @@ -2440,27 +2387,22 @@ try } server->Write(response); - status_promise->set_value(status); + context->set_value(status); } catch (const mp::VMStateInvalidException& e) { - status_promise->set_value(grpc::Status{grpc::StatusCode::FAILED_PRECONDITION, e.what()}); + context->set_value(grpc::Status{grpc::StatusCode::FAILED_PRECONDITION, e.what()}); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what())); + context->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what())); } void mp::Daemon::umount(const UmountRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - fmt::memory_buffer errors; for (const auto& path_entry : request->target_paths()) { @@ -2518,38 +2460,29 @@ try persist_instances(); - status_promise->set_value(grpc_status_for(errors)); + context->set_value(grpc_status_for(errors)); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::version(const VersionRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - VersionReply reply; reply.set_version(multipass::version_string); config->update_prompt->populate(reply.mutable_update_info()); server->Write(reply); - status_promise->set_value(grpc::Status::OK); + context->set_value(grpc::Status::OK); } void mp::Daemon::get(const GetRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - GetReply reply; auto key = request->key(); @@ -2558,26 +2491,22 @@ try reply.set_value(val); server->Write(reply); - status_promise->set_value(grpc::Status::OK); + context->set_value(grpc::Status::OK); } catch (const mp::UnrecognizedSettingException& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, e.what(), "")); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what(), "")); } void mp::Daemon::set(const SetRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - auto key = request->key(); auto val = request->val(); std::string bridge_name; @@ -2599,7 +2528,7 @@ try MP_SETTINGS.set(QString::fromStdString(key), QString::fromStdString(val)); mpl::debug(category, "Succeeded setting {}={}", key, val); - status_promise->set_value(grpc::Status::OK); + context->set_value(grpc::Status::OK); } catch (const mp::NonAuthorizedBridgeSettingsException& e) { @@ -2625,46 +2554,41 @@ catch (const mp::NonAuthorizedBridgeSettingsException& e) mpl::debug(category, "Succeeded setting {}={}", key, val); - status_promise->set_value(grpc::Status::OK); + context->set_value(grpc::Status::OK); } else { mpl::debug(category, "User did not authorize, cancelling"); - status_promise->set_value( - grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } } catch (const mp::BridgeFailureException& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, e.what(), "")); } catch (const mp::UnrecognizedSettingException& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, e.what(), "")); } catch (const mp::InstanceStateSettingsException& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } catch (const mp::InvalidSettingException& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, e.what(), "")); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what(), "")); } void mp::Daemon::keys(const mp::KeysRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - KeysReply reply; for (const auto& key : MP_SETTINGS.keys()) @@ -2673,29 +2597,24 @@ try mpl::debug(category, "Returning {} settings keys", reply.settings_keys_size()); server->Write(reply); - status_promise->set_value(grpc::Status::OK); + context->set_value(grpc::Status::OK); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what(), "")); } void mp::Daemon::authenticate( const AuthenticateRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - auto stored_hash = MP_SETTINGS.get(mp::passphrase_key); if (stored_hash.isNull() || stored_hash.isEmpty()) { - return status_promise->set_value(grpc::Status( + return context->set_value(grpc::Status( grpc::StatusCode::FAILED_PRECONDITION, "Incorrect passphrase. No passphrase is set.\n\n" "To authenticate, first ask an authenticated user to set a passphrase and share it " @@ -2708,28 +2627,22 @@ try if (stored_hash != hashed_passphrase) { - return status_promise->set_value( - grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, - "Passphrase is not correct. Please try again.")); + return context->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, + "Passphrase is not correct. Please try again.")); } - status_promise->set_value(grpc::Status::OK); + context->set_value(grpc::Status::OK); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what(), "")); } void mp::Daemon::snapshot(const mp::SnapshotRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - const auto& instance_name = request->instance(); auto [instance_trail, status] = find_instance_and_react(operative_instances, deleted_instances, @@ -2744,13 +2657,13 @@ try using St = VirtualMachine::State; if (auto state = vm_ptr->current_state(); state != St::off && state != St::stopped) - return status_promise->set_value( + return context->set_value( grpc::Status{grpc::FAILED_PRECONDITION, "Multipass can only take snapshots of stopped instances."}); auto snapshot_name = request->snapshot(); if (!snapshot_name.empty() && !mp::utils::valid_hostname(snapshot_name)) - return status_promise->set_value( + return context->set_value( grpc::Status{grpc::INVALID_ARGUMENT, fmt::format(R"(Invalid snapshot name: "{}".)", snapshot_name)}); @@ -2764,27 +2677,22 @@ try server->Write(reply); } - status_promise->set_value(status); + context->set_value(status); } catch (const SnapshotNameTakenException& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, e.what(), "")); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what(), "")); } void mp::Daemon::restore(const mp::RestoreRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - RestoreReply reply; const auto& instance_name = request->instance(); auto [instance_trail, status] = find_instance_and_react(operative_instances, @@ -2804,7 +2712,7 @@ try using St = VirtualMachine::State; if (auto state = vm_ptr->current_state(); state != St::off && state != St::stopped) - return status_promise->set_value( + return context->set_value( grpc::Status{grpc::FAILED_PRECONDITION, "Multipass can only restore snapshots of stopped instances."}); @@ -2853,26 +2761,22 @@ try server->Write(reply); } - status_promise->set_value(status); + context->set_value(status); } catch (const mp::NoSuchSnapshotException& e) { - status_promise->set_value(grpc::Status{grpc::StatusCode::NOT_FOUND, e.what(), ""}); + context->set_value(grpc::Status{grpc::StatusCode::NOT_FOUND, e.what(), ""}); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what(), "")); } void mp::Daemon::clone(const CloneRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - const auto& source_name = request->source_name(); const auto [src_instance_trail, src_vm_status] = find_instance_and_react(operative_instances, @@ -2888,14 +2792,13 @@ try if (source_vm_state != VirtualMachine::State::stopped && source_vm_state != VirtualMachine::State::off) { - return status_promise->set_value( - grpc::Status{grpc::FAILED_PRECONDITION, - "Multipass can only clone stopped instances."}); + return context->set_value(grpc::Status{grpc::FAILED_PRECONDITION, + "Multipass can only clone stopped instances."}); } const std::string destination_name = dest_name_for_clone(*request); if (auto dest_vm_status = validate_dest_name(destination_name); !dest_vm_status.ok()) - return status_promise->set_value(std::move(dest_vm_status)); + return context->set_value(std::move(dest_vm_status)); auto rollback_resources = sg::make_scope_guard([this, destination_name]() noexcept -> void { top_catch_all(category, [this, destination_name]() { @@ -2937,24 +2840,19 @@ try server->Write(rpc_response); rollback_resources.dismiss(); } - status_promise->set_value(src_vm_status); + context->set_value(src_vm_status); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what())); + context->set_value(grpc::Status(grpc::StatusCode::INTERNAL, e.what())); } void mp::Daemon::daemon_info( const DaemonInfoRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - DaemonInfoReply response; QStorageInfo storage_info{config->data_directory}; @@ -2964,27 +2862,22 @@ try response.set_memory(MP_PLATFORM.get_total_ram()); server->Write(response); - status_promise->set_value(grpc::Status{}); + context->set_value(grpc::Status{}); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::wait_ready( const WaitReadyRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) + DaemonRpcContext* context) try { WaitReadyReply response; - mpl::ClientLogger logger{ - mpl::level_from(request->verbosity_level()), - *config->logger, - server}; - - logger.log(mpl::Level::debug, "daemon", "Checking connection to image servers..."); + mpl::debug("daemon", "Checking connection to image servers..."); // We use wait_update_manifests_all_and_optionally_applied_force to check connectivity to image // servers. @@ -2992,32 +2885,28 @@ try { wait_update_manifests_all_and_optionally_applied_force( /*force_manifest_network_download=*/false); - logger.log(mpl::Level::debug, "daemon", "Successfully connected to image servers."); - status_promise->set_value(grpc::Status::OK); + mpl::debug("daemon", "Successfully connected to image servers."); + context->set_value(grpc::Status::OK); } catch (const mp::DownloadException& e) { - logger.log(mpl::Level::warning, - "daemon", - fmt::format("Failed to connect to image servers: {}", e.what())); + mpl::warn("daemon", "Failed to connect to image servers: {}", e.what()); grpc::Status download_error_status{grpc::StatusCode::NOT_FOUND, "cannot connect to the image servers", ""}; - status_promise->set_value(download_error_status); + context->set_value(download_error_status); } } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::zones(const ZonesRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) // clang-format off + DaemonRpcContext* context) // clang-format off try // clang-format on { - mpl::ClientLogger logger{mpl::level_from(request->verbosity_level()), *config->logger, server}; - ZonesReply response{}; for (const auto& zone : config->az_manager->get_zones()) @@ -3028,21 +2917,19 @@ try // clang-format on } server->Write(response); - status_promise->set_value(grpc::Status{}); + context->set_value(grpc::Status{}); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::zones_state( const ZonesStateRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise) // clang-format off + DaemonRpcContext* context) // clang-format off try // clang-format on { - mpl::ClientLogger logger{mpl::level_from(request->verbosity_level()), *config->logger, server}; - auto& az_manager = *config->az_manager; if (request->zones().empty()) { @@ -3059,15 +2946,15 @@ try // clang-format on } } - status_promise->set_value(grpc::Status{}); + context->set_value(grpc::Status{}); } catch (const AvailabilityZoneNotFound& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, e.what(), "")); } catch (const std::exception& e) { - status_promise->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); + context->set_value(grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } void mp::Daemon::on_shutdown() @@ -3155,17 +3042,16 @@ void mp::Daemon::release_resources(const std::string& instance) void mp::Daemon::create_vm(const CreateRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise, + DaemonRpcContext* context, bool start) { auto checked_args = validate_create_arguments(request, config.get()); if (!checked_args.option_errors.error_codes().empty()) { - return status_promise->set_value( - grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, - "Invalid arguments supplied", - checked_args.option_errors.SerializeAsString())); + return context->set_value(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, + "Invalid arguments supplied", + checked_args.option_errors.SerializeAsString())); } else if (auto& nets = checked_args.nets_need_bridging; !nets.empty() && !request->permission_to_bridge()) @@ -3180,9 +3066,9 @@ void mp::Daemon::create_vm(const CreateRequest* request, RepeatedPtrField from the range, then move-assigns that temporary in */ server->Write(reply); - return status_promise->set_value(grpc::Status{grpc::StatusCode::FAILED_PRECONDITION, - "Missing bridges", - create_error.SerializeAsString()}); + return context->set_value(grpc::Status{grpc::StatusCode::FAILED_PRECONDITION, + "Missing bridges", + create_error.SerializeAsString()}); } auto name = name_from(checked_args.instance_name, *config->name_generator, operative_instances); @@ -3197,12 +3083,12 @@ void mp::Daemon::create_vm(const CreateRequest* request, assert(status.ok() == (instance_trail.index() == 2)); if (!status.ok()) - return status_promise->set_value(status); + return context->set_value(status); if (preparing_instances.find(name) != preparing_instances.end()) - return status_promise->set_value({grpc::StatusCode::INVALID_ARGUMENT, - fmt::format("instance \"{}\" is being prepared", name), - ""}); + return context->set_value({grpc::StatusCode::INVALID_ARGUMENT, + fmt::format("instance \"{}\" is being prepared", name), + ""}); if (!instances_running(operative_instances)) config->factory->hypervisor_health_check(); @@ -3217,7 +3103,7 @@ void mp::Daemon::create_vm(const CreateRequest* request, QObject::connect( prepare_future_watcher, &QFutureWatcher::finished, - [this, server, status_promise, name, timeout, start, prepare_future_watcher, log_level] { + [this, server, context, name, timeout, start, prepare_future_watcher, log_level] { mpl::ClientLogger logger{log_level, *config->logger, server}; @@ -3272,13 +3158,13 @@ void mp::Daemon::create_vm(const CreateRequest* request, server, std::vector{name}, timeout, - status_promise, + context, std::string(), std::string())); } else { - status_promise->set_value(grpc::Status::OK); + context->set_value(grpc::Status::OK); } } catch (const std::exception& e) @@ -3290,7 +3176,7 @@ void mp::Daemon::create_vm(const CreateRequest* request, persist_instances(); }); - status_promise->set_value( + context->set_value( grpc::Status(grpc::StatusCode::FAILED_PRECONDITION, e.what(), "")); } @@ -3627,11 +3513,11 @@ mp::MountHandler::UPtr mp::Daemon::make_mount(VirtualMachine* vm, const VMMount& mount) { return mount.get_mount_type() == VMMount::MountType::Classic - ? std::make_unique(vm, - config->ssh_key_provider.get(), - target, - mount) - : vm->make_native_mount_handler(target, mount); + ? std::make_unique(vm, + config->ssh_key_provider.get(), + target, + mount) + : vm->make_native_mount_handler(target, mount); } QFutureWatcher* mp::Daemon::create_future_watcher( @@ -3743,7 +3629,7 @@ mp::Daemon::AsyncOperationStatus mp::Daemon::async_wait_for_ready_all(grpc::ServerReaderWriterInterface* server, const std::vector& vms, const std::chrono::seconds& timeout, - std::promise* status_promise, + DaemonRpcContext* context, const std::string& start_errors, const std::string& start_warnings) { @@ -3808,7 +3694,7 @@ mp::Daemon::async_wait_for_ready_all(grpc::ServerReaderWriterInterfaceset_value(async_op_result.status); + if (async_op_result.context) + async_op_result.context->set_value(async_op_result.status); } void mp::Daemon::update_manifests_all(const bool force_update) @@ -3936,9 +3822,9 @@ void mp::Daemon::populate_instance_info(VirtualMachine& vm, std::string mp::Daemon::dest_name_for_clone(const CloneRequest& request) { return request.has_destination_name() - ? request.destination_name() - : generate_next_clone_name(vm_instance_specs.at(request.source_name()).clone_count, - request.source_name()); + ? request.destination_name() + : generate_next_clone_name(vm_instance_specs.at(request.source_name()).clone_count, + request.source_name()); }; grpc::Status mp::Daemon::validate_dest_name(const std::string& name) diff --git a/src/daemon/daemon.h b/src/daemon/daemon.h index 2929cbda33..ef722ad4e3 100644 --- a/src/daemon/daemon.h +++ b/src/daemon/daemon.h @@ -41,6 +41,7 @@ namespace multipass { struct DaemonConfig; +struct DaemonRpcContext; class SettingsHandler; class Daemon : public QObject, public multipass::VMStatusMonitor @@ -68,122 +69,124 @@ public slots: virtual void create(const CreateRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void launch(const LaunchRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void purge(const PurgeRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void find(const FindRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void info(const InfoRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void list(const ListRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void networks(const NetworksRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void mount(const MountRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void recover(const RecoverRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void ssh_info(const SSHInfoRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void start(const StartRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void stop(const StopRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void suspend(const SuspendRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void restart(const RestartRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void delet(const DeleteRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void umount(const UmountRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void version(const VersionRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void get(const GetRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void set(const SetRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void keys(const KeysRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void authenticate( const AuthenticateRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void clone(const CloneRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void snapshot(const SnapshotRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void restore(const RestoreRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void daemon_info( const DaemonInfoRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); + virtual void zones(const ZonesRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); + virtual void zones_state( const ZonesStateRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); virtual void wait_ready( const WaitReadyRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise); + DaemonRpcContext* context); private: void release_resources(const std::string& instance); void create_vm(const CreateRequest* request, grpc::ServerReaderWriterInterface* server, - std::promise* status_promise, + DaemonRpcContext* context, bool start); bool delete_vm(InstanceTable::iterator vm_it, bool purge, DeleteReply& response); grpc::Status reboot_vm(VirtualMachine& vm); @@ -212,7 +215,7 @@ public slots: struct AsyncOperationStatus { grpc::Status status; - std::promise* status_promise; + DaemonRpcContext* context; }; // These async_* methods need to operate on instance names and look up the VMs again, lest they @@ -227,7 +230,7 @@ public slots: async_wait_for_ready_all(grpc::ServerReaderWriterInterface* server, const std::vector& vms, const std::chrono::seconds& timeout, - std::promise* status_promise, + DaemonRpcContext* context, const std::string& errors, const std::string& start_warnings); void finish_async_operation(const std::string& async_future_key); diff --git a/src/daemon/daemon_rpc.cpp b/src/daemon/daemon_rpc.cpp index 90a6f4fd10..87a503d014 100644 --- a/src/daemon/daemon_rpc.cpp +++ b/src/daemon/daemon_rpc.cpp @@ -17,6 +17,7 @@ #include "daemon_rpc.h" +#include #include #include #include @@ -66,8 +67,8 @@ auto make_server(const std::string& server_address, if (server == nullptr) { auto detail = check_is_server_running(server_address) - ? " A multipass daemon is already running there." - : ""; + ? " A multipass daemon is already running there." + : ""; throw std::runtime_error( fmt::format("Failed to start multipass gRPC service at {}.{}", server_address, detail)); } @@ -85,14 +86,29 @@ auto server_socket_type_for(const std::string& server_address) return mp::ServerSocketType::tcp; } -template -grpc::Status emit_signal_and_wait_for_result(OperationSignal operation_signal) +template +concept HasVerbosityLevel = requires(T t) { t.verbosity_level(); }; + +template +grpc::Status emit_signal_and_wait_for_result(OperationSignal operation_signal, + grpc::ServerReaderWriterInterface* server, + U* request, + mpl::MultiplexingLogger& mpx) { - std::promise status_promise; - auto status_future = status_promise.get_future(); - emit operation_signal(&status_promise); + auto level = [&request]() { + if constexpr (HasVerbosityLevel) + return mpl::level_from(request->verbosity_level()); + else + return mpl::Level::info; + }(); - return status_future.get(); + std::promise promise; + auto future = promise.get_future(); + multipass::DaemonRpcContextImpl ctx{promise, server, level, mpx}; + emit operation_signal(request, + static_cast*>(server), + static_cast(&ctx)); + return future.get(); } std::string client_cert_from(grpc::ServerContext* context) @@ -133,11 +149,13 @@ void accept_cert(mp::CertStore* client_cert_store, mp::DaemonRpc::DaemonRpc(const std::string& server_address, const CertProvider& cert_provider, - CertStore* client_cert_store) + CertStore* client_cert_store, + std::shared_ptr logger) : server_address{server_address}, server{make_server(server_address, cert_provider, this)}, server_socket_type{server_socket_type_for(server_address)}, - client_cert_store{client_cert_store} + client_cert_store{client_cert_store}, + logger(logger) { handle_socket_restrictions(server_address, client_cert_store->empty()); @@ -153,202 +171,218 @@ void mp::DaemonRpc::shutdown_and_wait() grpc::Status mp::DaemonRpc::create(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - CreateRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_create, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_create, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::launch(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - LaunchRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_launch, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_launch, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::purge(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - PurgeRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_purge, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_purge, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::find(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - FindRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_find, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_find, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::info(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - InfoRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_info, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_info, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::list(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - ListRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_list, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_list, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::clone(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - CloneRequest request; - server->Read(&request); - - auto adapted_on_clone = [this, &request, server](auto&& arg) -> void { - this->on_clone(&request, server, std::forward(arg)); - }; - - return verify_client_and_dispatch_operation(adapted_on_clone, client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_clone, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::networks( grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - NetworksRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_networks, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_networks, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::mount(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - MountRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_mount, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_mount, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::recover(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - RecoverRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_recover, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_recover, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::ssh_info(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - SSHInfoRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_ssh_info, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_ssh_info, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::start(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - StartRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_start, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_start, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::stop(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - StopRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_stop, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_stop, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::suspend(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - SuspendRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_suspend, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_suspend, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::restart(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - RestartRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_restart, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_restart, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::delet(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - DeleteRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_delete, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_delete, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::umount(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - UmountRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_umount, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_umount, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::version(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - VersionRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_version, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_version, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::ping(grpc::ServerContext* context, @@ -368,12 +402,13 @@ grpc::Status mp::DaemonRpc::ping(grpc::ServerContext* context, grpc::Status mp::DaemonRpc::get(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - GetRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_get, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_get, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::authenticate( @@ -383,8 +418,14 @@ grpc::Status mp::DaemonRpc::authenticate( AuthenticateRequest request; server->Read(&request); - auto status = emit_signal_and_wait_for_result( - std::bind(&DaemonRpc::on_authenticate, this, &request, server, std::placeholders::_1)); + auto status = emit_signal_and_wait_for_result(std::bind(&DaemonRpc::on_authenticate, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + server, + &request, + *logger); if (status.ok()) { @@ -404,99 +445,111 @@ grpc::Status mp::DaemonRpc::authenticate( grpc::Status mp::DaemonRpc::set(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - SetRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_set, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_set, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::keys(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - KeysRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_keys, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_keys, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::snapshot( grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - SnapshotRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_snapshot, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_snapshot, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::restore(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - RestoreRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_restore, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_restore, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::daemon_info( grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - DaemonInfoRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_daemon_info, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_daemon_info, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::wait_ready( grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - WaitReadyRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_wait_ready, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_wait_ready, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::zones(grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - ZonesRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_zones, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_zones, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } grpc::Status mp::DaemonRpc::zones_state( grpc::ServerContext* context, grpc::ServerReaderWriter* server) { - ZonesStateRequest request; - server->Read(&request); - - return verify_client_and_dispatch_operation( - std::bind(&DaemonRpc::on_zones_state, this, &request, server, std::placeholders::_1), - client_cert_from(context)); + return verify_client_and_dispatch_operation(std::bind(&DaemonRpc::on_zones_state, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3), + client_cert_from(context), + server); } -template -grpc::Status mp::DaemonRpc::verify_client_and_dispatch_operation(OperationSignal signal, - const std::string& client_cert) +template +grpc::Status +mp::DaemonRpc::verify_client_and_dispatch_operation(OperationSignal signal, + const std::string& client_cert, + grpc::ServerReaderWriterInterface* server) { + U request{}; + server->Read(&request); if (server_socket_type == mp::ServerSocketType::unix && client_cert_store->empty()) { try @@ -518,5 +571,5 @@ grpc::Status mp::DaemonRpc::verify_client_and_dispatch_operation(OperationSignal "(e.g. via 'multipass set local.passphrase')."}; } - return emit_signal_and_wait_for_result(signal); + return emit_signal_and_wait_for_result(signal, server, &request, *logger); } diff --git a/src/daemon/daemon_rpc.h b/src/daemon/daemon_rpc.h index 4764d45b5e..1d1e723050 100644 --- a/src/daemon/daemon_rpc.h +++ b/src/daemon/daemon_rpc.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,9 @@ namespace multipass { + +struct DaemonRpcContext; + using CreateRequest = LaunchRequest; using CreateReply = LaunchReply; using CreateError = LaunchError; @@ -52,105 +56,109 @@ class DaemonRpc : public QObject, public multipass::Rpc::Service, private Disabl public: DaemonRpc(const std::string& server_address, const CertProvider& cert_provider, - CertStore* client_cert_store); + CertStore* client_cert_store, + std::shared_ptr logger); void shutdown_and_wait(); signals: void on_create(const CreateRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_launch(const LaunchRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_purge(const PurgeRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_find(const FindRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_info(const InfoRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_list(const ListRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_clone(const CloneRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_networks(const NetworksRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_mount(const MountRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_recover(const RecoverRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_ssh_info(const SSHInfoRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_start(const StartRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_stop(const StopRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_suspend(const SuspendRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_restart(const RestartRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_delete(const DeleteRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_umount(const UmountRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_version(const VersionRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_get(const GetRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_set(const SetRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_keys(const KeysRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_authenticate(const AuthenticateRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_snapshot(const SnapshotRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_restore(const RestoreRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_daemon_info(const DaemonInfoRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_wait_ready(const WaitReadyRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_zones(const ZonesRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); void on_zones_state(const ZonesStateRequest* request, grpc::ServerReaderWriter* server, - std::promise* status_promise); + DaemonRpcContext* context); private: - template - grpc::Status verify_client_and_dispatch_operation(OperationSignal signal, - const std::string& client_cert); + template + grpc::Status + verify_client_and_dispatch_operation(OperationSignal signal, + const std::string& client_cert, + grpc::ServerReaderWriterInterface* server); const std::string server_address; const std::unique_ptr server; const ServerSocketType server_socket_type; CertStore* client_cert_store; + std::shared_ptr logger; protected: grpc::Status create(grpc::ServerContext* context, diff --git a/tests/unit/daemon_test_fixture.cpp b/tests/unit/daemon_test_fixture.cpp index f393d63c3d..b5a969bcb4 100644 --- a/tests/unit/daemon_test_fixture.cpp +++ b/tests/unit/daemon_test_fixture.cpp @@ -21,6 +21,7 @@ #include "common.h" #include "file_operations.h" #include "mock_cert_provider.h" +#include "mock_daemon_rpc_context.h" #include "mock_server_reader_writer.h" #include "mock_standard_paths.h" #include "stub_availability_zone_manager.h" @@ -39,6 +40,7 @@ #include #include #include +#include #include @@ -575,9 +577,14 @@ grpc::Status mpt::DaemonTestFixture::call_daemon_slot(Daemon& daemon, std::promise status_promise; auto status_future = status_promise.get_future(); - auto thread = QThread::create([&daemon, slot, &request, &server, &status_promise] { + NiceMock ctx; + ON_CALL(ctx, set_value).WillByDefault([&status_promise](grpc::Status status) { + status_promise.set_value(std::move(status)); + }); + + auto thread = QThread::create([&daemon, slot, &request, &server, &ctx] { QEventLoop inner_loop; - (daemon.*slot)(&request, &server, &status_promise); + (daemon.*slot)(&request, &server, &ctx); inner_loop.exec(); }); QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater); @@ -600,182 +607,182 @@ template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( void (mp::Daemon::*)( const mp::AuthenticateRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), const mp::AuthenticateRequest&, StrictMock>&&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(mp::VersionRequest const*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), mp::VersionRequest const&, StrictMock>&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(const mp::ListRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), mp::ListRequest const&, StrictMock>&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(mp::KeysRequest const*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), mp::KeysRequest const&, StrictMock>&&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(mp::KeysRequest const*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), mp::KeysRequest const&, StrictMock>&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(mp::GetRequest const*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), mp::GetRequest const&, StrictMock>&&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(mp::GetRequest const*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), mp::GetRequest const&, StrictMock>&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(mp::SetRequest const*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), mp::SetRequest const&, StrictMock>&&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(mp::SetRequest const*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), mp::SetRequest const&, StrictMock>&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(mp::NetworksRequest const*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), mp::NetworksRequest const&, StrictMock>&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(mp::NetworksRequest const*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), mp::NetworksRequest const&, NiceMock>&&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(mp::PurgeRequest const*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), mp::PurgeRequest const&, NiceMock>&&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(const mp::MountRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), const mp::MountRequest&, StrictMock>&&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(const mp::UmountRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), const mp::UmountRequest&, StrictMock>&&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(mp::LaunchRequest const*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), mp::LaunchRequest const&, StrictMock>&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(const mp::StartRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), const mp::StartRequest&, StrictMock>&&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(const mp::RestartRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), const mp::RestartRequest&, StrictMock>&&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(const mp::InfoRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), const mp::InfoRequest&, StrictMock>&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(const mp::SuspendRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), const mp::SuspendRequest&, StrictMock>&&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(const mp::SnapshotRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), const mp::SnapshotRequest&, StrictMock>&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(const mp::SnapshotRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), const mp::SnapshotRequest&, testing::StrictMock>&&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(const mp::RestoreRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), const mp::RestoreRequest&, testing::StrictMock>&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(const mp::RestoreRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), const mp::RestoreRequest&, StrictMock>&&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(const mp::CloneRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), const mp::CloneRequest&, NiceMock>&); template grpc::Status mpt::DaemonTestFixture::call_daemon_slot( mp::Daemon&, void (mp::Daemon::*)(const mp::CloneRequest*, grpc::ServerReaderWriterInterface*, - std::promise*), + mp::DaemonRpcContext*), const mp::CloneRequest&, NiceMock>&&); template using DaemonSlotPtr = void (mp::Daemon::*)(const Request*, grpc::ServerReaderWriterInterface*, - std::promise*); + mp::DaemonRpcContext*); template