Skip to content

Commit 2b430cc

Browse files
authored
Merge 29b71be into d14cebe
2 parents d14cebe + 29b71be commit 2b430cc

File tree

9 files changed

+448
-11
lines changed

9 files changed

+448
-11
lines changed

ydb/core/cms/console/configs_dispatcher.cpp

Lines changed: 155 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,44 @@ class TConfigsDispatcher : public TActorBootstrapped<TConfigsDispatcher> {
186186
void Handle(TEvConsole::TEvGetNodeLabelsRequest::TPtr &ev);
187187
void Handle(TEvConsole::TEvFetchStartupConfigRequest::TPtr &ev);
188188
void Handle(TEvConsole::TEvGetNodeConfigurationVersionRequest::TPtr &ev);
189+
void Handle(TEvConfigsDispatcher::TEvGetStateRequest::TPtr &ev);
190+
void Handle(TEvConfigsDispatcher::TEvGetStorageYamlRequest::TPtr &ev);
189191

190192
void ReplyMonJson(TActorId mailbox);
193+
194+
EConfigSource DetermineConfigSource() const {
195+
if (auto it = Labels.find("config_source"); it != Labels.end()) {
196+
if (it->second == "seed_nodes") {
197+
return EConfigSource::SeedNodes;
198+
}
199+
}
200+
return EConfigSource::DynamicConfig;
201+
}
202+
203+
TConfigsDispatcherState GetState() const {
204+
TConfigsDispatcherState state;
205+
206+
auto configSource = DetermineConfigSource();
207+
state.ConfigSource = configSource;
208+
209+
if (auto it = Labels.find("config_source"); it != Labels.end()) {
210+
state.ConfigSourceLabel = it->second;
211+
}
212+
213+
if (auto it = Labels.find("configuration_version"); it != Labels.end()) {
214+
state.ConfigurationVersion = it->second;
215+
}
216+
217+
state.HasStorageYaml = !StartupStorageYaml.empty();
218+
state.StorageYamlSize = StartupStorageYaml.size();
219+
state.YamlConfigEnabled = YamlConfigEnabled;
220+
state.SubscriptionsCount = SubscriptionsByKinds.size();
221+
state.LastReplayUsedSeedNodesPath = LastReplayUsedSeedNodesPath;
222+
state.LastReplayUsedDynamicConfigPath = LastReplayUsedDynamicConfigPath;
223+
state.Labels = Labels;
224+
225+
return state;
226+
}
191227

192228
STATEFN(StateInit)
193229
{
@@ -203,6 +239,8 @@ class TConfigsDispatcher : public TActorBootstrapped<TConfigsDispatcher> {
203239
hFuncTraced(TEvConfigsDispatcher::TEvGetConfigRequest, Handle);
204240
hFuncTraced(TEvConfigsDispatcher::TEvSetConfigSubscriptionRequest, Handle);
205241
hFuncTraced(TEvConfigsDispatcher::TEvRemoveConfigSubscriptionRequest, Handle);
242+
hFuncTraced(TEvConfigsDispatcher::TEvGetStateRequest, Handle);
243+
hFuncTraced(TEvConfigsDispatcher::TEvGetStorageYamlRequest, Handle);
206244
// Resolve
207245
hFunc(TEvConsole::TEvGetNodeLabelsRequest, Handle);
208246
hFunc(TEvConsole::TEvFetchStartupConfigRequest, Handle);
@@ -228,6 +266,8 @@ class TConfigsDispatcher : public TActorBootstrapped<TConfigsDispatcher> {
228266
hFuncTraced(TEvConfigsDispatcher::TEvRemoveConfigSubscriptionRequest, Handle);
229267
hFuncTraced(TEvConsole::TEvConfigNotificationResponse, Handle);
230268
IgnoreFunc(TEvConfigsDispatcher::TEvSetConfigSubscriptionResponse);
269+
hFuncTraced(TEvConfigsDispatcher::TEvGetStateRequest, Handle);
270+
hFuncTraced(TEvConfigsDispatcher::TEvGetStorageYamlRequest, Handle);
231271
// Resolve
232272
hFunc(TEvConsole::TEvGetNodeLabelsRequest, Handle);
233273
hFunc(TEvConsole::TEvFetchStartupConfigRequest, Handle);
@@ -249,6 +289,7 @@ class TConfigsDispatcher : public TActorBootstrapped<TConfigsDispatcher> {
249289
const NKikimrConfig::TAppConfig BaseConfig;
250290
NKikimrConfig::TAppConfig CurrentConfig;
251291
const TString StartupConfigYaml;
292+
const TString StartupStorageYaml;
252293
NKikimrConfig::TAppConfig CandidateStartupConfig;
253294
bool StartupConfigProcessError = false;
254295
bool StartupConfigProcessDiff = false;
@@ -263,6 +304,10 @@ class TConfigsDispatcher : public TActorBootstrapped<TConfigsDispatcher> {
263304
TVector<TActorId> HttpRequests;
264305
TActorId CommonSubscriptionClient;
265306
TDeque<TAutoPtr<IEventHandle>> EventsQueue;
307+
308+
// Observability: Track which replay path was used
309+
bool LastReplayUsedSeedNodesPath = false;
310+
bool LastReplayUsedDynamicConfigPath = false;
266311

267312
THashMap<TActorId, TSubscription::TPtr> SubscriptionsBySubscriber;
268313
THashMap<TDynBitMap, TSubscription::TPtr> SubscriptionsByKinds;
@@ -285,6 +330,7 @@ TConfigsDispatcher::TConfigsDispatcher(const TConfigsDispatcherInitInfo& initInf
285330
, BaseConfig(initInfo.InitialConfig)
286331
, CurrentConfig(initInfo.InitialConfig)
287332
, StartupConfigYaml(initInfo.StartupConfigYaml)
333+
, StartupStorageYaml(initInfo.StartupStorageYaml)
288334
, CandidateStartupConfig(initInfo.InitialConfig)
289335
, DebugInfo(initInfo.DebugInfo)
290336
, RecordedInitialConfiguratorDeps(std::move(initInfo.RecordedInitialConfiguratorDeps))
@@ -442,6 +488,20 @@ void TConfigsDispatcher::ReplyMonJson(TActorId mailbox) {
442488
response.InsertValue("yaml_config", MainYamlConfig);
443489
response.InsertValue("resolved_json_config", NJson::ReadJsonFastTree(ResolvedJsonConfig, true));
444490
response.InsertValue("current_json_config", NJson::ReadJsonFastTree(NProtobufJson::Proto2Json(CurrentConfig, NYamlConfig::GetProto2JsonConfig()), true));
491+
492+
auto state = GetState();
493+
if (auto it = Labels.find("config_source"); it != Labels.end()) {
494+
response.InsertValue("config_source", it->second);
495+
}
496+
if (auto it = Labels.find("configuration_version"); it != Labels.end()) {
497+
response.InsertValue("configuration_version", it->second);
498+
}
499+
response.InsertValue("has_storage_yaml", state.HasStorageYaml);
500+
if (state.HasStorageYaml) {
501+
response.InsertValue("storage_yaml_size", static_cast<i64>(state.StorageYamlSize));
502+
}
503+
response.InsertValue("last_replay_seed_nodes", state.LastReplayUsedSeedNodesPath);
504+
response.InsertValue("last_replay_dynamic_config", state.LastReplayUsedDynamicConfigPath);
445505

446506
if (DebugInfo) {
447507
// TODO: write custom json serializer for security fields
@@ -652,6 +712,19 @@ void TConfigsDispatcher::Handle(TEvInterconnect::TEvNodesInfo::TPtr &ev)
652712
: s == &TThis::StateInit ? "StateInit"
653713
: "Unknown" ) << Endl;
654714
str << "YamlConfigEnabled: " << YamlConfigEnabled << Endl;
715+
716+
str << Endl << "=== Configuration Source ===" << Endl;
717+
auto state = GetState();
718+
str << state.ToDebugString() << Endl;
719+
if (LastReplayUsedSeedNodesPath) {
720+
str << "Last Replay Path: Seed Nodes (ConfigClient)" << Endl;
721+
} else if (LastReplayUsedDynamicConfigPath) {
722+
str << "Last Replay Path: Dynamic Config (DynConfigClient)" << Endl;
723+
} else {
724+
str << "Last Replay Path: Not yet executed" << Endl;
725+
}
726+
str << Endl;
727+
655728
str << "Subscriptions: " << Endl;
656729
for (auto &[kinds, subscription] : SubscriptionsByKinds) {
657730
str << "- Kinds: " << KindsToString(kinds) << Endl
@@ -759,6 +832,34 @@ void TConfigsDispatcher::Handle(TEvInterconnect::TEvNodesInfo::TPtr &ev)
759832
}
760833
}
761834
str << "<br />" << Endl;
835+
COLLAPSED_REF_CONTENT("storage-yaml-config", "Storage YAML Config (Seed Nodes)") {
836+
if (!StartupStorageYaml.empty()) {
837+
DIV() {
838+
TAG(TH5) {
839+
str << "Startup Storage Config (from seed nodes)" << Endl;
840+
}
841+
TAG_CLASS_STYLE(TDiv, "configs-dispatcher", "padding: 0 12px;") {
842+
TAG_ATTRS(TDiv, {{"class", "yaml-sticky-btn-wrap fold-yaml-config yaml-btn-3"}, {"title", "fold"}}) {
843+
DIV_CLASS("yaml-sticky-btn") { }
844+
}
845+
TAG_ATTRS(TDiv, {{"class", "yaml-sticky-btn-wrap unfold-yaml-config yaml-btn-2"}, {"title", "unfold"}}) {
846+
DIV_CLASS("yaml-sticky-btn") { }
847+
}
848+
TAG_ATTRS(TDiv, {{"class", "yaml-sticky-btn-wrap copy-yaml-config yaml-btn-1"}, {"title", "copy"}}) {
849+
DIV_CLASS("yaml-sticky-btn") { }
850+
}
851+
DIV_CLASS("yaml-config-item") {
852+
str << StartupStorageYaml;
853+
}
854+
}
855+
}
856+
} else {
857+
str << "<div class=\"alert alert-info\" role=\"alert\">" << Endl;
858+
str << "No storage config available. This is normal for non-seed-nodes initialization." << Endl;
859+
str << "</div>" << Endl;
860+
}
861+
}
862+
str << "<br />" << Endl;
762863
COLLAPSED_REF_CONTENT("resolved-yaml-config", "Resolved YAML config") {
763864
TAG_CLASS_STYLE(TDiv, "configs-dispatcher", "padding: 0 12px;") {
764865
TAG_ATTRS(TDiv, {{"class", "yaml-sticky-btn-wrap fold-yaml-config yaml-btn-3"}, {"id", "fold-resolved-yaml-config"}, {"title", "fold"}}) {
@@ -818,9 +919,9 @@ void TConfigsDispatcher::Handle(TEvInterconnect::TEvNodesInfo::TPtr &ev)
818919

819920
class TConfigurationResult
820921
: public IConfigurationResult
922+
, public IStorageConfigResult
821923
{
822924
public:
823-
// TODO make ref
824925
const NKikimrConfig::TAppConfig& GetConfig() const override {
825926
return Config;
826927
}
@@ -829,10 +930,6 @@ class TConfigurationResult
829930
return !MainYamlConfig.empty();
830931
}
831932

832-
const TString& GetMainYamlConfig() const override {
833-
return MainYamlConfig;
834-
}
835-
836933
TMap<ui64, TString> GetVolatileYamlConfigs() const override {
837934
return VolatileYamlConfigs;
838935
}
@@ -845,10 +942,24 @@ class TConfigurationResult
845942
return DatabaseYamlConfig;
846943
}
847944

945+
const TString& GetStorageYamlConfig() const override {
946+
return StorageYamlConfig;
947+
}
948+
949+
const TString& GetSourceAddress() const override {
950+
return SourceAddress;
951+
}
952+
953+
const TString& GetMainYamlConfig() const override {
954+
return MainYamlConfig;
955+
}
956+
848957
NKikimrConfig::TAppConfig Config;
849958
TString MainYamlConfig;
850959
TMap<ui64, TString> VolatileYamlConfigs;
851960
TString DatabaseYamlConfig;
961+
TString StorageYamlConfig;
962+
TString SourceAddress;
852963
};
853964

854965
void TConfigsDispatcher::UpdateCandidateStartupConfig(TEvConsole::TEvConfigSubscriptionNotification::TPtr &ev)
@@ -864,16 +975,41 @@ try {
864975

865976
auto &rec = ev->Get()->Record;
866977

867-
auto dcClient = std::make_unique<TDynConfigClientMock>();
868978
auto configs = std::make_shared<TConfigurationResult>();
869-
dcClient->SavedResult = configs;
870979
configs->Config = rec.GetRawConsoleConfig();
871980
configs->MainYamlConfig = rec.GetMainYamlConfig();
872981
if (rec.HasDatabaseYamlConfig()) {
873982
configs->DatabaseYamlConfig = rec.GetDatabaseYamlConfig();
874983
}
875984
// TODO volatile
876-
RecordedInitialConfiguratorDeps->DynConfigClient = std::move(dcClient);
985+
986+
auto configSource = DetermineConfigSource();
987+
988+
LastReplayUsedSeedNodesPath = false;
989+
LastReplayUsedDynamicConfigPath = false;
990+
991+
switch (configSource) {
992+
case EConfigSource::SeedNodes:
993+
configs->StorageYamlConfig = StartupStorageYaml;
994+
{
995+
auto configClient = std::make_unique<TConfigClientMock>();
996+
configClient->SavedResult = configs;
997+
RecordedInitialConfiguratorDeps->ConfigClient = std::move(configClient);
998+
}
999+
LastReplayUsedSeedNodesPath = true;
1000+
break;
1001+
1002+
case EConfigSource::DynamicConfig:
1003+
case EConfigSource::Unknown:
1004+
{
1005+
auto dcClient = std::make_unique<TDynConfigClientMock>();
1006+
dcClient->SavedResult = configs;
1007+
RecordedInitialConfiguratorDeps->DynConfigClient = std::move(dcClient);
1008+
}
1009+
LastReplayUsedDynamicConfigPath = true;
1010+
break;
1011+
}
1012+
8771013
auto deps = RecordedInitialConfiguratorDeps->GetDeps();
8781014
NConfig::TInitialConfigurator initCfg(deps);
8791015

@@ -1051,9 +1187,11 @@ void TConfigsDispatcher::Handle(TEvConsole::TEvConfigSubscriptionNotification::T
10511187
}
10521188

10531189
if (CurrentStateFunc() == &TThis::StateInit) {
1190+
BLOG_D("Handle TEvConfigSubscriptionNotification: transitioning to StateWork");
10541191
Become(&TThis::StateWork);
10551192
ProcessEnqueuedEvents();
10561193
}
1194+
BLOG_D("Handle TEvConfigSubscriptionNotification: exit");
10571195
}
10581196

10591197
void TConfigsDispatcher::UpdateYamlVersion(const TSubscription::TPtr &subscription) const
@@ -1295,6 +1433,15 @@ void TConfigsDispatcher::Handle(TEvConsole::TEvGetNodeConfigurationVersionReques
12951433
Send(ev->Sender, response.release());
12961434
}
12971435

1436+
void TConfigsDispatcher::Handle(TEvConfigsDispatcher::TEvGetStateRequest::TPtr &ev) {
1437+
auto state = GetState();
1438+
Send(ev->Sender, new TEvConfigsDispatcher::TEvGetStateResponse(std::move(state)));
1439+
}
1440+
1441+
void TConfigsDispatcher::Handle(TEvConfigsDispatcher::TEvGetStorageYamlRequest::TPtr &ev) {
1442+
Send(ev->Sender, new TEvConfigsDispatcher::TEvGetStorageYamlResponse(StartupStorageYaml));
1443+
}
1444+
12981445
IActor *CreateConfigsDispatcher(const TConfigsDispatcherInitInfo& initInfo) {
12991446
return new TConfigsDispatcher(initInfo);
13001447
}

ydb/core/cms/console/configs_dispatcher.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22
#include "defs.h"
3+
#include "configs_dispatcher_observer.h"
34

45
#include <ydb/core/protos/config.pb.h>
56
#include <ydb/core/config/init/init.h>
@@ -36,6 +37,12 @@ namespace TEvConfigsDispatcher {
3637
EvGetConfigResponse,
3738
EvRemoveConfigSubscriptionRequest,
3839
EvRemoveConfigSubscriptionResponse,
40+
41+
// Observability events
42+
EvGetStateRequest,
43+
EvGetStateResponse,
44+
EvGetStorageYamlRequest,
45+
EvGetStorageYamlResponse,
3946

4047
EvEnd
4148
};
@@ -106,6 +113,46 @@ namespace TEvConfigsDispatcher {
106113
struct TEvGetConfigResponse : public TEventLocal<TEvGetConfigResponse, EvGetConfigResponse> {
107114
std::shared_ptr<const NKikimrConfig::TAppConfig> Config;
108115
};
116+
117+
/**
118+
* Request current state of ConfigsDispatcher.
119+
* Response: TEvGetStateResponse
120+
*/
121+
struct TEvGetStateRequest : public TEventLocal<TEvGetStateRequest, EvGetStateRequest> {
122+
TEvGetStateRequest() = default;
123+
};
124+
125+
/**
126+
* Response containing current state snapshot.
127+
*/
128+
struct TEvGetStateResponse : public TEventLocal<TEvGetStateResponse, EvGetStateResponse> {
129+
TConfigsDispatcherState State;
130+
131+
TEvGetStateResponse(TConfigsDispatcherState state)
132+
: State(std::move(state))
133+
{}
134+
};
135+
136+
/**
137+
* Request storage YAML config (if available).
138+
* Only available if initialized from seed nodes.
139+
* Response: TEvGetStorageYamlResponse
140+
*/
141+
struct TEvGetStorageYamlRequest : public TEventLocal<TEvGetStorageYamlRequest, EvGetStorageYamlRequest> {
142+
TEvGetStorageYamlRequest() = default;
143+
};
144+
145+
/**
146+
* Response containing storage YAML config.
147+
* StorageYaml will be empty if not initialized from seed nodes.
148+
*/
149+
struct TEvGetStorageYamlResponse : public TEventLocal<TEvGetStorageYamlResponse, EvGetStorageYamlResponse> {
150+
TString StorageYaml;
151+
152+
TEvGetStorageYamlResponse(TString storageYaml)
153+
: StorageYaml(std::move(storageYaml))
154+
{}
155+
};
109156
};
110157

111158
/**

0 commit comments

Comments
 (0)