/
githubmirror
/
nbs
Обзор
Документация
Войти
/
githubmirror
/
nbs
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
cloud/filestore/apps/client/lib/command.cpp
605 строк
15 KB
yegorskii
Proper usage of ICertificateProvider interface (#6095)
03 июн 2026, 17:28
Не верифицирован
03 июн 2026, 17:28
2a84808
Код
Авторство
О чём код?
#include "command.h" #include <cloud/filestore/libs/client/durable.h> #include <cloud/filestore/libs/client/probes.h> #include <cloud/filestore/libs/vfs/probes.h> #include <cloud/storage/core/libs/common/hostname.h> #include <cloud/storage/core/libs/common/scheduler.h> #include <cloud/storage/core/libs/common/timer.h> #include <cloud/storage/core/libs/grpc/tls_certificate_provider.h> #include <cloud/storage/core/libs/iam/iface/config.h> #include <library/cpp/lwtrace/mon/mon_lwtrace.h> #include <library/cpp/protobuf/util/pb_io.h> #include <util/datetime/base.h> #include <util/generic/guid.h> #include <util/system/env.h> #include <util/system/fs.h> #include <util/system/sysstat.h> namespace NCloud::NFileStore::NClient { using namespace NThreading; namespace { //////////////////////////////////////////////////////////////////////////////// constexpr TDuration WaitTimeout = TDuration::Seconds(1); const TString DefaultServerConfigFile = "/Berkanavt/nfs-server/cfg/nfs-client.txt"; const TString DefaultVhostConfigFile = "/Berkanavt/nfs-vhost/cfg/nfs-client.txt"; const TString DefaultVhostLocalConfigFile = "/Berkanavt/nfs-vhost/cfg/nfs-client-local.txt"; const TString DefaultIamConfigFile = "/Berkanavt/nfs-server/cfg/nfs-iam.txt"; ICertificateProviderPtr CreateClientCertificateProvider( const TClientConfigPtr& config) { TVector<NCloud::TCertificateFiles> certPathList { { .PrivateKeyPath = config->GetCertPrivateKeyFile(), .CertChainPath = config->GetCertFile() } }; return CreateStaticCertificateProvider( config->GetRootCertsFile(), std::move(certPathList)); } } // namespace //////////////////////////////////////////////////////////////////////////////// TCommand::TCommand() { Opts.AddHelpOption('h'); Opts.AddVersionOption(); Opts.AddLongOption("verbose") .OptionalArgument("STR") .DefaultValue("info") .StoreResult(&VerboseLevel); Opts.AddLongOption("mon-address") .RequiredArgument("STR") .StoreResult(&MonitoringAddress); Opts.AddLongOption("mon-port") .RequiredArgument("NUM") .StoreResult(&MonitoringPort); Opts.AddLongOption("mon-threads") .RequiredArgument("NUM") .StoreResult(&MonitoringThreads); Opts.AddLongOption("server-address") .RequiredArgument("STR") .StoreResult(&ServerAddress); Opts.AddLongOption("server-port") .RequiredArgument("NUM") .StoreResult(&ServerPort); Opts.AddLongOption("secure-port", "connect secure port (overrides --server-port)") .RequiredArgument("NUM") .StoreResult(&SecurePort); Opts.AddLongOption("server-unix-socket-path") .RequiredArgument("STR") .StoreResult(&ServerUnixSocketPath); Opts.AddLongOption("skip-cert-verification", "skip server certificate verification") .StoreTrue(&SkipCertVerification); Opts.AddLongOption("config") .Help(TStringBuilder() << "config file name. Default is " << DefaultServerConfigFile << " and " << DefaultVhostConfigFile << " and " << DefaultVhostLocalConfigFile) .OptionalArgument("STR") .StoreResult(&ConfigFile); Opts.AddLongOption("iam-config") .Help(TStringBuilder() << "iam-config file name. Default is " << DefaultIamConfigFile) .RequiredArgument("STR") .StoreResult(&IamConfigFile); Opts.AddLongOption("json") .StoreTrue(&JsonOutput); } int TCommand::Run(int argc, char** argv) { OptsParseResult.ConstructInPlace(&Opts, argc, argv); Init(); Start(); if (!Execute()) { // wait until operation completed with_lock (WaitMutex) { while (ProgramShouldContinue.PollState() == TProgramShouldContinue::Continue) { WaitCondVar.WaitT(WaitMutex, WaitTimeout); } } } Stop(); return ProgramShouldContinue.GetReturnCode(); } void TCommand::Stop(int exitCode) { ProgramShouldContinue.ShouldStop(exitCode); WaitCondVar.Signal(); } bool TCommand::WaitForI(const TFuture<void>& future) { while (ProgramShouldContinue.PollState() == TProgramShouldContinue::Continue) { if (future.Wait(WaitTimeout)) { return true; } } return false; } void TCommand::Init() { if (!VerboseLevel.empty()) { auto level = GetLogLevel(VerboseLevel); Y_ENSURE(level, "unknown log level: " << VerboseLevel.Quote()); LogSettings.FiltrationLevel = *level; } Logging = CreateLoggingService("console", LogSettings); Log = Logging->CreateLog("NFS_CLIENT"); if (MonitoringPort) { Monitoring = CreateMonitoringService( MonitoringPort, MonitoringAddress, MonitoringThreads); } else { Monitoring = CreateMonitoringServiceStub(); } auto& probes = NLwTraceMonPage::ProbeRegistry(); probes.AddProbesList(LWTRACE_GET_PROBES(FILESTORE_CLIENT_PROVIDER)); probes.AddProbesList(LWTRACE_GET_PROBES(FILESTORE_VFS_PROVIDER)); Timer = CreateWallClockTimer(); Scheduler = CreateScheduler(); TString configFile; NProto::TClientAppConfig appConfig; if (ConfigFile && NFs::Exists(ConfigFile)) { configFile = ConfigFile; } else if (NFs::Exists(DefaultServerConfigFile)) { configFile = DefaultServerConfigFile; } else if (NFs::Exists(DefaultVhostConfigFile)) { configFile = DefaultVhostConfigFile; } else if (NFs::Exists(DefaultVhostLocalConfigFile)) { configFile = DefaultVhostLocalConfigFile; } if (configFile) { STORAGE_INFO("Using config file " << configFile); ParseFromTextFormat(configFile, appConfig); } else { STORAGE_WARN("Config file is not found"); } auto& config = *appConfig.MutableClientConfig(); if (ServerAddress) { config.SetHost(ServerAddress); } if (ServerPort) { config.SetPort(ServerPort); } if (SecurePort) { config.SetSecurePort(SecurePort); } if (ServerUnixSocketPath){ config.SetUnixSocketPath(ServerUnixSocketPath); } if (config.GetHost() == "localhost" && config.GetSecurePort() != 0) { // With TLS on transform localhost into fully qualified domain name. config.SetHost( GetFqdnHostNameWithRetries( [this] (const yexception&) { STORAGE_ERROR( "FQDNHostName failed: " << CurrentExceptionMessage() << "\n"); })); } if (SkipCertVerification) { config.SetSkipCertVerification(SkipCertVerification); } InitIamTokenClient(); // Do not send token via insecure channel. if (config.GetSecurePort() != 0) { auto iamToken = GetEnv("IAM_TOKEN"); if (!iamToken) { iamToken = GetIamTokenFromClient(); } config.SetAuthToken(std::move(iamToken)); } ClientConfig = std::make_shared<TClientConfig>(config); CertificateProvider = CreateClientCertificateProvider(ClientConfig); } void TCommand::Start() { if (Scheduler) { Scheduler->Start(); } if (Logging) { Logging->Start(); } if (Monitoring) { Monitoring->Start(); } if (CertificateProvider) { CertificateProvider->Start(); } } void TCommand::Stop() { if (IamClient) { IamClient->Stop(); } if (CertificateProvider) { CertificateProvider->Stop(); } if (Monitoring) { Monitoring->Stop(); } if (Logging) { Logging->Stop(); } if (Scheduler) { Scheduler->Stop(); } } void TCommand::InitIamTokenClient() { if (!ClientFactories) { return; } NProto::TIamClientConfig iamClientProtoConfig; if (IamConfigFile) { ParseFromTextFormat(IamConfigFile, iamClientProtoConfig); } else if (NFs::Exists(DefaultIamConfigFile)) { ParseFromTextFormat(DefaultIamConfigFile, iamClientProtoConfig); } auto iamClientConfig = std::make_shared<NCloud::NIamClient::TIamClientConfig>( iamClientProtoConfig); IamClient = ClientFactories->IamClientFactory( std::move(iamClientConfig), CreateLoggingService("console"), Scheduler, Timer); IamClient->Start(); } void TCommand::SetClientFactories( std::shared_ptr<TClientFactories> clientFactories) { ClientFactories = std::move(clientFactories); } TString TCommand::GetIamTokenFromClient() { TString iamToken; if (!IamClient) { return iamToken; } try { auto future = IamClient->GetTokenAsync(); const auto& tokenInfo = future.GetValue(WaitTimeout); if (!HasError(tokenInfo)) { iamToken = tokenInfo.GetResult().Token; } } catch (...) { STORAGE_ERROR(CurrentExceptionMessage()); } return iamToken; } //////////////////////////////////////////////////////////////////////////////// void TFileStoreServiceCommand::Init() { TCommand::Init(); Client = CreateDurableClient( Logging, Timer, Scheduler, CreateRetryPolicy(ClientConfig), CreateFileStoreClient( ClientConfig, Logging, CertificateProvider)); } void TFileStoreServiceCommand::Start() { TCommand::Start(); if (Client) { Client->Start(); } } void TFileStoreServiceCommand::Stop() { if (Client) { Client->Stop(); } TCommand::Stop(); } TFileStoreCommand::TFileStoreCommand(bool isClientIdRequired) { Opts.AddLongOption("filesystem") .Required() .RequiredArgument("STR") .StoreResult(&FileSystemId); auto& opt = Opts.AddLongOption("client-id") .RequiredArgument("CLIENT_ID") .StoreResult(&ClientId); if (isClientIdRequired) { opt.Required(); } else { opt.DefaultValue(CreateGuidAsString()); } Opts.AddLongOption("disable-multitablet-forwarding") .NoArgument() .SetFlag(&DisableMultiTabletForwarding); } //////////////////////////////////////////////////////////////////////////////// void TFileStoreCommand::Start() { TFileStoreServiceCommand::Start(); } void TFileStoreCommand::Stop() { TFileStoreServiceCommand::Stop(); } TFileStoreCommand::TSessionGuard TFileStoreCommand::CreateCustomSession( TString fsId, TString clientId) { NProto::TSessionConfig protoConfig; protoConfig.SetFileSystemId(std::move(fsId)); protoConfig.SetClientId(std::move(clientId)); auto config = std::make_shared<TSessionConfig>(protoConfig); auto session = NClient::CreateSession(Logging, Timer, Scheduler, Client, config); // extracting the value will break the internal state of this session object auto response = WaitFor(session->CreateSession(), /* extract */ false); CheckResponse(response); return TSessionGuard(*this, std::move(session)); } TFileStoreCommand::TSessionGuard TFileStoreCommand::CreateSession() { return CreateCustomSession(FileSystemId, ClientId); } void TFileStoreCommand::DestroySession(ISession& session) { auto response = WaitFor(session.DestroySession()); CheckResponse(response); } //////////////////////////////////////////////////////////////////////////////// NProto::TNodeAttr TFileStoreCommand::ResolveNode( ISession& session, ui64 parentNodeId, TString name, bool ignoreMissing) { const auto invalidNodeId = Max<ui64>(); auto makeInvalidNode = [&] () { NProto::TNodeAttr node; node.SetType(NProto::E_INVALID_NODE); // being explicit about the type node.SetId(invalidNodeId); return node; }; if (parentNodeId == invalidNodeId) { return makeInvalidNode(); } auto request = CreateRequest<NProto::TGetNodeAttrRequest>(); request->MutableHeaders()->SetDisableMultiTabletForwarding(false); request->SetNodeId(parentNodeId); request->SetName(std::move(name)); auto response = WaitFor(session.GetNodeAttr( PrepareCallContext(), std::move(request))); const auto code = MAKE_FILESTORE_ERROR(NProto::E_FS_NOENT); if (ignoreMissing && response.GetError().GetCode() == code) { return makeInvalidNode(); } CheckResponse(response); return response.GetNode(); } TVector<TFileStoreCommand::TPathEntry> TFileStoreCommand::ResolvePath( ISession& session, TStringBuf path, bool ignoreMissing) { TStringBuf tok; TStringBuf it(path); TVector<TPathEntry> result; result.emplace_back(); result.back().Node.SetId(RootNodeId); result.back().Node.SetType(NProto::E_DIRECTORY_NODE); while (it.NextTok('/', tok)) { if (tok) { auto node = ResolveNode( session, result.back().Node.GetId(), ToString(tok), ignoreMissing); result.push_back({node, tok}); } } return result; } NProto::TListNodesResponse TFileStoreCommand::ListAll( ISession& session, const TString& fsId, ui64 parentId, bool disableMultiTabletForwarding, ui32 maxBytes) { NProto::TListNodesResponse fullResult; TString cookie; do { auto request = CreateRequest<NProto::TListNodesRequest>(); request->SetFileSystemId(fsId); request->SetNodeId(parentId); request->MutableHeaders()->SetDisableMultiTabletForwarding( disableMultiTabletForwarding); request->SetCookie(cookie); if (maxBytes) { request->SetMaxBytes(maxBytes); } auto response = WaitFor(session.ListNodes( PrepareCallContext(), std::move(request))); Y_ENSURE_EX( !HasError(response.GetError()), yexception() << "ListNodes error: " << FormatError(response.GetError())); Y_ENSURE_EX( response.NamesSize() == response.NodesSize(), yexception() << "invalid ListNodes response: " << response.DebugString().Quote()); for (ui32 i = 0; i < response.NamesSize(); ++i) { fullResult.AddNames(*response.MutableNames(i)); *fullResult.AddNodes() = std::move(*response.MutableNodes(i)); } cookie = response.GetCookie(); } while (cookie); return fullResult; } TString TFileStoreCommand::ReadLink(ISession& session, ui64 nodeId) { auto request = CreateRequest<NProto::TReadLinkRequest>(); request->SetNodeId(nodeId); auto response = WaitFor(session.ReadLink( PrepareCallContext(), std::move(request))); CheckResponse(response); return response.GetSymLink(); } //////////////////////////////////////////////////////////////////////////////// TEndpointCommand::TEndpointCommand() { } void TEndpointCommand::Init() { TCommand::Init(); Client = CreateDurableClient( Logging, Timer, Scheduler, CreateRetryPolicy(ClientConfig), CreateEndpointManagerClient( ClientConfig, Logging, CreateClientCertificateProvider(ClientConfig))); } void TEndpointCommand::Start() { TCommand::Start(); if (Client) { Client->Start(); } } void TEndpointCommand::Stop() { if (Client) { Client->Stop(); } TCommand::Stop(); } } // namespace NCloud::NFileStore::NClient