blob: 76e5384a00a7dca528ec49984a68b44638c6ee54 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "vm_tools/cicerone/container.h"
#include <arpa/inet.h>
#include <algorithm>
#include <memory>
#include <utility>
#include <base/bind.h>
#include <base/guid.h>
#include <base/logging.h>
#include <base/memory/ptr_util.h>
#include <base/strings/stringprintf.h>
#include <google/protobuf/repeated_field.h>
#include <grpc++/grpc++.h>
#include "container_guest.grpc.pb.h" // NOLINT(build/include)
#include "vm_tools/common/constants.h"
using std::string;
namespace vm_tools {
namespace cicerone {
namespace {
// How long to wait before timing out on regular RPCs.
constexpr int64_t kDefaultTimeoutSeconds = 2;
// How long to wait before timing out on a package info call which may take
// longer due to PackageKit startup time on slower boards.
constexpr int64_t kPackageInfoTimeoutSeconds = 10;
} // namespace
Container::Container(const std::string& name,
const std::string& token,
base::WeakPtr<VirtualMachine> vm)
: name_(name), token_(token), vm_(vm) {}
// Sets the container's IPv4 address.
void Container::set_ipv4_address(uint32_t ipv4_address) {
ipv4_address_ = ipv4_address;
}
void Container::ConnectToGarcon(const std::string& addr) {
garcon_channel_ =
grpc::CreateChannel(addr, grpc::InsecureChannelCredentials());
garcon_stub_ =
std::make_unique<vm_tools::container::Garcon::Stub>(garcon_channel_);
}
bool Container::LaunchContainerApplication(
const std::string& desktop_file_id,
std::vector<std::string> files,
vm_tools::container::LaunchApplicationRequest::DisplayScaling
display_scaling,
std::string* out_error) {
CHECK(out_error);
vm_tools::container::LaunchApplicationRequest container_request;
vm_tools::container::LaunchApplicationResponse container_response;
container_request.set_desktop_file_id(desktop_file_id);
std::copy(std::make_move_iterator(files.begin()),
std::make_move_iterator(files.end()),
google::protobuf::RepeatedFieldBackInserter(
container_request.mutable_files()));
container_request.set_display_scaling(display_scaling);
grpc::ClientContext ctx;
ctx.set_deadline(gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_seconds(kDefaultTimeoutSeconds, GPR_TIMESPAN)));
grpc::Status status = garcon_stub_->LaunchApplication(&ctx, container_request,
&container_response);
if (!status.ok()) {
LOG(ERROR) << "Failed to launch application " << desktop_file_id
<< " in container " << name_ << ": " << status.error_message();
out_error->assign("gRPC failure launching application: " +
status.error_message());
return false;
}
out_error->assign(container_response.failure_reason());
return container_response.success();
}
bool Container::LaunchVshd(uint32_t port, std::string* out_error) {
vm_tools::container::LaunchVshdRequest container_request;
vm_tools::container::LaunchVshdResponse container_response;
container_request.set_port(port);
grpc::ClientContext ctx;
ctx.set_deadline(gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_seconds(kDefaultTimeoutSeconds, GPR_TIMESPAN)));
grpc::Status status =
garcon_stub_->LaunchVshd(&ctx, container_request, &container_response);
if (!status.ok()) {
LOG(ERROR) << "Failed to launch vshd in container " << name_ << ": "
<< status.error_message() << " code: " << status.error_code();
out_error->assign("gRPC failure launching vshd in container: " +
status.error_message());
return false;
}
out_error->assign(container_response.failure_reason());
return container_response.success();
}
bool Container::GetDebugInformation(std::string* out) {
vm_tools::container::GetDebugInformationRequest container_request;
vm_tools::container::GetDebugInformationResponse container_response;
grpc::ClientContext ctx;
ctx.set_deadline(gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_seconds(kDefaultTimeoutSeconds, GPR_TIMESPAN)));
grpc::Status status = garcon_stub_->GetDebugInformation(
&ctx, container_request, &container_response);
if (!status.ok()) {
LOG(ERROR) << "Failed to get debug information in container " << name_
<< ": " << status.error_message()
<< " code: " << status.error_code();
out->assign("gRPC failure to get debug information in container: " +
status.error_message());
return false;
}
out->assign(container_response.debug_information());
return true;
}
bool Container::GetContainerAppIcon(std::vector<std::string> desktop_file_ids,
uint32_t icon_size,
uint32_t scale,
std::vector<Icon>* icons) {
CHECK(icons);
vm_tools::container::IconRequest container_request;
vm_tools::container::IconResponse container_response;
std::copy(std::make_move_iterator(desktop_file_ids.begin()),
std::make_move_iterator(desktop_file_ids.end()),
google::protobuf::RepeatedFieldBackInserter(
container_request.mutable_desktop_file_ids()));
container_request.set_icon_size(icon_size);
container_request.set_scale(scale);
grpc::ClientContext ctx;
ctx.set_deadline(gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_seconds(kDefaultTimeoutSeconds, GPR_TIMESPAN)));
grpc::Status status =
garcon_stub_->GetIcon(&ctx, container_request, &container_response);
if (!status.ok()) {
LOG(ERROR) << "Failed to get icons in container " << name_ << ": "
<< status.error_message();
return false;
}
for (auto& icon : *container_response.mutable_desktop_icons()) {
icons->emplace_back(
Icon{.desktop_file_id = std::move(*icon.mutable_desktop_file_id()),
.content = std::move(*icon.mutable_icon())});
}
return true;
}
bool Container::GetLinuxPackageInfo(const std::string& file_path,
LinuxPackageInfo* out_pkg_info,
std::string* out_error) {
CHECK(out_pkg_info);
vm_tools::container::LinuxPackageInfoRequest container_request;
vm_tools::container::LinuxPackageInfoResponse container_response;
container_request.set_file_path(file_path);
grpc::ClientContext ctx;
ctx.set_deadline(gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_seconds(kPackageInfoTimeoutSeconds, GPR_TIMESPAN)));
grpc::Status status = garcon_stub_->GetLinuxPackageInfo(
&ctx, container_request, &container_response);
if (!status.ok()) {
LOG(ERROR) << "Failed to get Linux package info from container " << name_
<< ": " << status.error_message()
<< " code: " << status.error_code();
out_error->assign(
"gRPC failure getting Linux package info from container: " +
status.error_message());
return false;
}
out_error->assign(container_response.failure_reason());
out_pkg_info->package_id = std::move(container_response.package_id());
out_pkg_info->license = std::move(container_response.license());
out_pkg_info->description = std::move(container_response.description());
out_pkg_info->project_url = std::move(container_response.project_url());
out_pkg_info->size = container_response.size();
out_pkg_info->summary = std::move(container_response.summary());
return container_response.success();
}
int Container::InstallLinuxPackage(const std::string& file_path,
std::string* out_error) {
vm_tools::container::InstallLinuxPackageRequest container_request;
vm_tools::container::InstallLinuxPackageResponse container_response;
container_request.set_file_path(file_path);
grpc::ClientContext ctx;
ctx.set_deadline(gpr_time_add(
gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_seconds(kDefaultTimeoutSeconds, GPR_TIMESPAN)));
grpc::Status status = garcon_stub_->InstallLinuxPackage(
&ctx, container_request, &container_response);
if (!status.ok()) {
LOG(ERROR) << "Failed to install Linux package in container " << name_
<< ": " << status.error_message()
<< " code: " << status.error_code();
out_error->assign("gRPC failure installing Linux package in container: " +
status.error_message());
return vm_tools::container::InstallLinuxPackageResponse::FAILED;
}
out_error->assign(container_response.failure_reason());
return container_response.status();
}
bool Container::IsRunning() {
auto channel_state = garcon_channel_->GetState(true);
return channel_state == GRPC_CHANNEL_IDLE ||
channel_state == GRPC_CHANNEL_CONNECTING ||
channel_state == GRPC_CHANNEL_READY;
}
} // namespace cicerone
} // namespace vm_tools