diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2022-02-09 20:30:03 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2022-02-09 20:30:03 +0000 |
commit | 29f23754aef26b27d3abf0a21de3a00282983b2b (patch) | |
tree | fb5d43ec5f5f4b5f73f4477511c850826f4d3629 | |
parent | 09129344de7cd2bbf94718a89fd06e7d9e7e6c2d (diff) | |
parent | fe8fa2a3b49fa9a113d640c7343dbc7e6b31591a (diff) | |
download | cuttlefish-android-s-v2-beta-3.tar.gz |
Merge "Use CF_EXPECT in cvd_test_gce_driver and credential_source"android-s-v2-beta-3android-s-qpr3-beta-1android-s-v2-beta-3android-s-qpr3-beta-1
-rw-r--r-- | host/commands/test_gce_driver/cvd_test_gce_driver.cpp | 226 | ||||
-rw-r--r-- | host/libs/web/credential_source.cc | 62 | ||||
-rw-r--r-- | host/libs/web/credential_source.h | 7 |
3 files changed, 117 insertions, 178 deletions
diff --git a/host/commands/test_gce_driver/cvd_test_gce_driver.cpp b/host/commands/test_gce_driver/cvd_test_gce_driver.cpp index 33d022b2f..a7c1a8af5 100644 --- a/host/commands/test_gce_driver/cvd_test_gce_driver.cpp +++ b/host/commands/test_gce_driver/cvd_test_gce_driver.cpp @@ -59,15 +59,13 @@ using google::protobuf::util::SerializeDelimitedToFileDescriptor; namespace cuttlefish { namespace { -android::base::Result<Json::Value> ReadJsonFromFile(const std::string& path) { +Result<Json::Value> ReadJsonFromFile(const std::string& path) { Json::CharReaderBuilder builder; std::ifstream ifs(path); Json::Value content; std::string errorMessage; - if (!Json::parseFromStream(builder, ifs, &content, &errorMessage)) { - return android::base::Error() - << "Could not read config file \"" << path << "\": " << errorMessage; - } + CF_EXPECT(Json::parseFromStream(builder, ifs, &content, &errorMessage), + "Could not read config file \"" << path << "\": " << errorMessage); return content; } @@ -125,66 +123,47 @@ class ReadEvalPrintLoop { if (!handler_result.ok()) { test_gce_driver::TestMessage error_msg; error_msg.mutable_error()->set_text(handler_result.error().message()); - if (!SerializeDelimitedToFileDescriptor(error_msg, out_)) { - return Error() << "Failure while writing error message: \"" - << handler_result.error() << "\""; - } + CF_EXPECT(SerializeDelimitedToFileDescriptor(error_msg, out_), + "Failure while writing error message: (\n" + << handler_result.error() << "\n)"); } test_gce_driver::TestMessage stream_end_msg; stream_end_msg.mutable_stream_end(); // Set this in the oneof - if (!SerializeDelimitedToFileDescriptor(stream_end_msg, out_)) { - return Error() << "Failure while writing stream end message"; - } + CF_EXPECT(SerializeDelimitedToFileDescriptor(stream_end_msg, out_)); } return {}; } private: Result<void> NewInstance(const test_gce_driver::CreateInstance& request) { - if (request.id().name() == "") { - return Error() << "Instance name must be specified"; - } - if (request.id().zone() == "") { - return Error() << "Instance zone must be specified"; - } - auto instance = ScopedGceInstance::CreateDefault(gce_, request.id().zone(), - request.id().name()); - if (!instance.ok()) { - return Error() << "Failed to create instance: " << instance.error(); - } - instances_.emplace(request.id().name(), std::move(*instance)); + CF_EXPECT(request.id().name() != "", "Instance name must be specified"); + CF_EXPECT(request.id().zone() != "", "Instance zone must be specified"); + auto instance = CF_EXPECT(ScopedGceInstance::CreateDefault( + gce_, request.id().zone(), request.id().name())); + instances_.emplace(request.id().name(), std::move(instance)); return {}; } Result<void> SshCommand(const test_gce_driver::SshCommand& request) { auto instance = instances_.find(request.instance().name()); - if (instance == instances_.end()) { - return Error() << "Instance \"" << request.instance().name() - << "\" not found"; - } - auto ssh = instance->second->Ssh(); - if (!ssh.ok()) { - return Error() << "Failed to set up ssh command: " << ssh.error(); - } + CF_EXPECT(instance != instances_.end(), + "Instance \"" << request.instance().name() << "\" not found"); + auto ssh = CF_EXPECT(instance->second->Ssh()); for (auto argument : request.arguments()) { - ssh->RemoteParameter(argument); + ssh.RemoteParameter(argument); } std::optional<Subprocess> ssh_proc; SharedFD stdout_read; SharedFD stderr_read; { // Things created here need to be closed early - auto cmd = ssh->Build(); + auto cmd = ssh.Build(); SharedFD stdout_write; - if (!SharedFD::Pipe(&stdout_read, &stdout_write)) { - return Error() << "Failed to open pipe for stdout"; - } + CF_EXPECT(SharedFD::Pipe(&stdout_read, &stdout_write)); cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut, stdout_write); SharedFD stderr_write; - if (!SharedFD::Pipe(&stderr_read, &stderr_write)) { - return Error() << "Failed to open pipe for stderr"; - } + CF_EXPECT(SharedFD::Pipe(&stderr_read, &stderr_write)); cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdErr, stderr_write); ssh_proc = cmd.Start(); @@ -202,58 +181,48 @@ class ReadEvalPrintLoop { if (read_set.IsSet(stdout_read)) { char buffer[1 << 14]; auto read = stdout_read->Read(buffer, sizeof(buffer)); - if (read < 0) { - return Error() << "Failure in reading ssh stdout: " - << stdout_read->StrError(); - } else if (read == 0) { // EOF + CF_EXPECT(read >= 0, + "Failure in reading ssh stdout: " << stdout_read->StrError()); + if (read == 0) { // EOF stdout_read = SharedFD(); } else { - test_gce_driver::TestMessage output; - output.mutable_data()->set_type( + test_gce_driver::TestMessage stdout_chunk; + stdout_chunk.mutable_data()->set_type( test_gce_driver::DataType::DATA_TYPE_STDOUT); - output.mutable_data()->set_contents(buffer, read); - if (!SerializeDelimitedToFileDescriptor(output, out_)) { - return Error() << "Failure while writing stdout message"; - } + stdout_chunk.mutable_data()->set_contents(buffer, read); + CF_EXPECT(SerializeDelimitedToFileDescriptor(stdout_chunk, out_)); } } if (read_set.IsSet(stderr_read)) { char buffer[1 << 14]; auto read = stderr_read->Read(buffer, sizeof(buffer)); - if (read < 0) { - return Error() << "Failure in reading ssh stderr: " - << stderr_read->StrError(); - } else if (read == 0) { // EOF + CF_EXPECT(read >= 0, + "Failure in reading ssh stderr: " << stdout_read->StrError()); + if (read == 0) { // EOF stderr_read = SharedFD(); } else { - test_gce_driver::TestMessage output; - output.mutable_data()->set_type( + test_gce_driver::TestMessage stderr_chunk; + stderr_chunk.mutable_data()->set_type( test_gce_driver::DataType::DATA_TYPE_STDERR); - output.mutable_data()->set_contents(buffer, read); - if (!SerializeDelimitedToFileDescriptor(output, out_)) { - return Error() << "Failure while writing stdout message"; - } + stderr_chunk.mutable_data()->set_contents(buffer, read); + CF_EXPECT(SerializeDelimitedToFileDescriptor(stderr_chunk, out_)); } } } auto ret = ssh_proc->Wait(); - test_gce_driver::TestMessage output; - output.mutable_data()->set_type( + test_gce_driver::TestMessage retcode_chunk; + retcode_chunk.mutable_data()->set_type( test_gce_driver::DataType::DATA_TYPE_RETURN_CODE); - output.mutable_data()->set_contents(std::to_string(ret)); - if (!SerializeDelimitedToFileDescriptor(output, out_)) { - return Error() << "Failure while writing return code message"; - } + retcode_chunk.mutable_data()->set_contents(std::to_string(ret)); + CF_EXPECT(SerializeDelimitedToFileDescriptor(retcode_chunk, out_)); return {}; } Result<void> UploadBuildArtifact( const test_gce_driver::UploadBuildArtifact& request) { auto instance = instances_.find(request.instance().name()); - if (instance == instances_.end()) { - return Error() << "Instance \"" << request.instance().name() - << "\" not found"; - } + CF_EXPECT(instance != instances_.end(), + "Instance \"" << request.instance().name() << "\" not found"); struct { ScopedGceInstance* instance; @@ -269,15 +238,14 @@ class ReadEvalPrintLoop { if (data == nullptr) { auto ssh = callback_state.instance->Ssh(); if (!ssh.ok()) { - callback_state.result = Error() - << "ssh command failed: " << ssh.error(); + callback_state.result = CF_ERR("ssh command failed\n" << ssh.error()); return false; } auto tcp_server = ssh->TcpServerStdin(); if (!tcp_server.ok()) { - callback_state.result = Error() << "ssh tcp server failed: " - << tcp_server.error(); + callback_state.result = CF_ERR("ssh tcp server failed\n" + << tcp_server.error()); return false; } callback_state.tcp_server = *tcp_server; @@ -289,70 +257,59 @@ class ReadEvalPrintLoop { if (!callback_state.tcp_client->IsOpen()) { callback_state.ssh_proc->Stop(); callback_state.ssh_proc->Wait(); - callback_state.result = Error() - << "Failed to accept TCP client: " - << callback_state.tcp_client->StrError(); + callback_state.result = + CF_ERR("Failed to accept TCP client: " + << callback_state.tcp_client->StrError()); return false; } } if (WriteAll(callback_state.tcp_client, data, size) != size) { callback_state.ssh_proc->Stop(); - callback_state.result = Error() - << "Failed to write contents: " - << callback_state.tcp_client->StrError(); + callback_state.result = + CF_ERR("Failed to write contents\n" + << callback_state.tcp_client->StrError()); return false; } return true; }; DeviceBuild build(request.build().id(), request.build().target()); - if (!build_.ArtifactToCallback(build, request.artifact_name(), callback)) { - return Error() << "Failed to send file: " - << (callback_state.result.ok() - ? "Unknown failure" - : callback_state.result.error().message()); - } + CF_EXPECT( + build_.ArtifactToCallback(build, request.artifact_name(), callback), + "Failed to send file: (\n" + << (callback_state.result.ok() + ? "Unknown failure" + : callback_state.result.error().message() + "\n)")); if (callback_state.tcp_client->IsOpen() && callback_state.tcp_client->Shutdown(SHUT_WR) != 0) { - return Error() << "Failed to shutdown socket: " - << callback_state.tcp_client->StrError(); + return CF_ERR("Failed to shutdown socket: " + << callback_state.tcp_client->StrError()); } if (callback_state.ssh_proc) { auto ssh_ret = callback_state.ssh_proc->Wait(); - if (ssh_ret != 0) { - return Error() << "SSH command failed with code: " << ssh_ret; - } + CF_EXPECT(ssh_ret == 0, "SSH command failed with code: " << ssh_ret); } return {}; } Result<void> UploadFile(const test_gce_driver::UploadFile& request) { auto instance = instances_.find(request.instance().name()); - if (instance == instances_.end()) { - return Error() << "Instance \"" << request.instance().name() - << "\" not found"; - } + CF_EXPECT(instance != instances_.end(), + "Instance \"" << request.instance().name() << "\" not found"); - auto ssh = instance->second->Ssh(); - if (!ssh.ok()) { - return Error() << "Could not create command: " << ssh.error(); - } - - auto tcp = ssh->TcpServerStdin(); - if (!tcp.ok()) { - return Error() << "Failed to set up remote stdin: " << tcp.error(); - } + auto ssh = CF_EXPECT(instance->second->Ssh()); + auto tcp = CF_EXPECT(ssh.TcpServerStdin()); - ssh->RemoteParameter("cat >" + request.remote_path()); + ssh.RemoteParameter("cat >" + request.remote_path()); - auto ssh_proc = ssh->Build().Start(); + auto ssh_proc = ssh.Build().Start(); - auto client = SharedFD::Accept(**tcp); + auto client = SharedFD::Accept(*tcp); if (!client->IsOpen()) { ssh_proc.Stop(); - return Error() << "Failed to accept TCP client: " << client->StrError(); + return CF_ERR("Failed to accept TCP client: " << client->StrError()); } while (true) { @@ -364,42 +321,38 @@ class ReadEvalPrintLoop { ParseDelimitedFromZeroCopyStream(&data_msg, &in_, &clean_eof); if (clean_eof) { ssh_proc.Stop(); - return Error() << "Received EOF"; + return CF_ERR("Received EOF"); } else if (!parsed) { ssh_proc.Stop(); - return Error() << "Failed to parse message"; + return CF_ERR("Failed to parse message"); } else if (data_msg.contents_case() == test_gce_driver::TestMessage::ContentsCase::kStreamEnd) { break; } else if (data_msg.contents_case() != test_gce_driver::TestMessage::ContentsCase::kData) { ssh_proc.Stop(); - return Error() << "Received wrong type of message: " - << data_msg.contents_case(); + return CF_ERR( + "Received wrong type of message: " << data_msg.contents_case()); } else if (data_msg.data().type() != test_gce_driver::DataType::DATA_TYPE_FILE_CONTENTS) { ssh_proc.Stop(); - return Error() << "Received unexpected data type: " - << data_msg.data().type(); + return CF_ERR( + "Received unexpected data type: " << data_msg.data().type()); } LOG(INFO) << "going to write message of size " << data_msg.data().contents().size(); if (WriteAll(client, data_msg.data().contents()) != data_msg.data().contents().size()) { ssh_proc.Stop(); - return Error() << "Failed to write contents: " << client->StrError(); + return CF_ERR("Failed to write contents: " << client->StrError()); } LOG(INFO) << "successfully wrote message?"; } - if (client->Shutdown(SHUT_WR) != 0) { - return Error() << "Failed to shutdown socket: " << client->StrError(); - } + CF_EXPECT(client->Shutdown(SHUT_WR) != 0, client->StrError()); auto ssh_ret = ssh_proc.Wait(); - if (ssh_ret != 0) { - return Error() << "SSH command failed with code: " << ssh_ret; - } + CF_EXPECT(ssh_ret == 0, "SSH command failed with code: " << ssh_ret); return {}; } @@ -415,7 +368,7 @@ class ReadEvalPrintLoop { } // namespace -int TestGceDriverMain(int argc, char** argv) { +Result<void> TestGceDriverMain(int argc, char** argv) { std::vector<Flag> flags; std::string service_account_json_private_key_path = ""; flags.emplace_back(GflagsCompatFlag("service-account-json-private-key-path", @@ -425,39 +378,36 @@ int TestGceDriverMain(int argc, char** argv) { std::vector<std::string> args = ArgsToVec(argc - 1, argv + 1); // Skip argv[0] - CHECK(ParseFlags(flags, args)) << "Could not process command line flags."; + CF_EXPECT(ParseFlags(flags, args), "Could not process command line flags."); - auto service_json = ReadJsonFromFile(service_account_json_private_key_path); - CHECK(service_json.ok()) << service_json.error(); + auto service_json = + CF_EXPECT(ReadJsonFromFile(service_account_json_private_key_path)); static constexpr char COMPUTE_SCOPE[] = "https://www.googleapis.com/auth/compute"; auto curl = CurlWrapper::Create(); - auto gce_creds = ServiceAccountOauthCredentialSource::FromJson( - *curl, *service_json, COMPUTE_SCOPE); - CHECK(gce_creds); + auto gce_creds = CF_EXPECT(ServiceAccountOauthCredentialSource::FromJson( + *curl, service_json, COMPUTE_SCOPE)); - // TODO(b/216667647): Allow these settings to be configured. - GceApi gce(*curl, *gce_creds, cloud_project); + GceApi gce(*curl, gce_creds, cloud_project); static constexpr char BUILD_SCOPE[] = "https://www.googleapis.com/auth/androidbuild.internal"; - auto build_creds = ServiceAccountOauthCredentialSource::FromJson( - *curl, *service_json, BUILD_SCOPE); - CHECK(build_creds); + auto build_creds = CF_EXPECT(ServiceAccountOauthCredentialSource::FromJson( + *curl, service_json, BUILD_SCOPE)); - BuildApi build(*curl, build_creds.get()); + BuildApi build(*curl, &build_creds); ReadEvalPrintLoop executor(gce, build, STDIN_FILENO, STDOUT_FILENO); LOG(INFO) << "Starting processing"; - auto result = executor.Process(); - CHECK(result.ok()) << "Executor loop failed: " << result.error(); + CF_EXPECT(executor.Process()); - return 0; + return {}; } } // namespace cuttlefish int main(int argc, char** argv) { - return cuttlefish::TestGceDriverMain(argc, argv); + auto res = cuttlefish::TestGceDriverMain(argc, argv); + CHECK(res.ok()) << "cvd_test_gce_driver failed: " << res.error(); } diff --git a/host/libs/web/credential_source.cc b/host/libs/web/credential_source.cc index b9a29bff9..b29be8a02 100644 --- a/host/libs/web/credential_source.cc +++ b/host/libs/web/credential_source.cc @@ -90,51 +90,39 @@ std::unique_ptr<CredentialSource> FixedCredentialSource::make( return std::unique_ptr<CredentialSource>(new FixedCredentialSource(credential)); } -static int OpenSslPrintErrCallback(const char* str, size_t len, void*) { - LOG(ERROR) << std::string(str, len); - return 1; // success +static std::string CollectSslErrors() { + std::stringstream errors; + auto callback = [](const char* str, size_t len, void* stream) { + ((std::stringstream*)stream)->write(str, len); + return 1; // success + }; + ERR_print_errors_cb(callback, &errors); + return errors.str(); } -std::unique_ptr<ServiceAccountOauthCredentialSource> +Result<ServiceAccountOauthCredentialSource> ServiceAccountOauthCredentialSource::FromJson(CurlWrapper& curl, const Json::Value& json, const std::string& scope) { - std::unique_ptr<ServiceAccountOauthCredentialSource> source; - source.reset(new ServiceAccountOauthCredentialSource(curl)); - - if (!json.isMember("client_email")) { - LOG(ERROR) << "Service account json missing `client_email` field"; - return {}; - } else if (json["client_email"].type() != Json::ValueType::stringValue) { - LOG(ERROR) << "Service account `client_email` field was the wrong type"; - return {}; - } - source->email_ = json["client_email"].asString(); - - if (!json.isMember("private_key")) { - LOG(ERROR) << "Service account json missing `private_key` field"; - return {}; - } else if (json["private_key"].type() != Json::ValueType::stringValue) { - LOG(ERROR) << "Service account json `private_key` field was the wrong type"; - return {}; - } - std::string key_str = json["private_key"].asString(); + ServiceAccountOauthCredentialSource source(curl); + source.scope_ = scope; - std::unique_ptr<BIO, int (*)(BIO*)> bo(BIO_new(BIO_s_mem()), BIO_free); - if (!bo) { - LOG(ERROR) << "Failed to create boringssl BIO"; - return {}; - } - CHECK(BIO_write(bo.get(), key_str.c_str(), key_str.size()) == key_str.size()); + CF_EXPECT(json.isMember("client_email")); + CF_EXPECT(json["client_email"].type() == Json::ValueType::stringValue); + source.email_ = json["client_email"].asString(); - source->private_key_.reset(PEM_read_bio_PrivateKey(bo.get(), nullptr, 0, 0)); - if (!source->private_key_) { - LOG(ERROR) << "PEM_read_bio_PrivateKey failed, showing openssl error stack"; - ERR_print_errors_cb(OpenSslPrintErrCallback, nullptr); - return {}; - } + CF_EXPECT(json.isMember("private_key")); + CF_EXPECT(json["private_key"].type() == Json::ValueType::stringValue); + std::string key_str = json["private_key"].asString(); + + std::unique_ptr<BIO, int (*)(BIO*)> bo(CF_EXPECT(BIO_new(BIO_s_mem())), + BIO_free); + CF_EXPECT(BIO_write(bo.get(), key_str.c_str(), key_str.size()) == + key_str.size()); - source->scope_ = scope; + auto pkey = CF_EXPECT(PEM_read_bio_PrivateKey(bo.get(), nullptr, 0, 0), + CollectSslErrors()); + source.private_key_.reset(pkey); return source; } diff --git a/host/libs/web/credential_source.h b/host/libs/web/credential_source.h index d81ca66f6..7ab071cf5 100644 --- a/host/libs/web/credential_source.h +++ b/host/libs/web/credential_source.h @@ -18,11 +18,12 @@ #include <chrono> #include <memory> -#include "curl_wrapper.h" - #include <json/json.h> #include <openssl/evp.h> +#include "common/libs/utils/result.h" +#include "host/libs/web/curl_wrapper.h" + namespace cuttlefish { class CredentialSource { @@ -58,7 +59,7 @@ public: class ServiceAccountOauthCredentialSource : public CredentialSource { public: - static std::unique_ptr<ServiceAccountOauthCredentialSource> FromJson( + static Result<ServiceAccountOauthCredentialSource> FromJson( CurlWrapper& curl, const Json::Value& service_account_json, const std::string& scope); |