Skip to content

Commit 74f3150

Browse files
authored
Add options deprecation support to dynconfig (#7162)
1 parent f186ded commit 74f3150

File tree

11 files changed

+132
-28
lines changed

11 files changed

+132
-28
lines changed

ydb/core/cms/console/console__replace_yaml_config.cpp

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ class TConfigsManager::TTxReplaceYamlConfig : public TTransactionBase<TConfigsMa
7676
.Cluster = Cluster,
7777
});
7878

79+
bool hasForbiddenUnknown = false;
80+
81+
TMap<TString, std::pair<TString, TString>> deprecatedFields;
82+
TMap<TString, std::pair<TString, TString>> unknownFields;
83+
7984
if (UpdatedConfig != Self->YamlConfig || Self->YamlDropped) {
8085
Modify = true;
8186

@@ -90,19 +95,29 @@ class TConfigsManager::TTxReplaceYamlConfig : public TTransactionBase<TConfigsMa
9095
ythrow yexception() << "Version mismatch";
9196
}
9297

93-
if (AllowUnknownFields) {
94-
UnknownFieldsCollector = new NYamlConfig::TBasicUnknownFieldsCollector;
95-
}
98+
UnknownFieldsCollector = new NYamlConfig::TBasicUnknownFieldsCollector;
9699

97100
for (auto& [_, config] : resolved.Configs) {
98101
auto cfg = NYamlConfig::YamlToProto(
99102
config.second,
100-
AllowUnknownFields,
103+
true,
101104
true,
102105
UnknownFieldsCollector);
103106
}
104107

105-
if (!DryRun) {
108+
const auto& deprecatedPaths = NKikimrConfig::TAppConfig::GetReservedChildrenPaths();
109+
110+
for (const auto& [path, info] : UnknownFieldsCollector->GetUnknownKeys()) {
111+
if (deprecatedPaths.contains(path)) {
112+
deprecatedFields[path] = info;
113+
} else {
114+
unknownFields[path] = info;
115+
}
116+
}
117+
118+
hasForbiddenUnknown = !unknownFields.empty() && !AllowUnknownFields;
119+
120+
if (!DryRun && !hasForbiddenUnknown) {
106121
DoAudit(txc, ctx);
107122

108123
db.Table<Schema::YamlConfig>().Key(Version + 1)
@@ -118,25 +133,34 @@ class TConfigsManager::TTxReplaceYamlConfig : public TTransactionBase<TConfigsMa
118133
}
119134
}
120135

