diff --git a/eden/fs/store/hg/HgBackingStore.cpp b/eden/fs/store/hg/HgBackingStore.cpp index 47ccfee069..c2485595dc 100644 --- a/eden/fs/store/hg/HgBackingStore.cpp +++ b/eden/fs/store/hg/HgBackingStore.cpp @@ -383,6 +383,21 @@ void HgBackingStore::initializeTreeManifestImport( #endif // EDEN_HAVE_HG_TREEMANIFEST } +std::unique_ptr HgBackingStore::getMononokeServiceAddress() { + auto edenConfig = config_->getEdenConfig(); + auto hostname = edenConfig->getMononokeHostName(); + + if (hostname) { + auto port = edenConfig->getMononokePort(); + XLOG(DBG2) << "Using " << *hostname << ":" << port << " for Mononoke"; + return std::make_unique(*hostname, port); + } + + const auto& tier = edenConfig->getMononokeTierName(); + XLOG(DBG2) << "Using SMC tier " << tier << " for Mononoke"; + return std::make_unique(tier); +} + #ifndef EDEN_WIN_NOMONONOKE std::unique_ptr HgBackingStore::initializeHttpMononokeBackingStore() { @@ -399,27 +414,11 @@ HgBackingStore::initializeHttpMononokeBackingStore() { return nullptr; } - auto executor = folly::getIOExecutor(); - auto hostname = edenConfig->getMononokeHostName(); - - std::unique_ptr service; - if (hostname) { - auto port = edenConfig->getMononokePort(); - service = std::make_unique(*hostname, port); - XLOG(DBG2) << "HTTP Mononoke enabled for repository " << repoName_ - << ", using host " << *hostname << ":" << port; - } else { - const auto& tier = edenConfig->getMononokeTierName(); - service = std::make_unique(tier); - XLOG(DBG2) << "HTTP Mononoke enabled for repository " << repoName_ - << ", using tier " << tier; - } - return std::make_unique( - std::move(service), + getMononokeServiceAddress(), repoName_, std::chrono::milliseconds(FLAGS_mononoke_timeout), - executor.get(), + folly::getIOExecutor().get(), sslContext); } @@ -440,25 +439,16 @@ HgBackingStore::initializeThriftMononokeBackingStore() { std::unique_ptr HgBackingStore::initializeCurlMononokeBackingStore() { auto edenConfig = config_->getEdenConfig(); - auto hostname = edenConfig->getMononokeHostName(); auto clientCertificate = edenConfig->getClientCertificate(); - if (!hostname) { - XLOG(WARN) << "Mononoke is disabled because no Mononoke host is provided"; - return nullptr; - } - if (!clientCertificate) { XLOG(WARN) << "Mononoke is disabled because no client certificate is provided"; return nullptr; } - XLOG(DBG2) << "Initializing cURL Mononoke backing store for repository " - << repoName_ << ", using host " << *hostname; - return std::make_unique( - *hostname, + getMononokeServiceAddress(), AbsolutePath(folly::to(*clientCertificate)), repoName_, std::chrono::milliseconds(FLAGS_mononoke_timeout), diff --git a/eden/fs/store/hg/HgBackingStore.h b/eden/fs/store/hg/HgBackingStore.h index c6be9f738e..d6e7ddaad1 100644 --- a/eden/fs/store/hg/HgBackingStore.h +++ b/eden/fs/store/hg/HgBackingStore.h @@ -43,6 +43,7 @@ class MononokeThriftBackingStore; class MononokeCurlBackingStore; class UnboundedQueueExecutor; class ReloadableConfig; +class ServiceAddress; /** * A BackingStore implementation that loads data out of a mercurial repository. @@ -117,6 +118,13 @@ class HgBackingStore : public BackingStore { */ std::shared_ptr getMononoke(); + /** + * Get an instance of `ServiceAddress` that points to Mononoke API Server + * based on user's configuration. It could be a pair of host and port or a smc + * tier name. + */ + std::unique_ptr getMononokeServiceAddress(); + #ifndef EDEN_WIN_NOMONONOKE /** * Create an instance of MononokeHttpBackingStore with values from config_ diff --git a/eden/fs/store/mononoke/CurlHttpClient.cpp b/eden/fs/store/mononoke/CurlHttpClient.cpp index 5072ee6054..3808781657 100644 --- a/eden/fs/store/mononoke/CurlHttpClient.cpp +++ b/eden/fs/store/mononoke/CurlHttpClient.cpp @@ -30,15 +30,16 @@ write_callback(char* contents, size_t size, size_t nmemb, void* out) { } // namespace CurlHttpClient::CurlHttpClient( - std::string host, + folly::SocketAddress address, AbsolutePath certificate, std::chrono::milliseconds timeout) - : host_(std::move(host)), + : address_(std::move(address)), certificate_(std::move(certificate)), timeout_(timeout) { handle_ = buildRequest(); } +/// Makes an HTTP GET request to the given path. std::unique_ptr CurlHttpClient::get(const std::string& path) { auto buffer = folly::IOBufQueue{}; @@ -46,10 +47,12 @@ std::unique_ptr CurlHttpClient::get(const std::string& path) { throw std::runtime_error("curl failed to set CURLOPT_WRITEDATA"); } - if (curl_easy_setopt(handle_.get(), CURLOPT_URL, (host_ + path).c_str()) != - CURLE_OK) { + auto url = folly::to( + "https://", address_.getHostStr(), ":", address_.getPort(), path); + + if (curl_easy_setopt(handle_.get(), CURLOPT_URL, url.c_str()) != CURLE_OK) { throw std::runtime_error( - folly::to("curl failed to set url: ", host_, path)); + folly::to("curl failed to set url: ", url)); } auto ret = curl_easy_perform(handle_.get()); diff --git a/eden/fs/store/mononoke/CurlHttpClient.h b/eden/fs/store/mononoke/CurlHttpClient.h index e3c866fa1f..ee75866ffb 100644 --- a/eden/fs/store/mononoke/CurlHttpClient.h +++ b/eden/fs/store/mononoke/CurlHttpClient.h @@ -10,6 +10,7 @@ #pragma once #include +#include #include #include #include @@ -34,7 +35,7 @@ struct CurlDeleter { class CurlHttpClient { public: CurlHttpClient( - std::string host, + folly::SocketAddress address, AbsolutePath certificate, std::chrono::milliseconds timeout); @@ -44,7 +45,7 @@ class CurlHttpClient { void initGlobal(); std::unique_ptr buildRequest(); - std::string host_; + folly::SocketAddress address_; AbsolutePath certificate_; // cURL timeout for the request (see CURLOPT_TIMEOUT_MS for detail) diff --git a/eden/fs/store/mononoke/MononokeCurlBackingStore.cpp b/eden/fs/store/mononoke/MononokeCurlBackingStore.cpp index 4139552f08..bca98be5d3 100644 --- a/eden/fs/store/mononoke/MononokeCurlBackingStore.cpp +++ b/eden/fs/store/mononoke/MononokeCurlBackingStore.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "eden/fs/model/Blob.h" #include "eden/fs/model/Hash.h" @@ -23,6 +24,7 @@ #include "eden/fs/store/mononoke/CurlHttpClient.h" #include "eden/fs/store/mononoke/MononokeAPIUtils.h" #include "eden/fs/utils/PathFuncs.h" +#include "eden/fs/utils/ServiceAddress.h" DEFINE_int32( mononoke_curl_threads, @@ -39,7 +41,8 @@ static folly::ThreadLocalPtr threadCurlClient; CurlHttpClient& getCurlHttpClient() { if (!threadCurlClient) { throw std::logic_error( - "Attempting to use curl client in a non-curl client thread"); + "Attempting to use curl client in a non-curl client thread " + "or failed to resolve service address"); } return *threadCurlClient; } @@ -47,31 +50,43 @@ CurlHttpClient& getCurlHttpClient() { class MononokeCurlThreadFactory : public folly::ThreadFactory { public: MononokeCurlThreadFactory( - std::string host, + std::unique_ptr service, AbsolutePath certificate, std::chrono::milliseconds timeout) : delegate_("CurlClient"), - host_(host), + service_(std::move(service)), certificate_(certificate), timeout_(timeout) {} std::thread newThread(folly::Func&& func) override { return delegate_.newThread([this, func = std::move(func)]() mutable { - threadCurlClient.reset(new CurlHttpClient(host_, certificate_, timeout_)); - func(); + try { + auto address = service_->getSocketAddressBlocking(); + if (address) { + threadCurlClient.reset( + new CurlHttpClient(address->first, certificate_, timeout_)); + func(); + } else { + XLOG(WARN) << "failed to resolve address for Mononoke API Server"; + } + } catch (const std::exception& ex) { + XLOG(WARN) + << "failed to resolve address for Mononoke API Server, reason: " + << ex.what(); + } }); } private: folly::NamedThreadFactory delegate_; - std::string host_; + std::unique_ptr service_; AbsolutePath certificate_; const std::chrono::milliseconds timeout_; -}; +}; // namespace } // namespace MononokeCurlBackingStore::MononokeCurlBackingStore( - std::string host, + std::unique_ptr service, AbsolutePath certificate, std::string repo, std::chrono::milliseconds timeout, @@ -82,7 +97,7 @@ MononokeCurlBackingStore::MononokeCurlBackingStore( std::make_unique>(), std::make_shared( - host, + std::move(service), certificate, timeout))), serverExecutor_(std::move(executor)) {} diff --git a/eden/fs/store/mononoke/MononokeCurlBackingStore.h b/eden/fs/store/mononoke/MononokeCurlBackingStore.h index cda09fc089..a36cd27189 100644 --- a/eden/fs/store/mononoke/MononokeCurlBackingStore.h +++ b/eden/fs/store/mononoke/MononokeCurlBackingStore.h @@ -28,11 +28,12 @@ namespace eden { class Blob; class Tree; class Hash; +class ServiceAddress; class MononokeCurlBackingStore : public BackingStore { public: MononokeCurlBackingStore( - std::string host, + std::unique_ptr service, AbsolutePath certificate, std::string repo, std::chrono::milliseconds timeout, diff --git a/eden/fs/store/mononoke/test/CurlTest.cpp b/eden/fs/store/mononoke/test/CurlTest.cpp index 9c309d840c..c953ee72a2 100644 --- a/eden/fs/store/mononoke/test/CurlTest.cpp +++ b/eden/fs/store/mononoke/test/CurlTest.cpp @@ -44,6 +44,7 @@ class TestServer { } }; +// @lint-ignore-every PRIVATEKEY1 const std::string kClientCACertName = "client-ca-cert.pem"; const std::string kClientCACertContent = folly::stripLeftMargin(R"( -----BEGIN CERTIFICATE----- @@ -263,8 +264,7 @@ class CurlTest : public ::testing::Test { certs_->path() / kClientCACertName); const auto address = server_->getAddresses()[0].address; - host_ = folly::to( - "https://[", address.getFullyQualified(), "]:", address.getPort()); + address_ = folly::SocketAddress("::1", address.getPort()); } static void TearDownTestCase() { @@ -274,16 +274,16 @@ class CurlTest : public ::testing::Test { static std::unique_ptr certs_; static std::unique_ptr server_; - static std::string host_; + static folly::SocketAddress address_; }; std::unique_ptr CurlTest::certs_ = nullptr; std::unique_ptr CurlTest::server_ = nullptr; -std::string CurlTest::host_ = ""; +folly::SocketAddress CurlTest::address_; TEST_F(CurlTest, Success) { auto client = CurlHttpClient( - host_, + address_, AbsolutePath((certs_->path() / kClientChainName).native()), std::chrono::milliseconds(100000)); @@ -294,7 +294,7 @@ TEST_F(CurlTest, Success) { TEST_F(CurlTest, InvalidClientCertificate) { auto client = CurlHttpClient( - host_, + address_, AbsolutePath((certs_->path() / kInvalidChainName).native()), std::chrono::milliseconds(100000)); @@ -308,7 +308,7 @@ TEST_F(CurlTest, InvalidClientCertificate) { TEST_F(CurlTest, ThrowOn4XX) { auto client = CurlHttpClient( - host_, + address_, AbsolutePath((certs_->path() / kClientChainName).native()), std::chrono::milliseconds(100000)); diff --git a/eden/win/fs/edenfs.vcxproj b/eden/win/fs/edenfs.vcxproj index aa600689c1..9aad35cded 100644 --- a/eden/win/fs/edenfs.vcxproj +++ b/eden/win/fs/edenfs.vcxproj @@ -205,6 +205,7 @@ + @@ -289,6 +290,7 @@ + @@ -342,4 +344,4 @@ - \ No newline at end of file + diff --git a/eden/win/fs/edenfs.vcxproj.filters b/eden/win/fs/edenfs.vcxproj.filters index 6257868df2..5e948dfd40 100644 --- a/eden/win/fs/edenfs.vcxproj.filters +++ b/eden/win/fs/edenfs.vcxproj.filters @@ -320,6 +320,9 @@ fs\Tracing + + fs\Util + @@ -583,6 +586,9 @@ Win\fs\Utils + + fs\Util + @@ -610,4 +616,4 @@ fs\Service - \ No newline at end of file +