Skip to content

Commit b42ca36

Browse files
author
Aleksandr Usenko
committed
Backport YDB #41434
1 parent 8b01a90 commit b42ca36

5 files changed

Lines changed: 433 additions & 7 deletions

File tree

contrib/ydb/core/cms/console/console__get_yaml_config.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ class TConfigsManager::TTxGetYamlConfig : public TTransactionBase<TConfigsManage
4040
Response->Record.MutableResponse()->add_config(Self->MainYamlConfig);
4141

4242
for (const auto& [database, config] : Self->DatabaseYamlConfigs) {
43-
Response->Record.MutableResponse()->add_identity()->set_database(database);
44-
Response->Record.MutableResponse()->add_identity()->set_version(config.Version);
43+
auto& dbIdentity = *Response->Record.MutableResponse()->add_identity();
44+
dbIdentity.set_database(database);
45+
dbIdentity.set_version(config.Version);
4546
Response->Record.MutableResponse()->add_config(config.Config);
4647
}
4748

contrib/ydb/core/grpc_services/rpc_config.cpp

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,127 @@
1313
#include <contrib/ydb/core/base/auth.h>
1414
#include <contrib/ydb/core/cms/console/console.h>
1515
#include <contrib/ydb/core/cms/console/configs_dispatcher.h>
16+
#include <contrib/ydb/library/services/services.pb.h>
17+
18+
namespace {
19+
20+
TString DescribeConfigIdentity(const Ydb::DynamicConfig::ConfigIdentity& id)
21+
{
22+
TStringBuilder descr;
23+
24+
switch (id.type_case()) {
25+
case Ydb::DynamicConfig::ConfigIdentity::TypeCase::kCluster:
26+
descr << "cluster=" << id.cluster();
27+
break;
28+
case Ydb::DynamicConfig::ConfigIdentity::TypeCase::kDatabase:
29+
descr << "database=" << id.database();
30+
break;
31+
case Ydb::DynamicConfig::ConfigIdentity::TypeCase::TYPE_NOT_SET:
32+
descr << "<TYPE_NOT_SET>";
33+
break;
34+
default:
35+
descr << "<unknown-type:" << static_cast<int>(id.type_case()) << ">";
36+
break;
37+
}
38+
39+
descr << ";version=" << id.version();
40+
41+
return descr;
42+
}
43+
44+
bool ConvertGetConfigToFetchConfigResult(
45+
const Ydb::DynamicConfig::GetConfigResult &from,
46+
Ydb::Config::FetchConfigResult &to,
47+
TString& error)
48+
{
49+
const auto identityCount = from.identity_size();
50+
const auto configCount = from.config_size();
51+
52+
error.clear();
53+
54+
// Reject Ydb::DynamicConfig::GetConfigResult invariant violation
55+
if (identityCount < configCount) {
56+
TStringBuilder descr;
57+
descr << (configCount - identityCount)
58+
<< " extra 'config' field with no corresponding 'identity' field";
59+
error = descr;
60+
return false;
61+
}
62+
if (identityCount > configCount) {
63+
TStringBuilder descr;
64+
descr << "no 'config' fields for 'identity' fields [";
65+
for (int i = configCount; i < identityCount; i++) {
66+
if (i > configCount) {
67+
descr << ", ";
68+
}
69+
descr << "'" << DescribeConfigIdentity(from.identity(i)) << "'";
70+
}
71+
descr << "]";
72+
error = descr;
73+
return false;
74+
}
75+
76+
// Reject TYPE_NOT_SET upfront so the error path leaves 'to' untouched
77+
{
78+
TStringBuilder descr;
79+
int unsetCount = 0;
80+
81+
descr << "'identity' fields with no type set at indices [";
82+
for (int i = 0; i < identityCount; i++) {
83+
if (from.identity(i).type_case()
84+
== Ydb::DynamicConfig::ConfigIdentity::TypeCase::TYPE_NOT_SET)
85+
{
86+
if (unsetCount > 0) {
87+
descr << ", ";
88+
}
89+
descr << "#" << i << " - " << "'" << DescribeConfigIdentity(from.identity(i)) << "'";
90+
++unsetCount;
91+
}
92+
}
93+
descr << "]";
94+
95+
if (unsetCount > 0) {
96+
error = descr;
97+
return false;
98+
}
99+
}
100+
101+
for (int i = 0; i < identityCount; i++) {
102+
const auto& srcIdentity = from.identity(i);
103+
switch (srcIdentity.type_case()) {
104+
case Ydb::DynamicConfig::ConfigIdentity::TypeCase::kCluster: {
105+
auto dstEntry = to.add_config();
106+
auto dstIdentity = dstEntry->mutable_identity();
107+
dstIdentity->set_version(srcIdentity.version());
108+
dstIdentity->set_cluster(srcIdentity.cluster());
109+
dstIdentity->mutable_main();
110+
dstEntry->set_config(from.config(i));
111+
break;
112+
}
113+
case Ydb::DynamicConfig::ConfigIdentity::TypeCase::kDatabase: {
114+
auto dstEntry = to.add_config();
115+
auto dstIdentity = dstEntry->mutable_identity();
116+
dstIdentity->set_version(srcIdentity.version());
117+
dstIdentity->mutable_database()->set_database(srcIdentity.database());
118+
dstEntry->set_config(from.config(i));
119+
break;
120+
}
121+
case Ydb::DynamicConfig::ConfigIdentity::TypeCase::TYPE_NOT_SET:
122+
// TYPE_NOT_SET is rejected with error by pre-validation above
123+
break;
124+
default:
125+
// Any other value comes from a newer Console is skipped with a warning
126+
// so we don't fail on forward-compatible additions
127+
ALOG_NOTICE(NKikimrServices::GRPC_SERVER,
128+
"Convert Ydb::DynamicConfig::ConfigIdentity to Ydb::Config::FetchConfigResult: "
129+
<< "skipped unknown config identity '" << DescribeConfigIdentity(srcIdentity) << "'" );
130+
break;
131+
}
132+
}
133+
return true;
134+
}
135+
136+
} // namespace
16137