121-
auto fillResponse = [&](auto& ev){
122-
if (UnknownFieldsCollector) {
123-
for (auto& [path, info] : UnknownFieldsCollector->GetUnknownKeys()) {
124-
auto *issue = ev->Record.AddIssues();
125-
issue->set_severity(NYql::TSeverityIds::S_WARNING);
126-
issue->set_message(TStringBuilder{} << "Unknown key# " << info.first << " in proto# " << info.second << " found in path# " << path);
127-
}
136+
auto fillResponse = [&](auto& ev, auto errorLevel){
137+
for (auto& [path, info] : unknownFields) {
138+
auto *issue = ev->Record.AddIssues();
139+
issue->set_severity(errorLevel);
140+
issue->set_message(TStringBuilder{} << "Unknown key# " << info.first << " in proto# " << info.second << " found in path# " << path);
141+
}
142+
143+
for (auto& [path, info] : deprecatedFields) {
144+
auto *issue = ev->Record.AddIssues();
145+
issue->set_severity(NYql::TSeverityIds::S_WARNING);
146+
issue->set_message(TStringBuilder{} << "Deprecated key# " << info.first << " in proto# " << info.second << " found in path# " << path);
128147
}
129148

130149
Response = MakeHolder<NActors::IEventHandle>(Sender, ctx.SelfID, ev.Release());
131150
};
132151

133152

134-
if (!Force) {
153+
if (hasForbiddenUnknown) {
154+
Error = true;
155+
auto ev = MakeHolder<TEvConsole::TEvGenericError>();
156+
ev->Record.SetYdbStatus(Ydb::StatusIds::BAD_REQUEST);
157+
fillResponse(ev, NYql::TSeverityIds::S_ERROR);
158+
} else if (!Force) {
135159
auto ev = MakeHolder<TEvConsole::TEvReplaceYamlConfigResponse>();
136-
fillResponse(ev);
160+
fillResponse(ev, NYql::TSeverityIds::S_WARNING);
137161
} else {
138162
auto ev = MakeHolder<TEvConsole::TEvSetYamlConfigResponse>();
139-
fillResponse(ev);
163+
fillResponse(ev, NYql::TSeverityIds::S_WARNING);
140164
}
141165
} catch (const yexception& ex) {
142166
Error = true;

ydb/core/config/tools/protobuf_plugin/main.cpp

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
#include <map>
2+
#include <unordered_set>
23

3-
#include <util/system/compiler.h>
4+
#include <util/generic/deque.h>
45
#include <util/generic/map.h>
5-
#include <util/generic/set.h>
66
#include <util/generic/maybe.h>
77
#include <util/generic/ptr.h>
8+
#include <util/generic/set.h>
89
#include <util/generic/vector.h>
910
#include <util/string/builder.h>
1011
#include <util/string/cast.h>
1112
#include <util/string/printf.h>
1213
#include <util/string/subst.h>
14+
#include <util/string/join.h>
15+
#include <util/system/compiler.h>
16+
17+
#include <library/cpp/protobuf/json/util.h>
1318

1419
#include <google/protobuf/compiler/code_generator.h>
1520
#include <google/protobuf/compiler/plugin.h>
1621
#include <google/protobuf/io/printer.h>
1722
#include <google/protobuf/io/zero_copy_stream.h>
23+
1824
#include <ydb/core/config/protos/marker.pb.h>
25+
#include <ydb/core/config/utils/config_traverse.h>
1926

2027
#include <ydb/public/lib/protobuf/base_message_generator.h>
2128
#include <ydb/public/lib/protobuf/helpers.h>
@@ -31,8 +38,63 @@ class TMessageGenerator
3138
: public TBaseMessageGenerator
3239
{
3340
private:
41+
TString FieldName(const FieldDescriptor* field) const {
42+
TString name = field->name();
43+
NProtobufJson::ToSnakeCaseDense(&name);
44+
return name;
45+
}
46+
47+
TString ConstructFullFieldPath(const TDeque<const FieldDescriptor*>& fieldPath, const FieldDescriptor* field) const {
48+
49+
TVector<TString> path;
50+
path.push_back("");
51+
for (size_t i = 1; i < fieldPath.size(); ++i) {
52+
TString fieldName = FieldName(fieldPath[i]);
53+
path.push_back(fieldName);
54+
}
55+
56+
return JoinSeq("/", path);
57+
}
3458

3559
void GenerateConfigRoot(TVars vars) {
60+
std::unordered_set<TString> reservedPaths;
61+
NKikimr::NConfig::Traverse([&](const Descriptor* d, const TDeque<const Descriptor*>& typePath, const TDeque<const FieldDescriptor*>& fieldPath, const FieldDescriptor* field, ssize_t loop) {
62+
Y_UNUSED(fieldPath, typePath, fieldPath, field, loop);
63+
if (field && d) {
64+
for (int i = 0; i < d->reserved_name_count(); ++i) {
65+
TString name = d->reserved_name(i);
66+
NProtobufJson::ToSnakeCaseDense(&name);
67+
reservedPaths.insert(ConstructFullFieldPath(fieldPath, field) + "/" + name);
68+
}
69+
}
70+
}, Message);
71+
72+
for (int i = 0; i < Message->reserved_name_count(); ++i) {
73+
TString name = Message->reserved_name(i);
74+
NProtobufJson::ToSnakeCaseDense(&name);
75+
reservedPaths.insert(TString("/") + name);
76+
}
77+
78+
WITH_PLUGIN_MARKUP(HeaderIncludes, PLUGIN_NAME) {
79+
HeaderIncludes->Print(Vars, "#include <unordered_set>\n");
80+
}
81+
82+
WITH_PLUGIN_MARKUP(Header, PLUGIN_NAME) {
83+
Header->Print(vars, "inline static const std::unordered_set<TString>& GetReservedChildrenPaths() {\n");
84+
WITH_INDENT(Header) {
85+
Header->Print(vars, "static const std::unordered_set<TString> reserved = {\n");
86+
WITH_INDENT(Header) {
87+
for (const auto& path : reservedPaths) {
88+
vars["reservedPath"] = path;
89+
Header->Print(vars, "\"$reservedPath$\",\n");
90+
}
91+
}
92+
Header->Print(vars, "};\n");
93+
Header->Print(vars, "return reserved;\n");
94+
}
95+
Header->Print(vars, "}\n");
96+
}
97+
3698
for (auto i = 0; i < Message->field_count(); ++i) {
3799
const FieldDescriptor* field = Message->field(i);
38100
if (field->is_repeated()) {

ydb/core/config/tools/protobuf_plugin/ut.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,16 @@ Y_UNIT_TEST_SUITE(ValidationTests) {
322322
UNIT_ASSERT_VALUES_EQUAL(thirdSink.GetRenamedComplexField1().GetStringField(), source.GetComplexMessage2().GetStringField());
323323
UNIT_ASSERT(!thirdSink.GetRenamedComplexField1().HasIntField());
324324
}
325+
326+
Y_UNIT_TEST(HasReservedPaths) {
327+
NKikimrConfig::ActualConfigMessage msg;
328+
329+
const auto& reserved = msg.GetReservedChildrenPaths();
330+
331+
UNIT_ASSERT(reserved.contains("/field1/another_reserved_field"));
332+
UNIT_ASSERT(reserved.contains("/field21/another_reserved_field"));
333+
UNIT_ASSERT(reserved.contains("/root_reserved_field"));
334+
}
325335
}
326336

327337
template <>

ydb/core/config/tools/protobuf_plugin/ut/protos/config_root_test.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@ package NKikimrConfig;
44
option java_package = "ru.yandex.kikimr.proto";
55

66
message AdditionalMessage {
7+
reserved "AnotherReservedField";
78
}
89

910
message AnotherMessage {
1011
optional string Content = 1;
1112
optional AdditionalMessage Field1 = 2;
13+
reserved "IncludedReservedField";
1214
}
1315

1416
message ActualConfigMessage {
1517
option (NMarkers.Root) = true;
1618
optional AdditionalMessage Field1 = 1;
1719
optional AdditionalMessage Field21 = 21;
1820
optional string Field201 = 201;
21+
reserved "RootReservedField";
1922
}

ydb/core/config/tools/protobuf_plugin/ya.make

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ PROGRAM(config_proto_plugin)
22

33
PEERDIR(
44
contrib/libs/protoc
5+
library/cpp/protobuf/json
56
ydb/public/lib/protobuf
67
ydb/core/config/protos
8+
ydb/core/config/utils
79
)
810

911
SRCS(

ydb/core/config/ut/main.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <ydb/core/config/utils/config_traverse.h>
2+
#include <ydb/core/protos/config.pb.h>
23

34
#include <library/cpp/colorizer/colors.h>
45
#include <library/cpp/protobuf/json/util.h>
@@ -115,7 +116,8 @@ class TConfigDumper {
115116
<< " " << (field ? FieldName(field) : RootName())
116117
<< " = " << (field ? field->number() : 0) << ";"
117118
<< (loop != -1 ? Loop() : "") << std::endl;
118-
});
119+
},
120+
NKikimrConfig::TAppConfig::default_instance().GetDescriptor());
119121
}
120122

121123
void PrintLoops() const {
@@ -130,7 +132,8 @@ class TConfigDumper {
130132
path.push_back(DescriptorName(d));
131133
std::cout << JoinSeq(" -> ", path) << std::endl;
132134
}
133-
});
135+
},
136+
NKikimrConfig::TAppConfig::default_instance().GetDescriptor());
134137

