1111#include < ydb/core/protos/local.pb.h>
1212#include < ydb/core/blobstorage/nodewarden/node_warden_events.h>
1313#include < ydb/core/base/auth.h>
14+ #include < ydb/core/cms/console/console.h>
15+ #include < ydb/core/cms/console/configs_dispatcher.h>
1416
1517namespace NKikimr ::NGRpcService {
1618
@@ -136,10 +138,28 @@ void CopyFromConfigResponse(const NKikimrBlobStorage::TConfigResponse &from, Ydb
136138
137139class TReplaceStorageConfigRequest : public TBSConfigRequestGrpc <TReplaceStorageConfigRequest, TEvReplaceStorageConfigRequest,
138140 Ydb::Config::ReplaceConfigResult> {
139- public:
140141 using TBase = TBSConfigRequestGrpc<TReplaceStorageConfigRequest, TEvReplaceStorageConfigRequest, Ydb::Config::ReplaceConfigResult>;
142+ using TRpcBase = TRpcOperationRequestActor<TReplaceStorageConfigRequest, TEvReplaceStorageConfigRequest>;
143+ public:
141144 using TBase::TBase;
142145
146+ void Bootstrap (const TActorContext& ctx) {
147+ TRpcBase::Bootstrap (ctx);
148+ auto *self = Self ();
149+ self->OnBootstrap ();
150+ const auto & request = *GetProtoRequest ();
151+ auto shim = ConvertConfigReplaceRequest (request);
152+ if (shim.MainConfig ) {
153+ if (NYamlConfig::IsDatabaseConfig (*shim.MainConfig )) {
154+ DatabaseConfig = shim.MainConfig ;
155+ CheckDatabaseAuthorization ();
156+ return ;
157+ }
158+ }
159+ self->Become (&TReplaceStorageConfigRequest::StateFunc);
160+ self->Send (MakeBlobStorageNodeWardenID (ctx.SelfID .NodeId ()), new TEvNodeWardenQueryStorageConfig (false ));
161+ }
162+
143163 bool ValidateRequest (Ydb::StatusIds::StatusCode& status, NYql::TIssues& issues) override {
144164 const auto & request = *GetProtoRequest ();
145165 if (request.dry_run ()) {
@@ -207,13 +227,137 @@ class TReplaceStorageConfigRequest : public TBSConfigRequestGrpc<TReplaceStorage
207227 request->allow_unknown_fields () || request->bypass_checks (),
208228 request->bypass_checks ());
209229 }
230+
231+ private:
232+ std::optional<TString> DatabaseConfig;
233+ std::optional<TString> TargetDatabase;
234+
235+ void CheckDatabaseAuthorization () {
236+ const auto & metadata = NYamlConfig::GetDatabaseMetadata (*DatabaseConfig);
237+
238+ if (metadata.Database ) {
239+ TargetDatabase = metadata.Database ;
240+ }
241+ else {
242+ Reply (Ydb::StatusIds::BAD_REQUEST, " No database name found in metadata" ,
243+ NKikimrIssues::TIssuesIds::DEFAULT_ERROR, ActorContext ());
244+ return ;
245+ }
246+
247+ if (*TargetDatabase == (" /" + AppData ()->DomainsInfo ->Domain ->Name ) ||
248+ *TargetDatabase == AppData ()->DomainsInfo ->Domain ->Name ) {
249+ Reply (Ydb::StatusIds::BAD_REQUEST, " Provided database is a domain database." ,
250+ NKikimrIssues::TIssuesIds::DEFAULT_ERROR, ActorContext ());
251+ return ;
252+ }
253+ bool isAdministrator = NKikimr::IsAdministrator (AppData (), Request_->GetSerializedToken ());
254+ if (!isAdministrator) {
255+ auto request = std::make_unique<NSchemeCache::TSchemeCacheNavigate>();
256+ request->DatabaseName = *TargetDatabase;
257+
258+ auto & entry = request->ResultSet .emplace_back ();
259+ entry.Operation = NSchemeCache::TSchemeCacheNavigate::OpPath;
260+ entry.Path = NKikimr::SplitPath (*TargetDatabase);
261+
262+ auto * self = Self ();
263+ self->Send (MakeSchemeCacheID (), new TEvTxProxySchemeCache::TEvNavigateKeySet (request.release ()));
264+ self->Become (&TReplaceStorageConfigRequest::StateWaitResolveDatabase);
265+ return ;
266+ }
267+ SendRequestToConsole ();
268+ }
269+
270+ void SendRequestToConsole () {
271+ NTabletPipe::TClientConfig pipeConfig;
272+ pipeConfig.RetryPolicy = {
273+ .RetryLimitCount = 10 ,
274+ };
275+ auto pipe = NTabletPipe::CreateClient (SelfId (), MakeConsoleID (), pipeConfig);
276+ ConsolePipe = RegisterWithSameMailbox (pipe);
277+
278+ auto PrepareAndSendRequest = [&](auto requestType) {
279+ using TRequestType = decltype (requestType);
280+ auto request = std::make_unique<TRequestType>();
281+ request->Record .SetUserToken (Request_->GetSerializedToken ());
282+ request->Record .SetPeerName (Request_->GetPeerName ());
283+ request->Record .SetIngressDatabase (*TargetDatabase);
284+
285+ auto & req = *request->Record .MutableRequest ();
286+ req.set_config (*DatabaseConfig);
287+
288+ request->Record .SetBypassAuth (true );
289+ NTabletPipe::SendData (SelfId (), ConsolePipe, request.release ());
290+ };
291+
292+ if (GetProtoRequest ()->bypass_checks ()) {
293+ PrepareAndSendRequest (NConsole::TEvConsole::TEvSetYamlConfigRequest ());
294+ } else {
295+ PrepareAndSendRequest (NConsole::TEvConsole::TEvReplaceYamlConfigRequest ());
296+ }
297+ Self ()->Become (&TReplaceStorageConfigRequest::StateConsoleReplaceFunc);
298+ }
299+
300+ STFUNC (StateWaitResolveDatabase) {
301+ switch (ev->GetTypeRewrite ()) {
302+ hFunc (TEvTxProxySchemeCache::TEvNavigateKeySetResult, HandleResolveDatabase);
303+ default :
304+ return TBase::StateFuncBase (ev);
305+ }
306+ }
307+
308+ void HandleResolveDatabase (TEvTxProxySchemeCache::TEvNavigateKeySetResult::TPtr& ev) {
309+ const NSchemeCache::TSchemeCacheNavigate& request = *ev->Get ()->Request .Get ();
310+ auto *self = Self ();
311+ if (request.ResultSet .empty () || request.ErrorCount > 0 ) {
312+ self->Reply (Ydb::StatusIds::SCHEME_ERROR, " Error resolving database" ,
313+ NKikimrIssues::TIssuesIds::GENERIC_RESOLVE_ERROR, self->ActorContext ());
314+ return ;
315+ }
316+
317+ const auto & entry = request.ResultSet .front ();
318+ const auto & databaseOwner = entry.Self ->Info .GetOwner ();
319+
320+ NACLibProto::TUserToken tokenPb;
321+ if (!tokenPb.ParseFromString (Request_->GetSerializedToken ())) {
322+ tokenPb = NACLibProto::TUserToken ();
323+ }
324+ const auto & parsedToken = NACLib::TUserToken (tokenPb);
325+
326+ bool isDatabaseAdmin = NKikimr::IsDatabaseAdministrator (&parsedToken, databaseOwner);
327+ if (!isDatabaseAdmin) {
328+ self->Reply (Ydb::StatusIds::UNAUTHORIZED, " User is not a database administrator." ,
329+ NKikimrIssues::TIssuesIds::ACCESS_DENIED, self->ActorContext ());
330+ return ;
331+ }
332+ SendRequestToConsole ();
333+ }
334+
335+ STFUNC (StateConsoleReplaceFunc) {
336+ switch (ev->GetTypeRewrite ()) {
337+ hFunc (NConsole::TEvConsole::TEvReplaceYamlConfigResponse, Handle);
338+ hFunc (NConsole::TEvConsole::TEvSetYamlConfigResponse, Handle);
339+ default :
340+ return StateConsoleFunc (ev);
341+ }
342+ }
343+
344+ void Handle (NConsole::TEvConsole::TEvReplaceYamlConfigResponse::TPtr& ev) {
345+ auto * self = Self ();
346+ self->Reply (Ydb::StatusIds::SUCCESS, ev->Get ()->Record .GetIssues (), self->ActorContext ());
347+ }
348+
349+ void Handle (NConsole::TEvConsole::TEvSetYamlConfigResponse::TPtr& ev) {
350+ auto * self = Self ();
351+ self->Reply (Ydb::StatusIds::SUCCESS, ev->Get ()->Record .GetIssues (), self->ActorContext ());
352+ }
210353};
211354
212355class TFetchStorageConfigRequest : public TBSConfigRequestGrpc <TFetchStorageConfigRequest, TEvFetchStorageConfigRequest,
213356 Ydb::Config::FetchConfigResult> {
214357public:
215358 using TBase = TBSConfigRequestGrpc<TFetchStorageConfigRequest, TEvFetchStorageConfigRequest, Ydb::Config::FetchConfigResult>;
216359 using TBase::TBase;
360+ using TRpcBase = TRpcOperationRequestActor<TFetchStorageConfigRequest, TEvFetchStorageConfigRequest>;
217361
218362 bool ValidateRequest (Ydb::StatusIds::StatusCode& status, NYql::TIssues& issues) override {
219363 const auto & request = *GetProtoRequest ();
@@ -229,6 +373,20 @@ class TFetchStorageConfigRequest : public TBSConfigRequestGrpc<TFetchStorageConf
229373 return NACLib::GenericManage;
230374 }
231375
376+ void Bootstrap (const TActorContext &ctx) {
377+ TRpcBase::Bootstrap (ctx);
378+ auto *self = Self ();
379+ self->OnBootstrap ();
380+
381+ if (self->Request_ ->GetDatabaseName ()) {
382+ SendRequestToConsole ();
383+ return ;
384+ }
385+
386+ self->Become (&TFetchStorageConfigRequest::StateFunc);
387+ self->Send (MakeBlobStorageNodeWardenID (ctx.SelfID .NodeId ()), new TEvNodeWardenQueryStorageConfig (false ));
388+ }
389+
232390 void FillDistconfQuery (NStorage::TEvNodeConfigInvokeOnRoot& ev) const {
233391 auto *record = ev.Record .MutableFetchStorageConfig ();
234392
@@ -300,6 +458,39 @@ class TFetchStorageConfigRequest : public TBSConfigRequestGrpc<TFetchStorageConf
300458
301459 return ev;
302460 }
461+
462+ private:
463+ void SendRequestToConsole () {
464+ NTabletPipe::TClientConfig pipeConfig;
465+ pipeConfig.RetryPolicy = {
466+ .RetryLimitCount = 10 ,
467+ };
468+ auto pipe = NTabletPipe::CreateClient (SelfId (), MakeConsoleID (), pipeConfig);
469+ ConsolePipe = RegisterWithSameMailbox (pipe);
470+
471+ auto request = std::make_unique<NConsole::TEvConsole::TEvGetAllConfigsRequest>();
472+ request->Record .SetUserToken (Request_->GetSerializedToken ());
473+ request->Record .SetPeerName (Request_->GetPeerName ());
474+ if (Request_->GetDatabaseName ()) {
475+ request->Record .SetIngressDatabase (*Request_->GetDatabaseName ());
476+ }
477+ request->Record .SetBypassAuth (true );
478+
479+ NTabletPipe::SendData (SelfId (), ConsolePipe, request.release ());
480+ Self ()->Become (&TFetchStorageConfigRequest::StateConsoleFetchFunc);
481+ }
482+
483+ STFUNC (StateConsoleFetchFunc) {
484+ switch (ev->GetTypeRewrite ()) {
485+ hFunc (NConsole::TEvConsole::TEvGetAllConfigsResponse, Handle);
486+ default :
487+ return StateConsoleFunc (ev);
488+ }
489+ }
490+
491+ void Handle (NConsole::TEvConsole::TEvGetAllConfigsResponse::TPtr& ev) {
492+ ReplyWithResult (Ydb::StatusIds::SUCCESS, ev->Get ()->Record .GetResponse (), ActorContext ());
493+ }
303494};
304495
305496void DoReplaceConfig (std::unique_ptr<IRequestOpCtx> p, const IFacilityProvider&) {
@@ -372,3 +563,4 @@ void DoBootstrapCluster(std::unique_ptr<IRequestOpCtx> p, const IFacilityProvide
372563}
373564
374565} // namespace NKikimr::NGRpcService
566+
0 commit comments