blob: 17ea45693d97d606f88229392b2bea9d3b1b2800 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_VIRTUALIZATION_BIN_TERMINA_GUEST_MANAGER_GUEST_H_
#define SRC_VIRTUALIZATION_BIN_TERMINA_GUEST_MANAGER_GUEST_H_
#include <fuchsia/virtualization/cpp/fidl.h>
#include <lib/async/cpp/executor.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/trace/event.h>
#include <zircon/types.h>
#include <deque>
#include <memory>
#include "src/virtualization/bin/guest_manager/guest_manager.h"
#include "src/virtualization/bin/termina_guest_manager/crash_listener.h"
#include "src/virtualization/bin/termina_guest_manager/log_collector.h"
#include "src/virtualization/bin/termina_guest_manager/termina_config.h"
#include "src/virtualization/lib/grpc/grpc_vsock_server.h"
#include "src/virtualization/third_party/vm_tools/container_guest.grpc.pb.h"
#include "src/virtualization/third_party/vm_tools/container_host.grpc.pb.h"
#include "src/virtualization/third_party/vm_tools/tremplin.grpc.pb.h"
#include "src/virtualization/third_party/vm_tools/vm_guest.grpc.pb.h"
#include <grpc++/grpc++.h>
namespace termina_guest_manager {
struct GuestInfo {
uint32_t cid;
fuchsia::virtualization::ContainerStatus container_status;
int32_t download_percent;
std::string failure_reason;
};
using GuestInfoCallback = fit::function<void(GuestInfo)>;
using GetGuestNetworkState = fit::function<GuestNetworkState()>;
class Guest : public vm_tools::StartupListener::Service,
public vm_tools::tremplin::TremplinListener::Service,
public vm_tools::container::ContainerListener::Service {
public:
Guest(const termina_config::Config& config, GuestInfoCallback callback,
GetGuestNetworkState get_network_state);
~Guest();
// Retry the container startup workflow.
//
// Creating the container can fail under expected situations (ex: no network connectivity) so
// we provide a way to retry that workflow.
//
// This must only be used in response to a previous failure to start the container, which is
// indicated by a ContainerStatus::FAILED message sent to the GuestInfoCallback.
void RetryContainerStartup() {
if (tremplin_) {
CreateContainer();
}
}
void OnGuestLaunched(fuchsia::virtualization::GuestManager& guest_manager,
fuchsia::virtualization::Guest& guest);
// Send a shutdown RPC to the guest VM.
void InitiateGuestShutdown();
std::vector<fuchsia::virtualization::Listener> take_vsock_listeners() {
FX_CHECK(vsock_listeners_);
std::optional<std::vector<fuchsia::virtualization::Listener>> result = std::nullopt;
vsock_listeners_.swap(result);
return std::move(*result);
}
private:
zx::result<> StartGrpcServer();
void StartGuest(fuchsia::virtualization::GuestManager& guest_manager);
void MountFilesystems();
void MountReadOnlyFilesystem(const std::string& source, const std::string& target,
const std::string& fstype);
void ConfigureNetwork();
void StartTermina();
void LaunchContainerShell();
void AddMagmaDeviceToContainer();
void SetupGPUDriversInContainer();
void StartLxd();
void CreateContainer();
void StartContainer();
void SetupUser();
void DumpContainerDebugInfo();
// |vm_tools::StartupListener::Service|
grpc::Status VmReady(grpc::ServerContext* context, const vm_tools::EmptyMessage* request,
vm_tools::EmptyMessage* response) override;
// |vm_tools::tremplin::TremplinListener::Service|
grpc::Status TremplinReady(grpc::ServerContext* context,
const ::vm_tools::tremplin::TremplinStartupInfo* request,
vm_tools::tremplin::EmptyMessage* response) override;
grpc::Status UpdateStartLxdStatus(grpc::ServerContext* context,
const ::vm_tools::tremplin::StartLxdProgress* request,
vm_tools::tremplin::EmptyMessage* response) override;
grpc::Status UpdateCreateStatus(grpc::ServerContext* context,
const vm_tools::tremplin::ContainerCreationProgress* request,
vm_tools::tremplin::EmptyMessage* response) override;
grpc::Status UpdateDeletionStatus(::grpc::ServerContext* context,
const ::vm_tools::tremplin::ContainerDeletionProgress* request,
::vm_tools::tremplin::EmptyMessage* response) override;
grpc::Status UpdateStartStatus(::grpc::ServerContext* context,
const ::vm_tools::tremplin::ContainerStartProgress* request,
::vm_tools::tremplin::EmptyMessage* response) override;
grpc::Status UpdateExportStatus(::grpc::ServerContext* context,
const ::vm_tools::tremplin::ContainerExportProgress* request,
::vm_tools::tremplin::EmptyMessage* response) override;
grpc::Status UpdateImportStatus(::grpc::ServerContext* context,
const ::vm_tools::tremplin::ContainerImportProgress* request,
::vm_tools::tremplin::EmptyMessage* response) override;
grpc::Status ContainerShutdown(::grpc::ServerContext* context,
const ::vm_tools::tremplin::ContainerShutdownInfo* request,
::vm_tools::tremplin::EmptyMessage* response) override;
// |vm_tools::container::ContainerListener::Service|
grpc::Status ContainerReady(grpc::ServerContext* context,
const vm_tools::container::ContainerStartupInfo* request,
vm_tools::EmptyMessage* response) override;
grpc::Status ContainerShutdown(grpc::ServerContext* context,
const vm_tools::container::ContainerShutdownInfo* request,
vm_tools::EmptyMessage* response) override;
grpc::Status UpdateApplicationList(
grpc::ServerContext* context,
const vm_tools::container::UpdateApplicationListRequest* request,
vm_tools::EmptyMessage* response) override;
grpc::Status OpenUrl(grpc::ServerContext* context,
const vm_tools::container::OpenUrlRequest* request,
vm_tools::EmptyMessage* response) override;
grpc::Status InstallLinuxPackageProgress(
grpc::ServerContext* context,
const vm_tools::container::InstallLinuxPackageProgressInfo* request,
vm_tools::EmptyMessage* response) override;
grpc::Status UninstallPackageProgress(
grpc::ServerContext* context,
const vm_tools::container::UninstallPackageProgressInfo* request,
vm_tools::EmptyMessage* response) override;
grpc::Status OpenTerminal(grpc::ServerContext* context,
const vm_tools::container::OpenTerminalRequest* request,
vm_tools::EmptyMessage* response) override;
grpc::Status UpdateMimeTypes(grpc::ServerContext* context,
const vm_tools::container::UpdateMimeTypesRequest* request,
vm_tools::EmptyMessage* response) override;
void PostContainerStatus(fuchsia::virtualization::ContainerStatus container_status);
void PostContainerDownloadProgress(int32_t download_progress);
void PostContainerFailure(std::string failure_reason);
void PostContainerFailureWithNetworkStatus(std::string failure_reason);
async::Executor executor_;
GuestInfoCallback callback_;
termina_config::Config structured_config_;
std::unique_ptr<GrpcVsockServer> grpc_server_;
fuchsia::virtualization::HostVsockEndpointPtr socket_endpoint_;
uint32_t guest_cid_ = fuchsia::virtualization::DEFAULT_GUEST_CID;
std::unique_ptr<vm_tools::Maitred::Stub> maitred_;
std::unique_ptr<vm_tools::tremplin::Tremplin::Stub> tremplin_;
std::unique_ptr<vm_tools::container::Garcon::Stub> garcon_;
CrashListener crash_listener_;
LogCollector log_collector_;
std::optional<std::vector<::fuchsia::virtualization::Listener>> vsock_listeners_;
// A flow ID used to track the time from the time the VM is created until
// the time the guest has reported itself as ready via the VmReady RPC in the
// vm_tools::StartupListener::Service.
const trace_async_id_t vm_ready_nonce_ = TRACE_NONCE();
// Set to true if a shutdown was attempted before a maitre'd connection was established.
bool must_send_shutdown_rpc_ = false;
// Queries the suspected guest network status. Can be used to generate better error messages.
GetGuestNetworkState get_network_state_;
};
} // namespace termina_guest_manager
#endif // SRC_VIRTUALIZATION_BIN_TERMINA_GUEST_MANAGER_GUEST_H_