135138
}
136139

@@ -141,7 +144,8 @@ class TConfigDumper {
141144
if (field && field->is_required()) {
142145
fields[typePath.back()->file()][typePath.back()][field].insert(ConstructFullFieldPath(fieldPath, field));
143146
}
144-
});
147+
},
148+
NKikimrConfig::TAppConfig::default_instance().GetDescriptor());
145149
return fields;
146150
}
147151

ydb/core/config/ut/ya.make

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ SRCS(
66

77
PEERDIR(
88
ydb/core/config/utils
9+
ydb/core/protos
910
library/cpp/colorizer
1011
library/cpp/testing/unittest
1112
)

ydb/core/config/utils/config_traverse.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#include "config_traverse.h"
22

3-
#include <ydb/core/protos/config.pb.h>
4-
53
#include <contrib/libs/protobuf/src/google/protobuf/descriptor.h>
64

75
#include <util/generic/deque.h>
@@ -45,10 +43,7 @@ void Traverse(const Descriptor* d, TDeque<const Descriptor*>& typePath, TDeque<c
4543
typePath.pop_back();
4644
}
4745

48-
void Traverse(TOnEntryFn onEntry) {
49-
auto& inst = NKikimrConfig::TAppConfig::default_instance();
50-
const Descriptor* descriptor = inst.GetDescriptor();
51-
46+
void Traverse(TOnEntryFn onEntry, const Descriptor* descriptor) {
5247
TDeque<const Descriptor*> typePath;
5348
TDeque<const FieldDescriptor*> fieldPath;
5449
fieldPath.push_back(nullptr);

ydb/core/config/utils/config_traverse.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ using namespace google::protobuf;
1515

1616
using TOnEntryFn = std::function<void(const Descriptor*, const TDeque<const Descriptor*>&, const TDeque<const FieldDescriptor*>&, const FieldDescriptor*, ssize_t)>;
1717

18-
void Traverse(TOnEntryFn onEntry);
18+
void Traverse(TOnEntryFn onEntry, const Descriptor* descriptor);
1919

2020
} // namespace NKikimr::NConfig

ydb/core/config/utils/ya.make

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ SRCS(
55
)
66

77
PEERDIR(
8-
ydb/core/protos
98
library/cpp/protobuf/json
109
)
1110

0 commit comments

Comments
 (0)