17138
namespace NKikimr::NGRpcService {
18139

@@ -403,6 +524,8 @@ class TFetchStorageConfigRequest : public TBSConfigRequestGrpc<TFetchStorageConf
403524
self->OnBootstrap();
404525

405526
if (self->Request_->GetDatabaseName()) {
527+
// Database YAML config (Ydb::DynamicConfig::ConfigIdentity::TypeCase::kDatabase)
528+
// is requested directly from Console (like legacy API)
406529
SendRequestToConsole();
407530
return;
408531
}
@@ -513,7 +636,19 @@ class TFetchStorageConfigRequest : public TBSConfigRequestGrpc<TFetchStorageConf
513636
}
514637

515638
void Handle(NConsole::TEvConsole::TEvGetAllConfigsResponse::TPtr& ev) {
516-
ReplyWithResult(Ydb::StatusIds::SUCCESS, ev->Get()->Record.GetResponse(), ActorContext());
639+
Ydb::Config::FetchConfigResult result;
640+
TString error;
641+
642+
bool succeed = ConvertGetConfigToFetchConfigResult(ev->Get()->Record.GetResponse(), result, error);
643+
if (succeed) {
644+
ReplyWithResult(Ydb::StatusIds::SUCCESS, result, ActorContext());
645+
}
646+
else {
647+
// The malformed payload comes from the Console tablet (server-side),
648+
// not from the gRPC client — so this is an internal-error condition.
649+
Reply(Ydb::StatusIds::INTERNAL_ERROR, error,
650+
NKikimrIssues::TIssuesIds::DEFAULT_ERROR, ActorContext());
651+
}
517652
}
518653
};
519654

contrib/ydb/library/yaml_config/public/yaml_config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ TString ReplaceMetadata(const TString& config, const TMainMetadata& metadata);
251251
TString UpgradeMainConfigVersion(const TString& config);
252252

253253
/**
254-
* Takes valid MainConfig and increases version exactly by one
254+
* Takes valid StorageConfig and increases version exactly by one
255255
*/
256256
TString UpgradeStorageConfigVersion(const TString& config);
257257

contrib/ydb/public/lib/ydb_cli/commands/ydb_dynamic_config.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ int TCommandConfigFetch::Run(TConfig& config) {
155155
NStatusHelpers::ThrowOnErrorOrPrintIssues(result);
156156
TString clusterConfig;
157157
TString storageConfig;
158+
TString databaseConfig;
158159

159160
for (const auto& entry : result.GetConfigs()) {
160161
std::visit([&](auto&& arg) {
@@ -167,6 +168,8 @@ int TCommandConfigFetch::Run(TConfig& config) {
167168
if (DedicatedStorageSection || !DedicatedClusterSection) {
168169
storageConfig = entry.Config;
169170
}
171+
} else if constexpr (std::is_same_v<T, NYdb::NConfig::TDatabaseConfigIdentity>) {
172+
databaseConfig = entry.Config;
170173
}
171174
}, entry.Identity);
172175
}
@@ -182,7 +185,9 @@ int TCommandConfigFetch::Run(TConfig& config) {
182185
// and will get attention that something went horribly wrong
183186
Cerr << "Unable to bump main config version, returning as-is" << Endl;
184187
}
185-
if (!storageConfig.empty() || DedicatedStorageSection) {
188+
if (!storageConfig.empty() || !databaseConfig.empty() ||
189+
DedicatedStorageSection)
190+
{
186191
Cerr << "cluster config: " << Endl;
187192
}
188193
Cout << clusterConfig << Endl;
@@ -198,13 +203,36 @@ int TCommandConfigFetch::Run(TConfig& config) {
198203
// and will get attention that something went horribly wrong
199204
Cerr << "Unable to bump storage config version, returning as-is" << Endl;
200205
}
201-
if (!clusterConfig.empty() || DedicatedClusterSection) {
206+
if (!clusterConfig.empty() || !databaseConfig.empty() ||
207+
DedicatedClusterSection)
208+
{
202209
Cerr << "storage config:" << Endl;
203210
}
204211
Cout << storageConfig << Endl;
205212
}
206213

207-
if (clusterConfig.empty() && storageConfig.empty()) {
214+
if (!databaseConfig.empty()) {
215+
// NOTE: there is no native new-API path for per-database YAML config fetch yet —
216+
// the request is routed through Console via the legacy API (see
217+
// TFetchStorageConfigRequest::Bootstrap() in rpc_config.cpp).
218+
// Console's contract for per-database YAML config replace is
219+
// wire metadata.version == stored version, so the CLI must return the fetched
220+
// body as-is. Bumping metadata.version here would break the next
221+
// fetch | edit | replace round-trip — the user would have to manually fix
222+
// the version before re-submitting. Once a native new-API path lands,
223+
// this branch can mirror the cluster/storage branches and call
224+
// UpgradeDatabaseConfigVersion.
225+
226+
if (!clusterConfig.empty() || !storageConfig.empty() ||
227+
DedicatedStorageSection || DedicatedClusterSection)
228+
{
229+
Cerr << "database config:" << Endl;
230+
}
231+
Cout << databaseConfig << Endl;
232+
}
233+
234+
if (clusterConfig.empty() && storageConfig.empty() && databaseConfig.empty())
235+
{
208236
Cerr << "No config returned." << Endl;
209237
return EXIT_FAILURE;
210238
}

0 commit comments

Comments
 (0)