Skip to content

Commit 3381008

Browse files
Enjectionmregrockalexvru
authored
[stable-25-1] Distconf && New config api fixes (#15406)
Co-authored-by: mregrock <mregrock@ydb.tech> Co-authored-by: Alexander Rutkovsky <alexvru@ydb.tech>
1 parent 9e31b30 commit 3381008

File tree

11 files changed

+356
-50
lines changed

11 files changed

+356
-50
lines changed

ydb/apps/ydb/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
* Added support for dual configuration mode in the `ydb admin cluster config fetch` command, allowing it to handle separate cluster and storage config sections.
2+
* Add options for client certificates in SSL/TLS connections.
3+
* Add `ydb admin node config init` command to initialize directory with node config files.
4+
* Add `ydb admin cluster config generate` command to generate dynamic config from static config on cluster.
15
* Fixed memory leak in tpcds generator.
26
* Include external data sources and external tables in local backups (`ydb tools dump` and `ydb tools restore`). Both scheme objects are backed up as YQL creation queries saved in the `create_external_data_source.sql` and `create_external_table.sql` files respectively, which can be executed to recreate the original scheme objects.
37
* Fixed a bug where `ydb auth get-token` command tried to authenticate twice: while listing andpoints and while executing actual token request.

ydb/core/cms/console/console_configs_manager.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,24 @@ class TConfigsManager : public TActorBootstrapped<TConfigsManager> {
216216
HandleUnauthorized(ev, ctx);
217217
};
218218

219+
constexpr bool HasBypassAuth = std::is_same_v<
220+
std::decay_t<T>,
221+
typename TEvConsole::TEvGetAllConfigsRequest::TPtr
222+
> || std::is_same_v<
223+
std::decay_t<T>,
224+
typename TEvConsole::TEvReplaceYamlConfigRequest::TPtr
225+
> || std::is_same_v<
226+
std::decay_t<T>,
227+
typename TEvConsole::TEvSetYamlConfigRequest::TPtr
228+
>;
229+
230+
if constexpr (HasBypassAuth) {
231+
if (ev->Get()->Record.HasBypassAuth() && ev->Get()->Record.GetBypassAuth()) {
232+
Handle(ev, ctx);
233+
return;
234+
}
235+
}
236+
219237
if (IsAdministrator(AppData(ctx), ev->Get()->Record.GetUserToken())) {
220238
Handle(ev, ctx);
221239
} else {

ydb/core/cms/console/console_handshake.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class TConfigsManager::TConsoleCommitActor : public TActorBootstrapped<TConsoleC
3333

3434
void Bootstrap(const TActorId& consoleId) {
3535
auto executeRequest = [&](auto& request) {
36+
request->Record.SetBypassAuth(true);
3637
request->Record.MutableRequest()->set_config(MainYamlConfig);
3738
request->Record.MutableRequest()->set_allow_unknown_fields(AllowUnknownFields);
3839
Send(consoleId, request.release());

ydb/core/config/init/init_impl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,11 +1075,11 @@ class TInitialConfiguratorImpl
10751075
auto dir = fs::path(CommonAppOptions.ConfigDirPath.c_str());
10761076

10771077
if (auto path = dir / STORAGE_CONFIG_NAME; fs::is_regular_file(path)) {
1078-
storageYamlConfigFile = path.c_str();
1078+
storageYamlConfigFile = path.string();
10791079
}
10801080

10811081
if (auto path = dir / CONFIG_NAME; fs::is_regular_file(path)) {
1082-
yamlConfigFile = path.c_str();
1082+
yamlConfigFile = path.string();
10831083
loadedFromStore = true;
10841084
} else {
10851085
storageYamlConfigFile.clear();

ydb/core/grpc_services/rpc_config.cpp

Lines changed: 198 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
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

1517
namespace NKikimr::NGRpcService {
1618

@@ -136,10 +138,33 @@ void CopyFromConfigResponse(const NKikimrBlobStorage::TConfigResponse &from, Ydb
136138

137139
class 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+
if (!NKikimr::IsAdministrator(AppData(), Request_->GetSerializedToken())) {
160+
self->Reply(Ydb::StatusIds::UNAUTHORIZED, "User is not a cluster administrator.",
161+
NKikimrIssues::TIssuesIds::ACCESS_DENIED, self->ActorContext());
162+
return;
163+
}
164+
self->Become(&TReplaceStorageConfigRequest::StateFunc);
165+
self->Send(MakeBlobStorageNodeWardenID(ctx.SelfID.NodeId()), new TEvNodeWardenQueryStorageConfig(false));
166+
}
167+
143168
bool ValidateRequest(Ydb::StatusIds::StatusCode& status, NYql::TIssues& issues) override {
144169
const auto& request = *GetProtoRequest();
145170
if (request.dry_run()) {
@@ -207,13 +232,137 @@ class TReplaceStorageConfigRequest : public TBSConfigRequestGrpc<TReplaceStorage
207232
request->allow_unknown_fields() || request->bypass_checks(),
208233
request->bypass_checks());
209234
}
235+
236+
private:
237+
std::optional<TString> DatabaseConfig;
238+
std::optional<TString> TargetDatabase;
239+
240+
void CheckDatabaseAuthorization() {
241+
const auto& metadata = NYamlConfig::GetDatabaseMetadata(*DatabaseConfig);
242+
243+
if (metadata.Database) {
244+
TargetDatabase = metadata.Database;
245+
}
246+
else {
247+
Reply(Ydb::StatusIds::BAD_REQUEST, "No database name found in metadata",
248+
NKikimrIssues::TIssuesIds::DEFAULT_ERROR, ActorContext());
249+
return;
250+
}
251+
252+
if (*TargetDatabase == ("/" + AppData()->DomainsInfo->Domain->Name) ||
253+
*TargetDatabase == AppData()->DomainsInfo->Domain->Name) {
254+
Reply(Ydb::StatusIds::BAD_REQUEST, "Provided database is a domain database.",
255+
NKikimrIssues::TIssuesIds::DEFAULT_ERROR, ActorContext());
256+
return;
257+
}
258+
bool isAdministrator = NKikimr::IsAdministrator(AppData(), Request_->GetSerializedToken());
259+
if (!isAdministrator) {
260+
auto request = std::make_unique<NSchemeCache::TSchemeCacheNavigate>();
261+
request->DatabaseName = *TargetDatabase;
262+
263+
auto& entry = request->ResultSet.emplace_back();
264+
entry.Operation = NSchemeCache::TSchemeCacheNavigate::OpPath;
265+
entry.Path = NKikimr::SplitPath(*TargetDatabase);
266+
267+
auto* self = Self();
268+
self->Send(MakeSchemeCacheID(), new TEvTxProxySchemeCache::TEvNavigateKeySet(request.release()));
269+
self->Become(&TReplaceStorageConfigRequest::StateWaitResolveDatabase);
270+
return;
271+
}
272+
SendRequestToConsole();
273+
}
274+
275+
void SendRequestToConsole() {
276+
NTabletPipe::TClientConfig pipeConfig;
277+
pipeConfig.RetryPolicy = {
278+
.RetryLimitCount = 10,
279+
};
280+
auto pipe = NTabletPipe::CreateClient(SelfId(), MakeConsoleID(), pipeConfig);
281+
ConsolePipe = RegisterWithSameMailbox(pipe);
282+
283+
auto PrepareAndSendRequest = [&](auto requestType) {
284+
using TRequestType = decltype(requestType);
285+
auto request = std::make_unique<TRequestType>();
286+
request->Record.SetUserToken(Request_->GetSerializedToken());
287+
request->Record.SetPeerName(Request_->GetPeerName());
288+
request->Record.SetIngressDatabase(*TargetDatabase);
289+
290+
auto& req = *request->Record.MutableRequest();
291+
req.set_config(*DatabaseConfig);
292+
293+
request->Record.SetBypassAuth(true);
294+
NTabletPipe::SendData(SelfId(), ConsolePipe, request.release());
295+
};
296+
297+
if (GetProtoRequest()->bypass_checks()) {
298+
PrepareAndSendRequest(NConsole::TEvConsole::TEvSetYamlConfigRequest());
299+
} else {
300+
PrepareAndSendRequest(NConsole::TEvConsole::TEvReplaceYamlConfigRequest());
301+
}
302+
Self()->Become(&TReplaceStorageConfigRequest::StateConsoleReplaceFunc);
303+
}
304+
305+
STFUNC(StateWaitResolveDatabase) {
306+
switch (ev->GetTypeRewrite()) {
307+
hFunc(TEvTxProxySchemeCache::TEvNavigateKeySetResult, HandleResolveDatabase);
308+
default:
309+
return TBase::StateFuncBase(ev);
310+
}
311+
}
312+
313+
void HandleResolveDatabase(TEvTxProxySchemeCache::TEvNavigateKeySetResult::TPtr& ev) {
314+
const NSchemeCache::TSchemeCacheNavigate& request = *ev->Get()->Request.Get();
315+
auto *self = Self();
316+
if (request.ResultSet.empty() || request.ErrorCount > 0) {
317+
self->Reply(Ydb::StatusIds::SCHEME_ERROR, "Error resolving database",
318+
NKikimrIssues::TIssuesIds::GENERIC_RESOLVE_ERROR, self->ActorContext());
319+
return;
320+
}
321+
322+
const auto& entry = request.ResultSet.front();
323+
const auto& databaseOwner = entry.Self->Info.GetOwner();
324+
325+
NACLibProto::TUserToken tokenPb;
326+
if (!tokenPb.ParseFromString(Request_->GetSerializedToken())) {
327+
tokenPb = NACLibProto::TUserToken();
328+
}
329+
const auto& parsedToken = NACLib::TUserToken(tokenPb);
330+
331+
bool isDatabaseAdmin = NKikimr::IsDatabaseAdministrator(&parsedToken, databaseOwner);
332+
if (!isDatabaseAdmin) {
333+
self->Reply(Ydb::StatusIds::UNAUTHORIZED, "User is not a database administrator.",
334+
NKikimrIssues::TIssuesIds::ACCESS_DENIED, self->ActorContext());
335+
return;
336+
}
337+
SendRequestToConsole();
338+
}
339+
340+
STFUNC(StateConsoleReplaceFunc) {
341+
switch (ev->GetTypeRewrite()) {
342+
hFunc(NConsole::TEvConsole::TEvReplaceYamlConfigResponse, Handle);
343+
hFunc(NConsole::TEvConsole::TEvSetYamlConfigResponse, Handle);
344+
default:
345+
return StateConsoleFunc(ev);
346+
}
347+
}
348+
349+
void Handle(NConsole::TEvConsole::TEvReplaceYamlConfigResponse::TPtr& ev) {
350+
auto* self = Self();
351+
self->Reply(Ydb::StatusIds::SUCCESS, ev->Get()->Record.GetIssues(), self->ActorContext());
352+
}
353+
354+
void Handle(NConsole::TEvConsole::TEvSetYamlConfigResponse::TPtr& ev) {
355+
auto* self = Self();
356+
self->Reply(Ydb::StatusIds::SUCCESS, ev->Get()->Record.GetIssues(), self->ActorContext());
357+
}
210358
};
211359

212360
class TFetchStorageConfigRequest : public TBSConfigRequestGrpc<TFetchStorageConfigRequest, TEvFetchStorageConfigRequest,
213361
Ydb::Config::FetchConfigResult> {
214362
public:
215363
using TBase = TBSConfigRequestGrpc<TFetchStorageConfigRequest, TEvFetchStorageConfigRequest, Ydb::Config::FetchConfigResult>;
216364
using TBase::TBase;
365+
using TRpcBase = TRpcOperationRequestActor<TFetchStorageConfigRequest, TEvFetchStorageConfigRequest>;
217366

218367
bool ValidateRequest(Ydb::StatusIds::StatusCode& status, NYql::TIssues& issues) override {
219368
const auto& request = *GetProtoRequest();
@@ -229,6 +378,20 @@ class TFetchStorageConfigRequest : public TBSConfigRequestGrpc<TFetchStorageConf
229378
return NACLib::GenericManage;
230379
}
231380

381+
void Bootstrap(const TActorContext &ctx) {
382+
TRpcBase::Bootstrap(ctx);
383+
auto *self = Self();
384+
self->OnBootstrap();
385+
386+
if (self->Request_->GetDatabaseName()) {
387+
SendRequestToConsole();
388+
return;
389+
}
390+
391+
self->Become(&TFetchStorageConfigRequest::StateFunc);
392+
self->Send(MakeBlobStorageNodeWardenID(ctx.SelfID.NodeId()), new TEvNodeWardenQueryStorageConfig(false));
393+
}
394+
232395
void FillDistconfQuery(NStorage::TEvNodeConfigInvokeOnRoot& ev) const {
233396
auto *record = ev.Record.MutableFetchStorageConfig();
234397

@@ -300,6 +463,39 @@ class TFetchStorageConfigRequest : public TBSConfigRequestGrpc<TFetchStorageConf
300463

301464
return ev;
302465
}
466+
467+
private:
468+
void SendRequestToConsole() {
469+
NTabletPipe::TClientConfig pipeConfig;
470+
pipeConfig.RetryPolicy = {
471+
.RetryLimitCount = 10,
472+
};
473+
auto pipe = NTabletPipe::CreateClient(SelfId(), MakeConsoleID(), pipeConfig);
474+
ConsolePipe = RegisterWithSameMailbox(pipe);
475+
476+
auto request = std::make_unique<NConsole::TEvConsole::TEvGetAllConfigsRequest>();
477+
request->Record.SetUserToken(Request_->GetSerializedToken());
478+
request->Record.SetPeerName(Request_->GetPeerName());
479+
if (Request_->GetDatabaseName()) {
480+
request->Record.SetIngressDatabase(*Request_->GetDatabaseName());
481+
}
482+
request->Record.SetBypassAuth(true);
483+
484+
NTabletPipe::SendData(SelfId(), ConsolePipe, request.release());
485+
Self()->Become(&TFetchStorageConfigRequest::StateConsoleFetchFunc);
486+
}
487+
488+
STFUNC(StateConsoleFetchFunc) {
489+
switch (ev->GetTypeRewrite()) {
490+
hFunc(NConsole::TEvConsole::TEvGetAllConfigsResponse, Handle);
491+
default:
492+
return StateConsoleFunc(ev);
493+
}
494+
}
495+
496+
void Handle(NConsole::TEvConsole::TEvGetAllConfigsResponse::TPtr& ev) {
497+
ReplyWithResult(Ydb::StatusIds::SUCCESS, ev->Get()->Record.GetResponse(), ActorContext());
498+
}
303499
};
304500

305501
void DoReplaceConfig(std::unique_ptr<IRequestOpCtx> p, const IFacilityProvider&) {
@@ -372,3 +568,4 @@ void DoBootstrapCluster(std::unique_ptr<IRequestOpCtx> p, const IFacilityProvide
372568
}
373569

374570
} // namespace NKikimr::NGRpcService
571+

ydb/core/grpc_services/rpc_config_base.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <ydb/core/ydb_convert/ydb_convert.h>
1616
#include <ydb-cpp-sdk/library/operation_id/operation_id.h>
1717
#include <ydb-cpp-sdk/client/resources/ydb_resources.h>
18+
#include <ydb/core/cms/console/console.h>
1819

1920
namespace NKikimr::NGRpcService {
2021

@@ -351,6 +352,37 @@ class TBSConfigRequestGrpc : public TRpcOperationRequestActor<TDerived, TRequest
351352
NKikimrIssues::TIssuesIds::SHARD_NOT_AVAILABLE, self->ActorContext());
352353
}
353354

355+
TActorId ConsolePipe;
356+
357+
STFUNC(StateConsoleFunc) {
358+
switch (ev->GetTypeRewrite()) {
359+
hFunc(NConsole::TEvConsole::TEvGenericError, HandleConsole);
360+
hFunc(TEvTabletPipe::TEvClientDestroyed, HandleConsole);
361+
hFunc(TEvTabletPipe::TEvClientConnected, HandleConsole);
362+
default:
363+
return TBase::StateFuncBase(ev);
364+
}
365+
}
366+
367+
void HandleConsole(NConsole::TEvConsole::TEvGenericError::TPtr& ev) {
368+
auto *self = Self();
369+
self->Reply(ev->Get()->Record.GetYdbStatus(), ev->Get()->Record.GetIssues(), self->ActorContext());
370+
}
371+
372+
void HandleConsole(TEvTabletPipe::TEvClientDestroyed::TPtr&) {
373+
auto *self = Self();
374+
self->Reply(Ydb::StatusIds::UNAVAILABLE, "Connection to Console was lost",
375+
NKikimrIssues::TIssuesIds::SHARD_NOT_AVAILABLE, self->ActorContext());
376+
}
377+
378+
void HandleConsole(TEvTabletPipe::TEvClientConnected::TPtr& ev) {
379+
if (ev->Get()->Status != NKikimrProto::OK) {
380+
auto *self = Self();
381+
self->Reply(Ydb::StatusIds::UNAVAILABLE, "Failed to connect to Console",
382+
NKikimrIssues::TIssuesIds::SHARD_NOT_AVAILABLE, self->ActorContext());
383+
}
384+
}
385+
354386
virtual bool ValidateRequest(Ydb::StatusIds::StatusCode& status, NYql::TIssues& issues) = 0;
355387
virtual std::unique_ptr<IEventBase> ProcessControllerQuery() = 0;
356388

ydb/core/mind/bscontroller/console_interaction.cpp

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,14 +277,34 @@ namespace NKikimr::NBsController {
277277
PendingYamlConfig.reset();
278278
}
279279

280-
if (PendingYamlConfig && !NYamlConfig::IsMainConfig(*PendingYamlConfig)) {
281-
return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest,
282-
"cluster YAML config is not of MainConfig kind");
280+
if (PendingYamlConfig) {
281+
const ui64 expected = Self.YamlConfig
282+
? GetVersion(*Self.YamlConfig) + 1
283+
: 0;
284+
285+
if (!NYamlConfig::IsMainConfig(*PendingYamlConfig)) {
286+
return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest,
287+
"cluster YAML config is not of MainConfig kind");
288+
} else if (const auto& meta = NYamlConfig::GetMainMetadata(*PendingYamlConfig); meta.Version != expected) {
289+
return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest,
290+
TStringBuilder() << "cluster YAML config version mismatch got# " << meta.Version
291+
<< " expected# " << expected);
292+
}
283293
}
284294

285-
if (PendingStorageYamlConfig && *PendingStorageYamlConfig && !NYamlConfig::IsStorageConfig(**PendingStorageYamlConfig)) {
286-
return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest,
287-
"storage YAML config is not of StorageConfig kind");
295+
if (PendingStorageYamlConfig && *PendingStorageYamlConfig) {
296+
const ui64 expected = Self.StorageYamlConfig
297+
? Self.StorageYamlConfigVersion + 1
298+
: 0;
299+
300+
if (!NYamlConfig::IsStorageConfig(**PendingStorageYamlConfig)) {
301+
return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest,
302+
"storage YAML config is not of StorageConfig kind");
303+
} else if (const auto& meta = NYamlConfig::GetStorageMetadata(**PendingStorageYamlConfig); meta.Version != expected) {
304+
return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest,
305+
TStringBuilder() << "storage YAML config version mismatch got# " << meta.Version
306+
<< " expected# " << expected);
307+
}
288308
}
289309

290310
if (record.GetSkipConsoleValidation() || !record.HasClusterYaml()) {

0 commit comments

Comments
 (0)